From 69a6be0305772fbcba9bf0798e0f61445bf42083 Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Fri, 12 Oct 2012 15:51:44 +0400 Subject: [PATCH 001/180] 7173145: Improve in-memory representation of splashscreens Reviewed-by: bae, mschoene --- jdk/src/share/native/sun/awt/splashscreen/splashscreen_jpeg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jdk/src/share/native/sun/awt/splashscreen/splashscreen_jpeg.c b/jdk/src/share/native/sun/awt/splashscreen/splashscreen_jpeg.c index fcd7de01639..b1a59098955 100644 --- a/jdk/src/share/native/sun/awt/splashscreen/splashscreen_jpeg.c +++ b/jdk/src/share/native/sun/awt/splashscreen/splashscreen_jpeg.c @@ -133,6 +133,10 @@ SplashDecodeJpeg(Splash * splash, struct jpeg_decompress_struct *cinfo) ImageFormat srcFormat; jpeg_read_header(cinfo, TRUE); + + // SplashScreen jpeg converter expects data in RGB format only + cinfo->out_color_space = JCS_RGB; + jpeg_start_decompress(cinfo); SplashCleanup(splash); From f36ef09388cc33f69d56573d6a51ccea6333b632 Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Mon, 15 Oct 2012 07:42:18 -0700 Subject: [PATCH 002/180] 7192393: Better Checking of order of TLS Messages Also reviewed by Andrew Gross Reviewed-by: weijun --- .../sun/security/ssl/ClientHandshaker.java | 5 ++--- .../sun/security/ssl/ServerHandshaker.java | 16 +++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java b/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java index 9ebeb75c5aa..63d48ad376d 100644 --- a/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java +++ b/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java @@ -128,9 +128,8 @@ final class ClientHandshaker extends Handshaker { * in the constructor. */ void processMessage(byte type, int messageLen) throws IOException { - if (state > type - && (type != HandshakeMessage.ht_hello_request - && state != HandshakeMessage.ht_client_hello)) { + if (state >= type + && (type != HandshakeMessage.ht_hello_request)) { throw new SSLProtocolException( "Handshake message sequence violation, " + type); } diff --git a/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java b/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java index 8b10f8a9499..a8d256f76d6 100644 --- a/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java +++ b/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java @@ -150,7 +150,7 @@ final class ServerHandshaker extends Handshaker { // In SSLv3 and TLS, messages follow strictly increasing // numerical order _except_ for one annoying special case. // - if ((state > type) + if ((state >= type) && (state != HandshakeMessage.ht_client_key_exchange && type != HandshakeMessage.ht_certificate_verify)) { throw new SSLProtocolException( @@ -250,13 +250,15 @@ final class ServerHandshaker extends Handshaker { } // - // Move the state machine forward except for that annoying - // special case. This means that clients could send extra - // cert verify messages; not a problem so long as all of - // them actually check out. + // Move state machine forward if the message handling + // code didn't already do so // - if (state < type && type != HandshakeMessage.ht_certificate_verify) { - state = type; + if (state < type) { + if(type == HandshakeMessage.ht_certificate_verify) { + state = type + 2; // an annoying special case + } else { + state = type; + } } } From c4f31fd22e9905fb38ad0919154d9fcd6c7c3183 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 15 Oct 2012 19:00:13 +0400 Subject: [PATCH 003/180] 7200493: Improve cache handling Reviewed-by: art, ahgross --- .../share/classes/com/sun/beans/finder/MethodFinder.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java b/jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java index fa7cc5612ab..98c52bc929a 100644 --- a/jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java +++ b/jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java @@ -66,11 +66,14 @@ public final class MethodFinder extends AbstractFinder { Signature signature = new Signature(type, name, args); Method method = CACHE.get(signature); - if (method != null) { + boolean cached = method != null; + if (cached && isPackageAccessible(method.getDeclaringClass())) { return method; } method = findAccessibleMethod(new MethodFinder(name, args).find(type.getMethods())); - CACHE.put(signature, method); + if (!cached) { + CACHE.put(signature, method); + } return method; } From e2a34e4d9e5975da831124dd4d49e389fabcfcf5 Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Tue, 16 Oct 2012 14:13:39 +0400 Subject: [PATCH 004/180] 7186948: Improve Swing data validation Reviewed-by: art, ahgross --- jdk/src/share/classes/javax/swing/UIDefaults.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jdk/src/share/classes/javax/swing/UIDefaults.java b/jdk/src/share/classes/javax/swing/UIDefaults.java index 9f22122d7b2..9f304e742c7 100644 --- a/jdk/src/share/classes/javax/swing/UIDefaults.java +++ b/jdk/src/share/classes/javax/swing/UIDefaults.java @@ -677,6 +677,8 @@ public class UIDefaults extends Hashtable try { String className = (String)get(uiClassID); if (className != null) { + ReflectUtil.checkPackageAccess(className); + Class cls = (Class)get(className); if (cls == null) { if (uiClassLoader == null) { From 1ee5b4509e4ee5008bdcf19b54b14de7f6e1b443 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Tue, 16 Oct 2012 12:29:10 -0700 Subject: [PATCH 005/180] 7186945: Unpack200 improvement Reviewed-by: jrose, jjh, mschoene --- .../share/native/com/sun/java/util/jar/pack/jni.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/jni.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/jni.cpp index bedecda5391..50b5d114b39 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/jni.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/jni.cpp @@ -127,8 +127,10 @@ static jlong read_input_via_jni(unpacker* self, JNIEXPORT void JNICALL Java_com_sun_java_util_jar_pack_NativeUnpack_initIDs(JNIEnv *env, jclass clazz) { +#ifndef PRODUCT dbg = getenv("DEBUG_ATTACH"); while( dbg != null) { sleep(10); } +#endif NIclazz = (jclass) env->NewGlobalRef(clazz); unpackerPtrFID = env->GetFieldID(clazz, "unpackerPtr", "J"); currentInstMID = env->GetStaticMethodID(clazz, "currentInstance", @@ -230,11 +232,14 @@ Java_com_sun_java_util_jar_pack_NativeUnpack_getUnusedInput(JNIEnv *env, jobject // We have fetched all the files. // Now swallow up any remaining input. - if (uPtr->input_remaining() == 0) + if (uPtr->input_remaining() == 0) { return null; - else - return env->NewDirectByteBuffer(uPtr->input_scan(), - uPtr->input_remaining()); + } else { + bytes remaining_bytes; + remaining_bytes.malloc(uPtr->input_remaining()); + remaining_bytes.copyFrom(uPtr->input_scan(), uPtr->input_remaining()); + return env->NewDirectByteBuffer(remaining_bytes.ptr, remaining_bytes.len); + } } JNIEXPORT jlong JNICALL From 0c4da1ece18f318e7f8387f595dbfbc64c2573ef Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Tue, 16 Oct 2012 12:35:22 -0700 Subject: [PATCH 006/180] 7186957: Improve Pack200 data validation Reviewed-by: jrose, jjh, mschoene --- .../sun/java/util/jar/pack/BandStructure.java | 3 +- .../sun/java/util/jar/pack/ConstantPool.java | 2 ++ .../com/sun/java/util/jar/pack/bands.cpp | 4 +++ .../native/com/sun/java/util/jar/pack/bands.h | 4 +-- .../com/sun/java/util/jar/pack/unpack.cpp | 30 ++++++++++++++++--- 5 files changed, 36 insertions(+), 7 deletions(-) diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java index f3d5cec8e48..b53e082b802 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java @@ -1000,7 +1000,6 @@ class BandStructure { /** Write a constant pool reference. */ public void putRef(Entry e) { - assert(index != null); addValue(encodeRefOrNull(e, index)); } public void putRef(Entry e, Index index) { @@ -1052,6 +1051,8 @@ class BandStructure { int encodeRef(Entry e, Index ix) { + if (ix == null) + throw new RuntimeException("null index for " + e.stringValue()); int coding = ix.indexOf(e); if (verbose > 2) Utils.log.fine("putRef "+coding+" => "+e); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java index be4da54d247..4c5e5ba050d 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java @@ -1381,6 +1381,8 @@ class ConstantPool { /** Index of all CP entries of a given tag and class. */ public Index getMemberIndex(byte tag, ClassEntry classRef) { + if (classRef == null) + throw new RuntimeException("missing class reference for " + tagName(tag)); if (indexByTagAndClass == null) indexByTagAndClass = new Index[CONSTANT_Limit][]; Index allClasses = getIndexByTag(CONSTANT_Class); diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp index 08cdc8d3e76..6db0f31bc32 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp @@ -187,6 +187,10 @@ void band::setIndexByTag(byte tag) { entry* band::getRefCommon(cpindex* ix_, bool nullOKwithCaller) { CHECK_0; + if (ix_ == NULL) { + abort("no index"); + return NULL; + } assert(ix_->ixTag == ixTag || ((ixTag == CONSTANT_All || ixTag == CONSTANT_LoadableValue || diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h index b8e322aa1db..30ce8ed49a3 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h @@ -99,8 +99,8 @@ struct band { int getByte() { assert(ix == null); return vs[0].getByte(); } int getInt() { assert(ix == null); return vs[0].getInt(); } - entry* getRefN() { assert(ix != null); return getRefCommon(ix, true); } - entry* getRef() { assert(ix != null); return getRefCommon(ix, false); } + entry* getRefN() { return getRefCommon(ix, true); } + entry* getRef() { return getRefCommon(ix, false); } entry* getRefUsing(cpindex* ix2) { assert(ix == null); return getRefCommon(ix2, true); } entry* getRefCommon(cpindex* ix, bool nullOK); diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp index d7c51978ded..bb0e10bb32b 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp @@ -281,11 +281,13 @@ int entry::typeSize() { } inline cpindex* cpool::getFieldIndex(entry* classRef) { + if (classRef == NULL) { abort("missing class reference"); return NULL; } assert(classRef->tagMatches(CONSTANT_Class)); assert((uint)classRef->inord < (uint)tag_count[CONSTANT_Class]); return &member_indexes[classRef->inord*2+0]; } inline cpindex* cpool::getMethodIndex(entry* classRef) { + if (classRef == NULL) { abort("missing class reference"); return NULL; } assert(classRef->tagMatches(CONSTANT_Class)); assert((uint)classRef->inord < (uint)tag_count[CONSTANT_Class]); return &member_indexes[classRef->inord*2+1]; @@ -1289,6 +1291,7 @@ void unpacker::read_double_refs(band& cp_band, byte ref1Tag, byte ref2Tag, entry& e = cpMap[i]; e.refs = U_NEW(entry*, e.nrefs = 2); e.refs[0] = cp_band1.getRef(); + CHECK; e.refs[1] = cp_band2.getRef(); CHECK; } @@ -1369,6 +1372,7 @@ void unpacker::read_method_type(entry* cpMap, int len) { entry& e = cpMap[i]; e.refs = U_NEW(entry*, e.nrefs = 1); e.refs[0] = cp_MethodType.getRef(); + CHECK; } } @@ -2104,6 +2108,7 @@ void unpacker::read_attr_defs() { int attrc = ADH_BYTE_CONTEXT(header); int idx = ADH_BYTE_INDEX(header); entry* name = attr_definition_name.getRef(); + CHECK; entry* layout = attr_definition_layout.getRef(); CHECK; attr_defs[attrc].defineLayout(idx, name, layout->value.b.strval()); @@ -2208,7 +2213,9 @@ void unpacker::read_ics() { if (ics[i].name == NO_ENTRY_YET) { // Long form. ics[i].outer = ic_outer_class.getRefN(); + CHECK; ics[i].name = ic_name.getRefN(); + CHECK; } else { // Fill in outer and name based on inner. bytes& n = ics[i].inner->value.b; @@ -2724,6 +2731,7 @@ void unpacker::putlayout(band** body) { e = b.getRefUsing(cp.getKQIndex()); else e = b.getRefN(); + CHECK; switch (b.le_len) { case 0: break; case 1: putu1ref(e); break; @@ -4006,6 +4014,7 @@ void unpacker::write_bc_ops() { NOT_PRODUCT(bc_superfield.setIndex(null)); NOT_PRODUCT(bc_supermethod.setIndex(null)); } + CHECK; for (int curIP = 0; ; curIP++) { int curPC = (int)(wpoffset() - codeBase); @@ -4119,7 +4128,8 @@ void unpacker::write_bc_ops() { int coding = bc_initref.getInt(); // Find the nth overloading of in classRef. entry* ref = null; - cpindex* ix = (classRef == null)? null: cp.getMethodIndex(classRef); + cpindex* ix = cp.getMethodIndex(classRef); + CHECK; for (int j = 0, which_init = 0; ; j++) { ref = (ix == null)? null: ix->get(j); if (ref == null) break; // oops, bad input @@ -4396,6 +4406,7 @@ int unpacker::write_attrs(int attrc, julong indexBits) { case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_EnclosingMethod): aname = cp.sym[cpool::s_EnclosingMethod]; putref(class_EnclosingMethod_RC.getRefN()); + CHECK_0; putref(class_EnclosingMethod_RDN.getRefN()); break; @@ -4414,6 +4425,7 @@ int unpacker::write_attrs(int attrc, julong indexBits) { putu2(count = method_Exceptions_N.getInt()); for (j = 0; j < count; j++) { putref(method_Exceptions_RC.getRefN()); + CHECK_0; } break; @@ -4437,16 +4449,18 @@ int unpacker::write_attrs(int attrc, julong indexBits) { // (253) [(1)(2)(2)] // (254) [(1)(2)(2)(2)] putu2(code_StackMapTable_offset.getInt()); + CHECK_0; for (int k = (tag - 251); k > 0; k--) { put_stackmap_type(); + CHECK_0; } } else { // (255) [(1)NH[(2)]NH[(2)]] putu2(code_StackMapTable_offset.getInt()); putu2(j2 = code_StackMapTable_local_N.getInt()); - while (j2-- > 0) put_stackmap_type(); + while (j2-- > 0) {put_stackmap_type(); CHECK_0;} putu2(j2 = code_StackMapTable_stack_N.getInt()); - while (j2-- > 0) put_stackmap_type(); + while (j2-- > 0) {put_stackmap_type(); CHECK_0;} } } break; @@ -4470,7 +4484,9 @@ int unpacker::write_attrs(int attrc, julong indexBits) { bii += code_LocalVariableTable_span_O.getInt(); putu2(to_bci(bii) - bci); putref(code_LocalVariableTable_name_RU.getRefN()); + CHECK_0; putref(code_LocalVariableTable_type_RS.getRefN()); + CHECK_0; putu2(code_LocalVariableTable_slot.getInt()); } break; @@ -4485,7 +4501,9 @@ int unpacker::write_attrs(int attrc, julong indexBits) { bii += code_LocalVariableTypeTable_span_O.getInt(); putu2(to_bci(bii) - bci); putref(code_LocalVariableTypeTable_name_RU.getRefN()); + CHECK_0; putref(code_LocalVariableTypeTable_type_RS.getRefN()); + CHECK_0; putu2(code_LocalVariableTypeTable_slot.getInt()); } break; @@ -4513,7 +4531,7 @@ int unpacker::write_attrs(int attrc, julong indexBits) { break; } } - + CHECK_0; if (aname == null) { // Unparse a compressor-defined attribute. layout_definition* lo = ad.getLayout(idx); @@ -4669,7 +4687,9 @@ int unpacker::write_ics(int naOffset, int na) { flags &= ~ACC_IC_LONG_FORM; // clear high bit if set to get clean zero extra_ic.flags = flags; extra_ic.outer = class_InnerClasses_outer_RCN.getRefN(); + CHECK_0; extra_ic.name = class_InnerClasses_name_RUN.getRefN(); + CHECK_0; // Detect if this is an exact copy of the global tuple. if (global_ic != null) { if (global_ic->flags != extra_ic.flags || @@ -4778,6 +4798,7 @@ void unpacker::write_classfile_tail() { julong indexMask = ad.flagIndexMask(); cur_class = class_this.getRef(); + CHECK; cur_super = class_super.getRef(); CHECK; @@ -4791,6 +4812,7 @@ void unpacker::write_classfile_tail() { putu2(num = class_interface_count.getInt()); for (i = 0; i < num; i++) { putref(class_interface.getRef()); + CHECK; } write_members(class_field_count.getInt(), ATTR_CONTEXT_FIELD); From ef7ede903e93a14a736085aa6d23a5caa95ad886 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Tue, 16 Oct 2012 12:38:29 -0700 Subject: [PATCH 007/180] 7186946: Refine unpacker resource usage Reviewed-by: jrose, jjh, mschoene --- .../sun/java/util/jar/pack/NativeUnpack.java | 6 ++- .../sun/java/util/jar/pack/PackerImpl.java | 4 +- .../sun/java/util/jar/pack/UnpackerImpl.java | 6 +-- .../native/com/sun/java/util/jar/pack/jni.cpp | 40 ++++++++++++++----- .../com/sun/java/util/jar/pack/unpack.cpp | 4 +- 5 files changed, 42 insertions(+), 18 deletions(-) diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java index 7e525729034..3f2f430fb84 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -109,6 +109,10 @@ class NativeUnpack { return (p200 == null)? null: p200._nunp; } + private synchronized long getUnpackerPtr() { + return unpackerPtr; + } + // Callback from the unpacker engine to get more data. private long readInputFn(ByteBuffer pbuf, long minlen) throws IOException { if (in == null) return 0; // nothing is readable diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java index c7ef4ee2013..dce8811e377 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java @@ -83,7 +83,7 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer { * @param out an OutputStream * @exception IOException if an error is encountered. */ - public void pack(JarFile in, OutputStream out) throws IOException { + public synchronized void pack(JarFile in, OutputStream out) throws IOException { assert(Utils.currentInstance.get() == null); TimeZone tz = (props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null @@ -118,7 +118,7 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer { * @param out an OutputStream * @exception IOException if an error is encountered. */ - public void pack(JarInputStream in, OutputStream out) throws IOException { + public synchronized void pack(JarInputStream in, OutputStream out) throws IOException { assert(Utils.currentInstance.get() == null); TimeZone tz = (props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : TimeZone.getDefault(); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java index 5727d32986e..fd8ccfd3c71 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -106,7 +106,7 @@ public class UnpackerImpl extends TLGlobals implements Pack200.Unpacker { * @param out a JarOutputStream. * @exception IOException if an error is encountered. */ - public void unpack(InputStream in, JarOutputStream out) throws IOException { + public synchronized void unpack(InputStream in, JarOutputStream out) throws IOException { if (in == null) { throw new NullPointerException("null input"); } @@ -151,7 +151,7 @@ public class UnpackerImpl extends TLGlobals implements Pack200.Unpacker { * @param out a JarOutputStream. * @exception IOException if an error is encountered. */ - public void unpack(File in, JarOutputStream out) throws IOException { + public synchronized void unpack(File in, JarOutputStream out) throws IOException { if (in == null) { throw new NullPointerException("null input"); } diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/jni.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/jni.cpp index 50b5d114b39..26c683f0ae9 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/jni.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/jni.cpp @@ -50,6 +50,7 @@ static jfieldID unpackerPtrFID; static jmethodID currentInstMID; static jmethodID readInputMID; static jclass NIclazz; +static jmethodID getUnpackerPtrMID; static char* dbg = null; @@ -60,8 +61,8 @@ static jlong read_input_via_jni(unpacker* self, static unpacker* get_unpacker(JNIEnv *env, jobject pObj, bool noCreate=false) { unpacker* uPtr; - uPtr = (unpacker*)jlong2ptr(env->GetLongField(pObj, unpackerPtrFID)); - //fprintf(stderr, "get_unpacker(%p) uPtr=%p\n", pObj, uPtr); + jlong p = env->CallLongMethod(pObj, getUnpackerPtrMID); + uPtr = (unpacker*)jlong2ptr(p); if (uPtr == null) { if (noCreate) return null; uPtr = new unpacker(); @@ -94,11 +95,15 @@ static unpacker* get_unpacker() { if (env == null) return null; jobject pObj = env->CallStaticObjectMethod(NIclazz, currentInstMID); - //fprintf(stderr, "get_unpacker() pObj=%p\n", pObj); - if (pObj == null) - return null; - // Got pObj and env; now do it the easy way. - return get_unpacker(env, pObj); + //fprintf(stderr, "get_unpacker0() pObj=%p\n", pObj); + if (pObj != null) { + // Got pObj and env; now do it the easy way. + return get_unpacker(env, pObj); + } + // this should really not happen, if it does something is seriously + // wrong throw an exception + THROW_IOE(ERROR_INTERNAL); + return null; } static void free_unpacker(JNIEnv *env, jobject pObj, unpacker* uPtr) { @@ -137,10 +142,13 @@ Java_com_sun_java_util_jar_pack_NativeUnpack_initIDs(JNIEnv *env, jclass clazz) "()Ljava/lang/Object;"); readInputMID = env->GetMethodID(clazz, "readInputFn", "(Ljava/nio/ByteBuffer;J)J"); + getUnpackerPtrMID = env->GetMethodID(clazz, "getUnpackerPtr", "()J"); + if (unpackerPtrFID == null || currentInstMID == null || readInputMID == null || - NIclazz == null) { + NIclazz == null || + getUnpackerPtrMID == null) { THROW_IOE("cannot init class members"); } } @@ -148,8 +156,13 @@ Java_com_sun_java_util_jar_pack_NativeUnpack_initIDs(JNIEnv *env, jclass clazz) JNIEXPORT jlong JNICALL Java_com_sun_java_util_jar_pack_NativeUnpack_start(JNIEnv *env, jobject pObj, jobject pBuf, jlong offset) { - unpacker* uPtr = get_unpacker(env, pObj); - + // try to get the unpacker pointer the hard way first, we do this to ensure + // valid object pointers and env is intact, if not now is good time to bail. + unpacker* uPtr = get_unpacker(); + //fprintf(stderr, "start(%p) uPtr=%p initializing\n", pObj, uPtr); + if (uPtr == null) { + return -1; + } // redirect our io to the default log file or whatever. uPtr->redirect_stdio(); @@ -165,7 +178,12 @@ Java_com_sun_java_util_jar_pack_NativeUnpack_start(JNIEnv *env, jobject pObj, else { buf = (char*)buf + (size_t)offset; buflen -= (size_t)offset; } } - + // before we start off we make sure there is no other error by the time we + // get here + if (uPtr->aborting()) { + THROW_IOE(uPtr->get_abort_message()); + return 0; + } uPtr->start(buf, buflen); if (uPtr->aborting()) { THROW_IOE(uPtr->get_abort_message()); diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp index bb0e10bb32b..9c950498252 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp @@ -3117,7 +3117,7 @@ void unpacker::read_bcs() { void unpacker::read_bands() { byte* rp0 = rp; - + CHECK; read_file_header(); CHECK; @@ -3879,10 +3879,12 @@ void unpacker::dump_options() { // packed file and len is the length of the buffer. // If null, the callback is used to fill an internal buffer. void unpacker::start(void* packptr, size_t len) { + CHECK; NOT_PRODUCT(debug_u = this); if (packptr != null && len != 0) { inbytes.set((byte*) packptr, len); } + CHECK; read_bands(); } From f9122bd3fd36e7e1c113c9c50ca46ff2e29231a8 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Tue, 16 Oct 2012 16:38:38 -0700 Subject: [PATCH 008/180] 7200499: Better data validation for options Reviewed-by: darcy, jjh, mschoene --- jdk/src/share/bin/jli_util.h | 2 +- jdk/src/windows/bin/java_md.c | 32 ++++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/jdk/src/share/bin/jli_util.h b/jdk/src/share/bin/jli_util.h index 568318c95c6..dd53e936210 100644 --- a/jdk/src/share/bin/jli_util.h +++ b/jdk/src/share/bin/jli_util.h @@ -66,7 +66,7 @@ int JLI_GetStdArgc(); #include #define JLI_StrCaseCmp(p1, p2) stricmp((p1), (p2)) #define JLI_StrNCaseCmp(p1, p2, p3) strnicmp((p1), (p2), (p3)) -#define JLI_Snprintf _snprintf +size_t JLI_Snprintf(char *buffer, size_t size, const char *format, ...); void JLI_CmdToArgs(char *cmdline); #define JLI_Lseek _lseeki64 #else /* NIXES */ diff --git a/jdk/src/windows/bin/java_md.c b/jdk/src/windows/bin/java_md.c index e236cab1f2e..df118717279 100644 --- a/jdk/src/windows/bin/java_md.c +++ b/jdk/src/windows/bin/java_md.c @@ -101,7 +101,6 @@ int awtPreloadD3D = -1; /* funtion in awt.dll (src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp) */ #define D3D_PRELOAD_FUNC "preloadD3D" - /* Extracts value of a parameter with the specified name * from command line argument (returns pointer in the argument). * Returns NULL if the argument does not contains the parameter. @@ -276,7 +275,8 @@ LoadMSVCRT() #endif #ifdef CRT_DLL if (GetJREPath(crtpath, MAXPATHLEN)) { - if (JLI_StrLen(crtpath) + JLI_StrLen("\\bin\\") + JLI_StrLen(CRT_DLL) >= MAXPATHLEN) { + if (JLI_StrLen(crtpath) + JLI_StrLen("\\bin\\") + + JLI_StrLen(CRT_DLL) >= MAXPATHLEN) { JLI_ReportErrorMessage(JRE_ERROR11); return JNI_FALSE; } @@ -347,7 +347,8 @@ GetJVMPath(const char *jrepath, const char *jvmtype, if (JLI_StrChr(jvmtype, '/') || JLI_StrChr(jvmtype, '\\')) { JLI_Snprintf(jvmpath, jvmpathsize, "%s\\" JVM_DLL, jvmtype); } else { - JLI_Snprintf(jvmpath, jvmpathsize, "%s\\bin\\%s\\" JVM_DLL, jrepath, jvmtype); + JLI_Snprintf(jvmpath, jvmpathsize, "%s\\bin\\%s\\" JVM_DLL, + jrepath, jvmtype); } if (stat(jvmpath, &s) == 0) { return JNI_TRUE; @@ -526,6 +527,29 @@ jlong Counter2Micros(jlong counts) return (counts * 1000 * 1000)/counterFrequency.QuadPart; } +/* + * windows snprintf does not guarantee a null terminator in the buffer, + * if the computed size is equal to or greater than the buffer size, + * as well as error conditions, this function guarantees a null terminator + * under all these conditions. An unreasonable buffer size will return + * an error value. + */ +size_t +JLI_Snprintf(char* buffer, size_t size, const char* format, ...) +{ + size_t rc; + va_list vl; + if (size <= 0) + return -1; + va_start(vl, format); + rc = vsnprintf(buffer, size - 1, format, vl); + /* force a null terminator, if something is amiss */ + if (rc < 0 || rc >= size) + buffer[size - 1] = '\0'; + va_end(vl); + return rc; +} + void JLI_ReportErrorMessage(const char* fmt, ...) { va_list vl; @@ -880,7 +904,7 @@ unquote(const char *s) { */ void ExecJRE(char *jre, char **argv) { - int len; + jint len; char path[MAXPATHLEN + 1]; const char *progname = GetProgramName(); From 2414c54cc122c611c359e0e736cf43256602d75a Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Tue, 16 Oct 2012 10:56:25 -0700 Subject: [PATCH 009/180] 7200500: Launcher better input validation Reviewed-by: darcy, jjh, mschoene --- jdk/src/share/bin/parse_manifest.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/jdk/src/share/bin/parse_manifest.c b/jdk/src/share/bin/parse_manifest.c index ec3014931f2..22df69cb943 100644 --- a/jdk/src/share/bin/parse_manifest.c +++ b/jdk/src/share/bin/parse_manifest.c @@ -568,9 +568,9 @@ JLI_ParseManifest(char *jarfile, manifest_info *info) #ifdef O_BINARY | O_BINARY /* use binary mode on windows */ #endif - )) == -1) + )) == -1) { return (-1); - + } info->manifest_version = NULL; info->main_class = NULL; info->jre_version = NULL; @@ -617,12 +617,14 @@ JLI_JarUnpackFile(const char *jarfile, const char *filename, int *size) { zentry entry; void *data = NULL; - fd = open(jarfile, O_RDONLY + if ((fd = open(jarfile, O_RDONLY #ifdef O_BINARY | O_BINARY /* use binary mode on windows */ #endif - ); - if (fd != -1 && find_file(fd, &entry, filename) == 0) { + )) == -1) { + return NULL; + } + if (find_file(fd, &entry, filename) == 0) { data = inflate_file(fd, &entry, size); } close(fd); @@ -664,8 +666,9 @@ JLI_ManifestIterate(const char *jarfile, attribute_closure ac, void *user_data) #ifdef O_BINARY | O_BINARY /* use binary mode on windows */ #endif - )) == -1) + )) == -1) { return (-1); + } if (rc = find_file(fd, &entry, manifest_name) != 0) { close(fd); From 1193ef2418fbb3e307eb370fe769418e5b768b8f Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 22 Aug 2012 21:40:19 -0400 Subject: [PATCH 010/180] 6776941: Improve thread pool shutdown Reviewed-by: dl, skoivu --- .../util/concurrent/ThreadPoolExecutor.java | 172 +++++++++++------- 1 file changed, 104 insertions(+), 68 deletions(-) diff --git a/jdk/src/share/classes/java/util/concurrent/ThreadPoolExecutor.java b/jdk/src/share/classes/java/util/concurrent/ThreadPoolExecutor.java index db7adf0e417..b7be7274d3f 100644 --- a/jdk/src/share/classes/java/util/concurrent/ThreadPoolExecutor.java +++ b/jdk/src/share/classes/java/util/concurrent/ThreadPoolExecutor.java @@ -34,8 +34,10 @@ */ package java.util.concurrent; -import java.util.concurrent.locks.*; -import java.util.concurrent.atomic.*; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.atomic.AtomicInteger; import java.util.*; /** @@ -491,10 +493,15 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * policy limiting the number of threads. Even though it is not * treated as an error, failure to create threads may result in * new tasks being rejected or existing ones remaining stuck in - * the queue. On the other hand, no special precautions exist to - * handle OutOfMemoryErrors that might be thrown while trying to - * create threads, since there is generally no recourse from - * within this class. + * the queue. + * + * We go further and preserve pool invariants even in the face of + * errors such as OutOfMemoryError, that might be thrown while + * trying to create threads. Such errors are rather common due to + * the need to allocate a native stack in Thread#start, and users + * will want to perform clean pool shutdown to clean up. There + * will likely be enough memory available for the cleanup code to + * complete without encountering yet another OutOfMemoryError. */ private volatile ThreadFactory threadFactory; @@ -568,9 +575,13 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * task execution. This protects against interrupts that are * intended to wake up a worker thread waiting for a task from * instead interrupting a task being run. We implement a simple - * non-reentrant mutual exclusion lock rather than use ReentrantLock - * because we do not want worker tasks to be able to reacquire the - * lock when they invoke pool control methods like setCorePoolSize. + * non-reentrant mutual exclusion lock rather than use + * ReentrantLock because we do not want worker tasks to be able to + * reacquire the lock when they invoke pool control methods like + * setCorePoolSize. Additionally, to suppress interrupts until + * the thread actually starts running tasks, we initialize lock + * state to a negative value, and clear it upon start (in + * runWorker). */ private final class Worker extends AbstractQueuedSynchronizer @@ -594,6 +605,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * @param firstTask the first task (null if none) */ Worker(Runnable firstTask) { + setState(-1); // inhibit interrupts until runWorker this.firstTask = firstTask; this.thread = getThreadFactory().newThread(this); } @@ -609,7 +621,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService { // The value 1 represents the locked state. protected boolean isHeldExclusively() { - return getState() == 1; + return getState() != 0; } protected boolean tryAcquire(int unused) { @@ -630,6 +642,16 @@ public class ThreadPoolExecutor extends AbstractExecutorService { public boolean tryLock() { return tryAcquire(1); } public void unlock() { release(1); } public boolean isLocked() { return isHeldExclusively(); } + + void interruptIfStarted() { + Thread t; + if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) { + try { + t.interrupt(); + } catch (SecurityException ignore) { + } + } + } } /* @@ -728,12 +750,8 @@ public class ThreadPoolExecutor extends AbstractExecutorService { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { - for (Worker w : workers) { - try { - w.thread.interrupt(); - } catch (SecurityException ignore) { - } - } + for (Worker w : workers) + w.interruptIfStarted(); } finally { mainLock.unlock(); } @@ -790,19 +808,6 @@ public class ThreadPoolExecutor extends AbstractExecutorService { private static final boolean ONLY_ONE = true; - /** - * Ensures that unless the pool is stopping, the current thread - * does not have its interrupt set. This requires a double-check - * of state in case the interrupt was cleared concurrently with a - * shutdownNow -- if so, the interrupt is re-enabled. - */ - private void clearInterruptsForTaskRun() { - if (runStateLessThan(ctl.get(), STOP) && - Thread.interrupted() && - runStateAtLeast(ctl.get(), STOP)) - Thread.currentThread().interrupt(); - } - /* * Misc utilities, most of which are also exported to * ScheduledThreadPoolExecutor @@ -862,12 +867,13 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * Checks if a new worker can be added with respect to current * pool state and the given bound (either core or maximum). If so, * the worker count is adjusted accordingly, and, if possible, a - * new worker is created and started running firstTask as its + * new worker is created and started, running firstTask as its * first task. This method returns false if the pool is stopped or * eligible to shut down. It also returns false if the thread - * factory fails to create a thread when asked, which requires a - * backout of workerCount, and a recheck for termination, in case - * the existence of this worker was holding up termination. + * factory fails to create a thread when asked. If the thread + * creation fails, either due to the thread factory returning + * null, or due to an exception (typically OutOfMemoryError in + * Thread#start), we roll back cleanly. * * @param firstTask the task the new thread should run first (or * null if none). Workers are created with an initial first task @@ -910,46 +916,65 @@ public class ThreadPoolExecutor extends AbstractExecutorService { } } - Worker w = new Worker(firstTask); - Thread t = w.thread; + boolean workerStarted = false; + boolean workerAdded = false; + Worker w = null; + try { + final ReentrantLock mainLock = this.mainLock; + w = new Worker(firstTask); + final Thread t = w.thread; + if (t != null) { + mainLock.lock(); + try { + // Recheck while holding lock. + // Back out on ThreadFactory failure or if + // shut down before lock acquired. + int c = ctl.get(); + int rs = runStateOf(c); + if (rs < SHUTDOWN || + (rs == SHUTDOWN && firstTask == null)) { + if (t.isAlive()) // precheck that t is startable + throw new IllegalThreadStateException(); + workers.add(w); + int s = workers.size(); + if (s > largestPoolSize) + largestPoolSize = s; + workerAdded = true; + } + } finally { + mainLock.unlock(); + } + if (workerAdded) { + t.start(); + workerStarted = true; + } + } + } finally { + if (! workerStarted) + addWorkerFailed(w); + } + return workerStarted; + } + + /** + * Rolls back the worker thread creation. + * - removes worker from workers, if present + * - decrements worker count + * - rechecks for termination, in case the existence of this + * worker was holding up termination + */ + private void addWorkerFailed(Worker w) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { - // Recheck while holding lock. - // Back out on ThreadFactory failure or if - // shut down before lock acquired. - int c = ctl.get(); - int rs = runStateOf(c); - - if (t == null || - (rs >= SHUTDOWN && - ! (rs == SHUTDOWN && - firstTask == null))) { - decrementWorkerCount(); - tryTerminate(); - return false; - } - - workers.add(w); - - int s = workers.size(); - if (s > largestPoolSize) - largestPoolSize = s; + if (w != null) + workers.remove(w); + decrementWorkerCount(); + tryTerminate(); } finally { mainLock.unlock(); } - - t.start(); - // It is possible (but unlikely) for a thread to have been - // added to workers, but not yet started, during transition to - // STOP, which could result in a rare missed interrupt, - // because Thread.interrupt is not guaranteed to have any effect - // on a non-yet-started Thread (see Thread#interrupt). - if (runStateOf(ctl.get()) == STOP && ! t.isInterrupted()) - t.interrupt(); - - return true; } /** @@ -1096,15 +1121,25 @@ public class ThreadPoolExecutor extends AbstractExecutorService { * @param w the worker */ final void runWorker(Worker w) { + Thread wt = Thread.currentThread(); Runnable task = w.firstTask; w.firstTask = null; + w.unlock(); // allow interrupts boolean completedAbruptly = true; try { while (task != null || (task = getTask()) != null) { w.lock(); - clearInterruptsForTaskRun(); + // If pool is stopping, ensure thread is interrupted; + // if not, ensure thread is not interrupted. This + // requires a recheck in second case to deal with + // shutdownNow race while clearing interrupt + if ((runStateAtLeast(ctl.get(), STOP) || + (Thread.interrupted() && + runStateAtLeast(ctl.get(), STOP))) && + !wt.isInterrupted()) + wt.interrupt(); try { - beforeExecute(w.thread, task); + beforeExecute(wt, task); Throwable thrown = null; try { task.run(); @@ -2064,3 +2099,4 @@ public class ThreadPoolExecutor extends AbstractExecutorService { } } } + From c8ebc97b440104b7479b1d681967fb41a41c0052 Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Mon, 22 Oct 2012 07:28:51 -0700 Subject: [PATCH 011/180] 7192392: Better validation of client keys Also reviewed by Andrew Gross Reviewed-by: vinnie --- .../sun/crypto/provider/DHKeyAgreement.java | 5 + .../sun/security/pkcs11/P11KeyAgreement.java | 9 + .../sun/security/ssl/ClientHandshaker.java | 8 +- .../sun/security/ssl/DHClientKeyExchange.java | 19 +- .../classes/sun/security/ssl/DHCrypt.java | 87 ++++++-- .../sun/security/ssl/HandshakeMessage.java | 16 +- .../security/ssl/RSAClientKeyExchange.java | 4 +- .../sun/security/ssl/ServerHandshaker.java | 2 +- .../ssl/SignatureAndHashAlgorithm.java | 4 +- .../util/DisabledAlgorithmConstraints.java | 2 +- .../classes/sun/security/util/KeyLength.java | 91 -------- .../classes/sun/security/util/KeyUtil.java | 204 ++++++++++++++++++ .../security/mscapi/ShortRSAKeyWithinTLS.java | 6 +- 13 files changed, 334 insertions(+), 123 deletions(-) delete mode 100644 jdk/src/share/classes/sun/security/util/KeyLength.java create mode 100644 jdk/src/share/classes/sun/security/util/KeyUtil.java diff --git a/jdk/src/share/classes/com/sun/crypto/provider/DHKeyAgreement.java b/jdk/src/share/classes/com/sun/crypto/provider/DHKeyAgreement.java index b69875dd481..33fa49297dd 100644 --- a/jdk/src/share/classes/com/sun/crypto/provider/DHKeyAgreement.java +++ b/jdk/src/share/classes/com/sun/crypto/provider/DHKeyAgreement.java @@ -41,6 +41,8 @@ import javax.crypto.ShortBufferException; import javax.crypto.SecretKey; import javax.crypto.spec.*; +import sun.security.util.KeyUtil; + /** * This class implements the Diffie-Hellman key agreement protocol between * any number of parties. @@ -200,6 +202,9 @@ extends KeyAgreementSpi { throw new InvalidKeyException("Incompatible parameters"); } + // validate the Diffie-Hellman public key + KeyUtil.validate(dhPubKey); + // store the y value this.y = dhPubKey.getY(); diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11KeyAgreement.java b/jdk/src/share/classes/sun/security/pkcs11/P11KeyAgreement.java index dd7c3294649..11ce2b6126b 100644 --- a/jdk/src/share/classes/sun/security/pkcs11/P11KeyAgreement.java +++ b/jdk/src/share/classes/sun/security/pkcs11/P11KeyAgreement.java @@ -37,6 +37,7 @@ import javax.crypto.spec.*; import static sun.security.pkcs11.TemplateManager.*; import sun.security.pkcs11.wrapper.*; import static sun.security.pkcs11.wrapper.PKCS11Constants.*; +import sun.security.util.KeyUtil; /** * KeyAgreement implementation class. This class currently supports @@ -134,6 +135,10 @@ final class P11KeyAgreement extends KeyAgreementSpi { BigInteger p, g, y; if (key instanceof DHPublicKey) { DHPublicKey dhKey = (DHPublicKey)key; + + // validate the Diffie-Hellman public key + KeyUtil.validate(dhKey); + y = dhKey.getY(); DHParameterSpec params = dhKey.getParams(); p = params.getP(); @@ -145,6 +150,10 @@ final class P11KeyAgreement extends KeyAgreementSpi { try { DHPublicKeySpec spec = kf.engineGetKeySpec( key, DHPublicKeySpec.class); + + // validate the Diffie-Hellman public key + KeyUtil.validate(spec); + y = spec.getY(); p = spec.getP(); g = spec.getG(); diff --git a/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java b/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java index 63d48ad376d..0c1022b4ce7 100644 --- a/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java +++ b/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java @@ -192,8 +192,12 @@ final class ClientHandshaker extends Handshaker { } break; case K_DH_ANON: - this.serverKeyExchange(new DH_ServerKeyExchange( + try { + this.serverKeyExchange(new DH_ServerKeyExchange( input, protocolVersion)); + } catch (GeneralSecurityException e) { + throwSSLException("Server key", e); + } break; case K_DHE_DSS: case K_DHE_RSA: @@ -921,7 +925,7 @@ final class ClientHandshaker extends Handshaker { case K_DHE_RSA: case K_DHE_DSS: case K_DH_ANON: - preMasterSecret = dh.getAgreedSecret(serverDH); + preMasterSecret = dh.getAgreedSecret(serverDH, true); break; case K_ECDHE_RSA: case K_ECDHE_ECDSA: diff --git a/jdk/src/share/classes/sun/security/ssl/DHClientKeyExchange.java b/jdk/src/share/classes/sun/security/ssl/DHClientKeyExchange.java index 8838193a57b..b4500988970 100644 --- a/jdk/src/share/classes/sun/security/ssl/DHClientKeyExchange.java +++ b/jdk/src/share/classes/sun/security/ssl/DHClientKeyExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -29,7 +29,7 @@ package sun.security.ssl; import java.io.IOException; import java.io.PrintStream; import java.math.BigInteger; - +import javax.net.ssl.SSLHandshakeException; /* * Message used by clients to send their Diffie-Hellman public @@ -50,7 +50,7 @@ final class DHClientKeyExchange extends HandshakeMessage { private byte dh_Yc[]; // 1 to 2^16 -1 bytes BigInteger getClientPublicKey() { - return new BigInteger(1, dh_Yc); + return dh_Yc == null ? null : new BigInteger(1, dh_Yc); } /* @@ -72,7 +72,14 @@ final class DHClientKeyExchange extends HandshakeMessage { * but that's what the protocol spec requires.) */ DHClientKeyExchange(HandshakeInStream input) throws IOException { - dh_Yc = input.getBytes16(); + if (input.available() >= 2) { + dh_Yc = input.getBytes16(); + } else { + // currently, we don't support cipher suites that requires + // implicit public key of client. + throw new SSLHandshakeException( + "Unsupported implicit client DiffieHellman public key"); + } } int messageLength() { @@ -84,7 +91,9 @@ final class DHClientKeyExchange extends HandshakeMessage { } void send(HandshakeOutStream s) throws IOException { - s.putBytes16(dh_Yc); + if (dh_Yc != null && dh_Yc.length != 0) { + s.putBytes16(dh_Yc); + } } void print(PrintStream s) throws IOException { diff --git a/jdk/src/share/classes/sun/security/ssl/DHCrypt.java b/jdk/src/share/classes/sun/security/ssl/DHCrypt.java index d475ae8e978..ae9118f4ba5 100644 --- a/jdk/src/share/classes/sun/security/ssl/DHCrypt.java +++ b/jdk/src/share/classes/sun/security/ssl/DHCrypt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -28,12 +28,15 @@ package sun.security.ssl; import java.math.BigInteger; import java.security.*; - +import java.io.IOException; +import javax.net.ssl.SSLHandshakeException; import javax.crypto.SecretKey; import javax.crypto.KeyAgreement; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.*; +import sun.security.util.KeyUtil; + /** * This class implements the Diffie-Hellman key exchange algorithm. * D-H means combining your private key with your partners public key to @@ -54,7 +57,8 @@ import javax.crypto.spec.*; * . if we are server, call DHCrypt(keyLength,random). This generates * an ephemeral keypair of the request length. * . if we are client, call DHCrypt(modulus, base, random). This - * generates an ephemeral keypair using the parameters specified by the server. + * generates an ephemeral keypair using the parameters specified by + * the server. * . send parameters and public value to remote peer * . receive peers ephemeral public key * . call getAgreedSecret() to calculate the shared secret @@ -83,6 +87,9 @@ final class DHCrypt { // public component of our key, X = (g ^ x) mod p private BigInteger publicValue; // X (aka y) + // the times to recove from failure if public key validation + private static int MAX_FAILOVER_TIMES = 2; + /** * Generate a Diffie-Hellman keypair of the specified size. */ @@ -90,9 +97,12 @@ final class DHCrypt { try { KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("DiffieHellman"); kpg.initialize(keyLength, random); - KeyPair kp = kpg.generateKeyPair(); - privateKey = kp.getPrivate(); - DHPublicKeySpec spec = getDHPublicKeySpec(kp.getPublic()); + + DHPublicKeySpec spec = generateDHPublicKeySpec(kpg); + if (spec == null) { + throw new RuntimeException("Could not generate DH keypair"); + } + publicValue = spec.getY(); modulus = spec.getP(); base = spec.getG(); @@ -115,20 +125,25 @@ final class DHCrypt { KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("DiffieHellman"); DHParameterSpec params = new DHParameterSpec(modulus, base); kpg.initialize(params, random); - KeyPair kp = kpg.generateKeyPair(); - privateKey = kp.getPrivate(); - DHPublicKeySpec spec = getDHPublicKeySpec(kp.getPublic()); + + DHPublicKeySpec spec = generateDHPublicKeySpec(kpg); + if (spec == null) { + throw new RuntimeException("Could not generate DH keypair"); + } + publicValue = spec.getY(); } catch (GeneralSecurityException e) { throw new RuntimeException("Could not generate DH keypair", e); } } + static DHPublicKeySpec getDHPublicKeySpec(PublicKey key) { if (key instanceof DHPublicKey) { DHPublicKey dhKey = (DHPublicKey)key; DHParameterSpec params = dhKey.getParams(); - return new DHPublicKeySpec(dhKey.getY(), params.getP(), params.getG()); + return new DHPublicKeySpec(dhKey.getY(), + params.getP(), params.getG()); } try { KeyFactory factory = JsseJce.getKeyFactory("DH"); @@ -166,17 +181,32 @@ final class DHCrypt { *

It is illegal to call this member function if the private key * has not been set (or generated). * - * @param peerPublicKey the peer's public key. - * @returns the secret, which is an unsigned big-endian integer - * the same size as the Diffie-Hellman modulus. + * @param peerPublicKey the peer's public key. + * @param keyIsValidated whether the {@code peerPublicKey} has beed + * validated + * @return the secret, which is an unsigned big-endian integer + * the same size as the Diffie-Hellman modulus. */ - SecretKey getAgreedSecret(BigInteger peerPublicValue) { + SecretKey getAgreedSecret(BigInteger peerPublicValue, + boolean keyIsValidated) throws IOException { try { KeyFactory kf = JsseJce.getKeyFactory("DiffieHellman"); DHPublicKeySpec spec = new DHPublicKeySpec(peerPublicValue, modulus, base); PublicKey publicKey = kf.generatePublic(spec); KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman"); + + // validate the Diffie-Hellman public key + if (!keyIsValidated && + !KeyUtil.isOracleJCEProvider(ka.getProvider().getName())) { + try { + KeyUtil.validate(spec); + } catch (InvalidKeyException ike) { + // prefer handshake_failure alert to internal_error alert + throw new SSLHandshakeException(ike.getMessage()); + } + } + ka.init(privateKey); ka.doPhase(publicKey, true); return ka.generateSecret("TlsPremasterSecret"); @@ -185,4 +215,33 @@ final class DHCrypt { } } + // Generate and validate DHPublicKeySpec + private DHPublicKeySpec generateDHPublicKeySpec(KeyPairGenerator kpg) + throws GeneralSecurityException { + + boolean doExtraValiadtion = + (!KeyUtil.isOracleJCEProvider(kpg.getProvider().getName())); + for (int i = 0; i <= MAX_FAILOVER_TIMES; i++) { + KeyPair kp = kpg.generateKeyPair(); + privateKey = kp.getPrivate(); + DHPublicKeySpec spec = getDHPublicKeySpec(kp.getPublic()); + + // validate the Diffie-Hellman public key + if (doExtraValiadtion) { + try { + KeyUtil.validate(spec); + } catch (InvalidKeyException ivke) { + if (i == MAX_FAILOVER_TIMES) { + throw ivke; + } + // otherwise, ignore the exception and try the next one + continue; + } + } + + return spec; + } + + return null; + } } diff --git a/jdk/src/share/classes/sun/security/ssl/HandshakeMessage.java b/jdk/src/share/classes/sun/security/ssl/HandshakeMessage.java index 4b952fe9ed8..81364e07c53 100644 --- a/jdk/src/share/classes/sun/security/ssl/HandshakeMessage.java +++ b/jdk/src/share/classes/sun/security/ssl/HandshakeMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -41,12 +41,14 @@ import javax.security.auth.x500.X500Principal; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; +import javax.crypto.spec.DHPublicKeySpec; import javax.net.ssl.*; import sun.security.internal.spec.TlsPrfParameterSpec; import sun.security.ssl.CipherSuite.*; import static sun.security.ssl.CipherSuite.PRF.*; +import sun.security.util.KeyUtil; /** * Many data structures are involved in the handshake messages. These @@ -702,6 +704,7 @@ class DH_ServerKeyExchange extends ServerKeyExchange this.protocolVersion = protocolVersion; this.preferableSignatureAlgorithm = null; + // The DH key has been validated in the constructor of DHCrypt. setValues(obj); signature = null; } @@ -718,6 +721,7 @@ class DH_ServerKeyExchange extends ServerKeyExchange this.protocolVersion = protocolVersion; + // The DH key has been validated in the constructor of DHCrypt. setValues(obj); Signature sig; @@ -744,7 +748,8 @@ class DH_ServerKeyExchange extends ServerKeyExchange * DH_anon key exchange */ DH_ServerKeyExchange(HandshakeInStream input, - ProtocolVersion protocolVersion) throws IOException { + ProtocolVersion protocolVersion) + throws IOException, GeneralSecurityException { this.protocolVersion = protocolVersion; this.preferableSignatureAlgorithm = null; @@ -752,6 +757,10 @@ class DH_ServerKeyExchange extends ServerKeyExchange dh_p = input.getBytes16(); dh_g = input.getBytes16(); dh_Ys = input.getBytes16(); + KeyUtil.validate(new DHPublicKeySpec(new BigInteger(1, dh_Ys), + new BigInteger(1, dh_p), + new BigInteger(1, dh_g))); + signature = null; } @@ -772,6 +781,9 @@ class DH_ServerKeyExchange extends ServerKeyExchange dh_p = input.getBytes16(); dh_g = input.getBytes16(); dh_Ys = input.getBytes16(); + KeyUtil.validate(new DHPublicKeySpec(new BigInteger(1, dh_Ys), + new BigInteger(1, dh_p), + new BigInteger(1, dh_g))); // read the signature and hash algorithm if (protocolVersion.v >= ProtocolVersion.TLS12.v) { diff --git a/jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java b/jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java index 36fda8c39cb..7166ecdcb24 100644 --- a/jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java +++ b/jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java @@ -36,7 +36,7 @@ import javax.crypto.spec.*; import javax.net.ssl.*; import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; -import sun.security.util.KeyLength; +import sun.security.util.KeyUtil; /** * This is the client key exchange message (CLIENT --> SERVER) used with @@ -193,7 +193,7 @@ final class RSAClientKeyExchange extends HandshakeMessage { "unable to get the plaintext of the premaster secret"); } - int keySize = KeyLength.getKeySize(secretKey); + int keySize = KeyUtil.getKeySize(secretKey); if (keySize > 0 && keySize != 384) { // 384 = 48 * 8 if (debug != null && Debug.isOn("handshake")) { System.out.println( diff --git a/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java b/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java index a8d256f76d6..c651b444f49 100644 --- a/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java +++ b/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java @@ -1365,7 +1365,7 @@ final class ServerHandshaker extends Handshaker { if (debug != null && Debug.isOn("handshake")) { mesg.print(System.out); } - return dh.getAgreedSecret(mesg.getClientPublicKey()); + return dh.getAgreedSecret(mesg.getClientPublicKey(), false); } private SecretKey clientKeyExchange(ECDHClientKeyExchange mesg) diff --git a/jdk/src/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java b/jdk/src/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java index d1bc65393bb..043b9b156f7 100644 --- a/jdk/src/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java +++ b/jdk/src/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java @@ -38,7 +38,7 @@ import java.util.Collection; import java.util.Collections; import java.util.ArrayList; -import sun.security.util.KeyLength; +import sun.security.util.KeyUtil; /** * Signature and hash algorithm. @@ -279,7 +279,7 @@ final class SignatureAndHashAlgorithm { * If key size is less than 512, the digest length should be * less than or equal to 20 bytes. */ - int keySize = KeyLength.getKeySize(signingKey); + int keySize = KeyUtil.getKeySize(signingKey); if (keySize >= 768) { maxDigestLength = HashAlgorithm.SHA512.length; } else if ((keySize >= 512) && (keySize < 768)) { diff --git a/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java b/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java index ca0393a323d..17b56974ea3 100644 --- a/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java +++ b/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java @@ -440,7 +440,7 @@ public class DisabledAlgorithmConstraints implements AlgorithmConstraints { // Does this key constraint disable the specified key? public boolean disables(Key key) { - int size = KeyLength.getKeySize(key); + int size = KeyUtil.getKeySize(key); if (size == 0) { return true; // we don't allow any key of size 0. diff --git a/jdk/src/share/classes/sun/security/util/KeyLength.java b/jdk/src/share/classes/sun/security/util/KeyLength.java deleted file mode 100644 index 3ffbac3f30f..00000000000 --- a/jdk/src/share/classes/sun/security/util/KeyLength.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.security.util; - -import java.security.Key; -import java.security.PrivilegedAction; -import java.security.AccessController; -import java.security.interfaces.ECKey; -import java.security.interfaces.RSAKey; -import java.security.interfaces.DSAKey; -import javax.crypto.SecretKey; -import javax.crypto.interfaces.DHKey; - -/** - * A utility class to get key length - */ -public final class KeyLength { - - /** - * Returns the key size of the given key object in bits. - * - * @param key the key object, cannot be null - * @return the key size of the given key object in bits, or -1 if the - * key size is not accessible - */ - final public static int getKeySize(Key key) { - int size = -1; - - if (key instanceof Length) { - try { - Length ruler = (Length)key; - size = ruler.length(); - } catch (UnsupportedOperationException usoe) { - // ignore the exception - } - - if (size >= 0) { - return size; - } - } - - // try to parse the length from key specification - if (key instanceof SecretKey) { - SecretKey sk = (SecretKey)key; - String format = sk.getFormat(); - if ("RAW".equals(format) && sk.getEncoded() != null) { - size = (sk.getEncoded().length * 8); - } // Otherwise, it may be a unextractable key of PKCS#11, or - // a key we are not able to handle. - } else if (key instanceof RSAKey) { - RSAKey pubk = (RSAKey)key; - size = pubk.getModulus().bitLength(); - } else if (key instanceof ECKey) { - ECKey pubk = (ECKey)key; - size = pubk.getParams().getOrder().bitLength(); - } else if (key instanceof DSAKey) { - DSAKey pubk = (DSAKey)key; - size = pubk.getParams().getP().bitLength(); - } else if (key instanceof DHKey) { - DHKey pubk = (DHKey)key; - size = pubk.getParams().getP().bitLength(); - } // Otherwise, it may be a unextractable key of PKCS#11, or - // a key we are not able to handle. - - return size; - } -} - diff --git a/jdk/src/share/classes/sun/security/util/KeyUtil.java b/jdk/src/share/classes/sun/security/util/KeyUtil.java new file mode 100644 index 00000000000..6664dab38b6 --- /dev/null +++ b/jdk/src/share/classes/sun/security/util/KeyUtil.java @@ -0,0 +1,204 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.util; + +import java.security.Key; +import java.security.PrivilegedAction; +import java.security.AccessController; +import java.security.InvalidKeyException; +import java.security.interfaces.ECKey; +import java.security.interfaces.RSAKey; +import java.security.interfaces.DSAKey; +import java.security.spec.KeySpec; +import javax.crypto.SecretKey; +import javax.crypto.interfaces.DHKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; +import javax.crypto.spec.DHPublicKeySpec; +import java.math.BigInteger; + +/** + * A utility class to get key length, valiate keys, etc. + */ +public final class KeyUtil { + + /** + * Returns the key size of the given key object in bits. + * + * @param key the key object, cannot be null + * @return the key size of the given key object in bits, or -1 if the + * key size is not accessible + */ + public static final int getKeySize(Key key) { + int size = -1; + + if (key instanceof Length) { + try { + Length ruler = (Length)key; + size = ruler.length(); + } catch (UnsupportedOperationException usoe) { + // ignore the exception + } + + if (size >= 0) { + return size; + } + } + + // try to parse the length from key specification + if (key instanceof SecretKey) { + SecretKey sk = (SecretKey)key; + String format = sk.getFormat(); + if ("RAW".equals(format) && sk.getEncoded() != null) { + size = (sk.getEncoded().length * 8); + } // Otherwise, it may be a unextractable key of PKCS#11, or + // a key we are not able to handle. + } else if (key instanceof RSAKey) { + RSAKey pubk = (RSAKey)key; + size = pubk.getModulus().bitLength(); + } else if (key instanceof ECKey) { + ECKey pubk = (ECKey)key; + size = pubk.getParams().getOrder().bitLength(); + } else if (key instanceof DSAKey) { + DSAKey pubk = (DSAKey)key; + size = pubk.getParams().getP().bitLength(); + } else if (key instanceof DHKey) { + DHKey pubk = (DHKey)key; + size = pubk.getParams().getP().bitLength(); + } // Otherwise, it may be a unextractable key of PKCS#11, or + // a key we are not able to handle. + + return size; + } + + /** + * Returns whether the key is valid or not. + *

+ * Note that this method is only apply to DHPublicKey at present. + * + * @param publicKey + * the key object, cannot be null + * + * @throws NullPointerException if {@code publicKey} is null + * @throws InvalidKeyException if {@code publicKey} is invalid + */ + public static final void validate(Key key) + throws InvalidKeyException { + if (key == null) { + throw new NullPointerException( + "The key to be validated cannot be null"); + } + + if (key instanceof DHPublicKey) { + validateDHPublicKey((DHPublicKey)key); + } + } + + + /** + * Returns whether the key spec is valid or not. + *

+ * Note that this method is only apply to DHPublicKeySpec at present. + * + * @param keySpec + * the key spec object, cannot be null + * + * @throws NullPointerException if {@code keySpec} is null + * @throws InvalidKeyException if {@code keySpec} is invalid + */ + public static final void validate(KeySpec keySpec) + throws InvalidKeyException { + if (keySpec == null) { + throw new NullPointerException( + "The key spec to be validated cannot be null"); + } + + if (keySpec instanceof DHPublicKeySpec) { + validateDHPublicKey((DHPublicKeySpec)keySpec); + } + } + + /** + * Returns whether the specified provider is Oracle provider or not. + *

+ * Note that this method is only apply to SunJCE and SunPKCS11 at present. + * + * @param providerName + * the provider name + * @return true if, and only if, the provider of the specified + * {@code providerName} is Oracle provider + */ + public static final boolean isOracleJCEProvider(String providerName) { + return providerName != null && (providerName.equals("SunJCE") || + providerName.startsWith("SunPKCS11")); + } + + /** + * Returns whether the Diffie-Hellman public key is valid or not. + * + * Per RFC 2631 and NIST SP800-56A, the following algorithm is used to + * validate Diffie-Hellman public keys: + * 1. Verify that y lies within the interval [2,p-1]. If it does not, + * the key is invalid. + * 2. Compute y^q mod p. If the result == 1, the key is valid. + * Otherwise the key is invalid. + */ + private static void validateDHPublicKey(DHPublicKey publicKey) + throws InvalidKeyException { + DHParameterSpec paramSpec = publicKey.getParams(); + + BigInteger p = paramSpec.getP(); + BigInteger g = paramSpec.getG(); + BigInteger y = publicKey.getY(); + + validateDHPublicKey(p, g, y); + } + + private static void validateDHPublicKey(DHPublicKeySpec publicKeySpec) + throws InvalidKeyException { + validateDHPublicKey(publicKeySpec.getP(), + publicKeySpec.getG(), publicKeySpec.getY()); + } + + private static void validateDHPublicKey(BigInteger p, + BigInteger g, BigInteger y) throws InvalidKeyException { + + // For better interoperability, the interval is limited to [2, p-2]. + BigInteger leftOpen = BigInteger.ONE; + BigInteger rightOpen = p.subtract(BigInteger.ONE); + if (y.compareTo(leftOpen) <= 0) { + throw new InvalidKeyException( + "Diffie-Hellman public key is too small"); + } + if (y.compareTo(rightOpen) >= 0) { + throw new InvalidKeyException( + "Diffie-Hellman public key is too large"); + } + + // Don't bother to check against the y^q mod p if safe primes are used. + } +} + diff --git a/jdk/test/sun/security/mscapi/ShortRSAKeyWithinTLS.java b/jdk/test/sun/security/mscapi/ShortRSAKeyWithinTLS.java index e4f7eb1a773..8958718ae7a 100644 --- a/jdk/test/sun/security/mscapi/ShortRSAKeyWithinTLS.java +++ b/jdk/test/sun/security/mscapi/ShortRSAKeyWithinTLS.java @@ -29,7 +29,7 @@ import javax.net.*; import javax.net.ssl.*; import java.lang.reflect.*; -import sun.security.util.KeyLength; +import sun.security.util.KeyUtil; public class ShortRSAKeyWithinTLS { @@ -175,13 +175,13 @@ public class ShortRSAKeyWithinTLS { privateKey = (PrivateKey)ks.getKey(keyAlias, null); publicKey = (PublicKey)ks.getCertificate(keyAlias).getPublicKey(); - int privateKeySize = KeyLength.getKeySize(privateKey); + int privateKeySize = KeyUtil.getKeySize(privateKey); if (privateKeySize != keySize) { throw new Exception("Expected key size is " + keySize + ", but the private key size is " + privateKeySize); } - int publicKeySize = KeyLength.getKeySize(publicKey); + int publicKeySize = KeyUtil.getKeySize(publicKey); if (publicKeySize != keySize) { throw new Exception("Expected key size is " + keySize + ", but the public key size is " + publicKeySize); From 64bb35a5c6a514314ea81dc373a5bf62eadeba76 Mon Sep 17 00:00:00 2001 From: Kurchi Subhra Hazra Date: Mon, 22 Oct 2012 11:49:37 -0700 Subject: [PATCH 012/180] 7186954: Improve connection performance Reviewed-by: chegar, skoivu --- .../sun/net/httpserver/ChunkedInputStream.java | 14 +++++++++++--- .../sun/net/www/http/ChunkedInputStream.java | 9 +++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/jdk/src/share/classes/sun/net/httpserver/ChunkedInputStream.java b/jdk/src/share/classes/sun/net/httpserver/ChunkedInputStream.java index 4adab7d52ed..387ec1c8e62 100644 --- a/jdk/src/share/classes/sun/net/httpserver/ChunkedInputStream.java +++ b/jdk/src/share/classes/sun/net/httpserver/ChunkedInputStream.java @@ -41,8 +41,12 @@ class ChunkedInputStream extends LeftOverInputStream { private boolean needToReadHeader = true; - static char CR = '\r'; - static char LF = '\n'; + final static char CR = '\r'; + final static char LF = '\n'; + /* + * Maximum chunk header size of 2KB + 2 bytes for CRLF + */ + private final static int MAX_CHUNK_HEADER_SIZE = 2050; private int numeric (char[] arr, int nchars) throws IOException { assert arr.length >= nchars; @@ -73,10 +77,14 @@ class ChunkedInputStream extends LeftOverInputStream { char[] len_arr = new char [16]; int len_size = 0; boolean end_of_len = false; + int read = 0; while ((c=in.read())!= -1) { char ch = (char) c; - if (len_size == len_arr.length -1) { + read++; + if ((len_size == len_arr.length -1) || + (read > MAX_CHUNK_HEADER_SIZE)) + { throw new IOException ("invalid chunk header"); } if (gotCR) { diff --git a/jdk/src/share/classes/sun/net/www/http/ChunkedInputStream.java b/jdk/src/share/classes/sun/net/www/http/ChunkedInputStream.java index 3dd445e7488..af45752206f 100644 --- a/jdk/src/share/classes/sun/net/www/http/ChunkedInputStream.java +++ b/jdk/src/share/classes/sun/net/www/http/ChunkedInputStream.java @@ -125,6 +125,11 @@ class ChunkedInputStream extends InputStream implements Hurryable { */ private boolean closed; + /* + * Maximum chunk header size of 2KB + 2 bytes for CRLF + */ + private final static int MAX_CHUNK_HEADER_SIZE = 2050; + /** * State to indicate that next field should be :- * chunk-size [ chunk-extension ] CRLF @@ -290,6 +295,10 @@ class ChunkedInputStream extends InputStream implements Hurryable { break; } pos++; + if ((pos - rawPos) >= MAX_CHUNK_HEADER_SIZE) { + error = true; + throw new IOException("Chunk header too long"); + } } if (pos >= rawCount) { return; From 42cf97b02fd2a64bf8ab254087cdee142c4326c9 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 19 Sep 2012 12:58:43 +0800 Subject: [PATCH 013/180] 8000210: Improve JarFile code quality Reviewed-by: ahgross, xuelei, mschoene --- .../share/classes/java/util/jar/JarFile.java | 21 ++++++++++--------- .../security/util/DerIndefLenConverter.java | 4 ++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/jdk/src/share/classes/java/util/jar/JarFile.java b/jdk/src/share/classes/java/util/jar/JarFile.java index 513d509e2f8..2dbb5206512 100644 --- a/jdk/src/share/classes/java/util/jar/JarFile.java +++ b/jdk/src/share/classes/java/util/jar/JarFile.java @@ -34,6 +34,7 @@ import java.security.CodeSigner; import java.security.cert.Certificate; import java.security.AccessController; import java.security.CodeSource; +import sun.misc.IOUtils; import sun.security.action.GetPropertyAction; import sun.security.util.ManifestEntryVerifier; import sun.misc.SharedSecrets; @@ -329,6 +330,9 @@ class JarFile extends ZipFile { if (names != null) { for (int i = 0; i < names.length; i++) { JarEntry e = getJarEntry(names[i]); + if (e == null) { + throw new JarException("corrupted jar file"); + } if (!e.isDirectory()) { if (mev == null) { mev = new ManifestEntryVerifier @@ -348,6 +352,10 @@ class JarFile extends ZipFile { // treat the jar file as being unsigned jv = null; verify = false; + if (JarVerifier.debug != null) { + JarVerifier.debug.println("jarfile parsing error!"); + ex.printStackTrace(); + } } // if after initializing the verifier we have nothing @@ -375,11 +383,9 @@ class JarFile extends ZipFile { * META-INF files. */ private byte[] getBytes(ZipEntry ze) throws IOException { - byte[] b = new byte[(int)ze.getSize()]; - try (DataInputStream is = new DataInputStream(super.getInputStream(ze))) { - is.readFully(b, 0, b.length); + try (InputStream is = super.getInputStream(ze)) { + return IOUtils.readFully(is, (int)ze.getSize(), true); } - return b; } /** @@ -479,12 +485,7 @@ class JarFile extends ZipFile { if (!isKnownToNotHaveClassPathAttribute()) { JarEntry manEntry = getManEntry(); if (manEntry != null) { - byte[] b = new byte[(int)manEntry.getSize()]; - try (DataInputStream dis = new DataInputStream( - super.getInputStream(manEntry))) { - dis.readFully(b, 0, b.length); - } - + byte[] b = getBytes(manEntry); int last = b.length - src.length; int i = 0; next: diff --git a/jdk/src/share/classes/sun/security/util/DerIndefLenConverter.java b/jdk/src/share/classes/sun/security/util/DerIndefLenConverter.java index 50bb06ad7b3..78d9e302d6c 100644 --- a/jdk/src/share/classes/sun/security/util/DerIndefLenConverter.java +++ b/jdk/src/share/classes/sun/security/util/DerIndefLenConverter.java @@ -325,6 +325,10 @@ class DerIndefLenConverter { } } + if (unresolved != 0) { + throw new IOException("not all indef len BER resolved"); + } + newData = new byte[dataSize + numOfTotalLenBytes + unused]; dataPos=0; newDataPos=0; index=0; From cb3cb72e07d5e881ca4fc5f36e1b8dcd11c28d78 Mon Sep 17 00:00:00 2001 From: Sean Mullan Date: Fri, 26 Oct 2012 15:21:05 -0400 Subject: [PATCH 014/180] 7201068: Better handling of UI elements Reviewed-by: xuelei --- jdk/src/share/lib/security/java.security | 16 ++++++++++++++-- .../share/lib/security/java.security-macosx | 18 ++++++++++++++++-- .../share/lib/security/java.security-solaris | 16 ++++++++++++++-- .../share/lib/security/java.security-windows | 16 ++++++++++++++-- 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/jdk/src/share/lib/security/java.security b/jdk/src/share/lib/security/java.security index 3bb8597654c..d0dc3c5b423 100644 --- a/jdk/src/share/lib/security/java.security +++ b/jdk/src/share/lib/security/java.security @@ -145,7 +145,13 @@ keystore.type=jks # passed to checkPackageAccess unless the # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. -package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal. +package.access=sun.,\ + com.sun.xml.internal.,\ + com.sun.imageio.,\ + com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.glassfish.external.,\ + com.sun.org.glassfish.gmbal. # # List of comma-separated packages that start with or equal this string @@ -157,7 +163,13 @@ package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun. # by default, none of the class loaders supplied with the JDK call # checkPackageDefinition. # -package.definition=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal. +package.definition=sun.,\ + com.sun.xml.internal.,\ + com.sun.imageio.,\ + com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.glassfish.external.,\ + com.sun.org.glassfish.gmbal. # # Determines whether this properties file can be appended to diff --git a/jdk/src/share/lib/security/java.security-macosx b/jdk/src/share/lib/security/java.security-macosx index 689172f40d6..22c6b44c567 100644 --- a/jdk/src/share/lib/security/java.security-macosx +++ b/jdk/src/share/lib/security/java.security-macosx @@ -146,7 +146,14 @@ keystore.type=jks # passed to checkPackageAccess unless the # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. -package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,apple.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal. +package.access=sun.,\ + com.sun.xml.internal.,\ + com.sun.imageio.,\ + com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.glassfish.external.,\ + com.sun.org.glassfish.gmbal.,\ + apple. # # List of comma-separated packages that start with or equal this string @@ -158,7 +165,14 @@ package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun. # by default, none of the class loaders supplied with the JDK call # checkPackageDefinition. # -package.definition=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,apple.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal. +package.definition=sun.,\ + com.sun.xml.internal.,\ + com.sun.imageio.,\ + com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.glassfish.external.,\ + com.sun.org.glassfish.gmbal.,\ + apple. # # Determines whether this properties file can be appended to diff --git a/jdk/src/share/lib/security/java.security-solaris b/jdk/src/share/lib/security/java.security-solaris index 1c5062c4c8b..c26b06a8de4 100644 --- a/jdk/src/share/lib/security/java.security-solaris +++ b/jdk/src/share/lib/security/java.security-solaris @@ -147,7 +147,13 @@ keystore.type=jks # passed to checkPackageAccess unless the # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. -package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal. +package.access=sun.,\ + com.sun.xml.internal.,\ + com.sun.imageio.,\ + com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.glassfish.external.,\ + com.sun.org.glassfish.gmbal. # # List of comma-separated packages that start with or equal this string @@ -159,7 +165,13 @@ package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun. # by default, none of the class loaders supplied with the JDK call # checkPackageDefinition. # -package.definition=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal. +package.definition=sun.,\ + com.sun.xml.internal.,\ + com.sun.imageio.,\ + com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.glassfish.external.,\ + com.sun.org.glassfish.gmbal. # # Determines whether this properties file can be appended to diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows index c98c0c95865..f9103a98718 100644 --- a/jdk/src/share/lib/security/java.security-windows +++ b/jdk/src/share/lib/security/java.security-windows @@ -146,7 +146,13 @@ keystore.type=jks # passed to checkPackageAccess unless the # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. -package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal. +package.access=sun.,\ + com.sun.xml.internal.,\ + com.sun.imageio.,\ + com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.glassfish.external.,\ + com.sun.org.glassfish.gmbal. # # List of comma-separated packages that start with or equal this string @@ -158,7 +164,13 @@ package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun. # by default, none of the class loaders supplied with the JDK call # checkPackageDefinition. # -package.definition=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal. +package.definition=sun.,\ + com.sun.xml.internal.,\ + com.sun.imageio.,\ + com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.glassfish.external.,\ + com.sun.org.glassfish.gmbal. # # Determines whether this properties file can be appended to From 526b1f405ca7a6b8646905a44d9083eea3a6c810 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Tue, 30 Oct 2012 17:05:45 +0400 Subject: [PATCH 015/180] 8000539: JMX implementation allows invocation of methods of a system class Added extra packageAccess check call Reviewed-by: ahgross, dfuchs --- .../classes/com/sun/jmx/mbeanserver/Introspector.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java index 2e259a818c8..365a004778e 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java @@ -56,6 +56,8 @@ import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import javax.management.AttributeNotFoundException; import javax.management.openmbean.CompositeData; +import sun.reflect.misc.MethodUtil; +import sun.reflect.misc.ReflectUtil; /** * This class contains the methods for performing all the tests needed to verify @@ -528,8 +530,10 @@ public class Introspector { // to locate method readMethod = SimpleIntrospector.getReadMethod(clazz, element); } - if (readMethod != null) - return readMethod.invoke(complex); + if (readMethod != null) { + ReflectUtil.checkPackageAccess(readMethod.getDeclaringClass()); + return MethodUtil.invoke(readMethod, complex, new Class[0]); + } throw new AttributeNotFoundException( "Could not find the getter method for the property " + From 25e301ca19586c57c9047b42e0ccea9183105463 Mon Sep 17 00:00:00 2001 From: Sean Coffey Date: Tue, 30 Oct 2012 17:06:35 +0000 Subject: [PATCH 016/180] 8000631: Restrict access to class constructor Reviewed-by: alanb, ahgross --- .../com_sun_corba_se_impl_orbutil.jmk | 14 +- .../com/sun/corba/se/impl/corba/AnyImpl.java | 6 +- .../se/impl/encoding/CDRInputStream_1_0.java | 61 +- .../se/impl/encoding/CDROutputStream_1_0.java | 20 +- .../sun/corba/se/impl/io/FVDCodeBaseImpl.java | 8 +- .../corba/se/impl/io/ValueHandlerImpl.java | 85 +- .../sun/corba/se/impl/io/ValueUtility.java | 10 +- .../corba/se/impl/javax/rmi/CORBA/Util.java | 6 +- .../com/sun/corba/se/impl/orb/ORBImpl.java | 2 +- .../se/impl/orbutil/IIOPInputStream_1_3.java | 57 - .../se/impl/orbutil/IIOPOutputStream_1_3.java | 68 -- .../impl/orbutil/IIOPOutputStream_1_3_1.java | 66 - .../sun/corba/se/impl/orbutil/ORBUtility.java | 38 +- .../se/impl/orbutil/RepIdDelegator_1_3.java | 177 --- .../se/impl/orbutil/RepIdDelegator_1_3_1.java | 177 --- .../impl/orbutil/RepositoryIdCache_1_3.java | 108 -- .../impl/orbutil/RepositoryIdCache_1_3_1.java | 102 -- .../se/impl/orbutil/RepositoryIdFactory.java | 53 +- .../se/impl/orbutil/RepositoryId_1_3.java | 990 --------------- .../se/impl/orbutil/RepositoryId_1_3_1.java | 1065 ----------------- .../se/impl/orbutil/ValueHandlerImpl_1_3.java | 251 ---- .../impl/orbutil/ValueHandlerImpl_1_3_1.java | 77 -- .../corba/JavaCorbaAccess.java} | 32 +- .../classes/sun/corba/SharedSecrets.java | 60 + 24 files changed, 123 insertions(+), 3410 deletions(-) delete mode 100644 corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPInputStream_1_3.java delete mode 100644 corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPOutputStream_1_3.java delete mode 100644 corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPOutputStream_1_3_1.java delete mode 100644 corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3.java delete mode 100644 corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3_1.java delete mode 100644 corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3.java delete mode 100644 corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3_1.java delete mode 100644 corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryId_1_3.java delete mode 100644 corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryId_1_3_1.java delete mode 100644 corba/src/share/classes/com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3.java delete mode 100644 corba/src/share/classes/com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3_1.java rename corba/src/share/classes/{com/sun/corba/se/impl/orbutil/IIOPInputStream_1_3_1.java => sun/corba/JavaCorbaAccess.java} (58%) create mode 100644 corba/src/share/classes/sun/corba/SharedSecrets.java diff --git a/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_orbutil.jmk b/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_orbutil.jmk index 5009bb508e3..465c546ec59 100644 --- a/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_orbutil.jmk +++ b/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_orbutil.jmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 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 @@ -29,10 +29,6 @@ com_sun_corba_se_impl_orbutil_java = \ com/sun/corba/se/impl/orbutil/DenseIntMapImpl.java \ com/sun/corba/se/impl/orbutil/GetPropertyAction.java \ com/sun/corba/se/impl/orbutil/HexOutputStream.java \ - com/sun/corba/se/impl/orbutil/IIOPInputStream_1_3.java \ - com/sun/corba/se/impl/orbutil/IIOPInputStream_1_3_1.java \ - com/sun/corba/se/impl/orbutil/IIOPOutputStream_1_3.java \ - com/sun/corba/se/impl/orbutil/IIOPOutputStream_1_3_1.java \ com/sun/corba/se/impl/orbutil/LegacyHookGetFields.java \ com/sun/corba/se/impl/orbutil/LegacyHookPutFields.java \ com/sun/corba/se/impl/orbutil/LogKeywords.java \ @@ -45,19 +41,11 @@ com_sun_corba_se_impl_orbutil_java = \ com/sun/corba/se/impl/orbutil/ORBUtility.java \ com/sun/corba/se/impl/orbutil/ORBClassLoader.java \ com/sun/corba/se/impl/orbutil/RepIdDelegator.java \ - com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3.java \ - com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3_1.java \ - com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3.java \ - com/sun/corba/se/impl/orbutil/RepositoryId_1_3.java \ com/sun/corba/se/impl/orbutil/RepositoryIdFactory.java \ com/sun/corba/se/impl/orbutil/RepositoryIdStrings.java \ com/sun/corba/se/impl/orbutil/RepositoryIdUtility.java \ com/sun/corba/se/impl/orbutil/RepositoryIdInterface.java \ - com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3_1.java \ - com/sun/corba/se/impl/orbutil/RepositoryId_1_3_1.java \ com/sun/corba/se/impl/orbutil/StackImpl.java \ - com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3_1.java \ - com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3.java \ com/sun/corba/se/impl/orbutil/closure/Future.java \ com/sun/corba/se/impl/orbutil/closure/Constant.java \ com/sun/corba/se/impl/orbutil/concurrent/Sync.java \ diff --git a/corba/src/share/classes/com/sun/corba/se/impl/corba/AnyImpl.java b/corba/src/share/classes/com/sun/corba/se/impl/corba/AnyImpl.java index 6b33f34b9a9..0177bdd6407 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/corba/AnyImpl.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/corba/AnyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -1218,7 +1218,7 @@ public class AnyImpl extends Any // See bug 4391648 for more info about the tcORB in this // case. RepositoryIdStrings repStrs - = RepositoryIdFactory.getRepIdStringsFactory(tcORB); + = RepositoryIdFactory.getRepIdStringsFactory(); // Assertion: c instanceof Serializable? @@ -1251,7 +1251,7 @@ public class AnyImpl extends Any // Anything else // We know that this is a TypeCodeImpl since it is our ORB classTC = (TypeCodeImpl)ValueUtility.createTypeCodeForClass( - tcORB, c, ORBUtility.createValueHandler(tcORB)); + tcORB, c, ORBUtility.createValueHandler()); // Intruct classTC to store its buffer classTC.setCaching(true); // Update the cache diff --git a/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDRInputStream_1_0.java b/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDRInputStream_1_0.java index d17d6f378e2..a00d66cb5b5 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDRInputStream_1_0.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDRInputStream_1_0.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -269,8 +269,8 @@ public class CDRInputStream_1_0 extends CDRInputStreamBase private final void createRepositoryIdHandlers() { - repIdUtil = RepositoryIdFactory.getRepIdUtility(orb); - repIdStrs = RepositoryIdFactory.getRepIdStringsFactory(orb); + repIdUtil = RepositoryIdFactory.getRepIdUtility(); + repIdStrs = RepositoryIdFactory.getRepIdStringsFactory(); } public GIOPVersion getGIOPVersion() { @@ -564,10 +564,7 @@ public class CDRInputStream_1_0 extends CDRInputStreamBase checkForNegativeLength(len); - if (orb != null && ORBUtility.isLegacyORB((ORB)orb)) - return legacyReadString(len); - else - return internalReadString(len); + return internalReadString(len); } private final String internalReadString(int len) { @@ -588,54 +585,6 @@ public class CDRInputStream_1_0 extends CDRInputStreamBase return new String(result, 0, getCharConverter().getNumChars()); } - private final String legacyReadString(int len) { - - // - // Workaround for ORBs which send string lengths of - // zero to mean empty string. - // - // - // IMPORTANT: Do not replace 'new String("")' with "", it may result - // in a Serialization bug (See serialization.zerolengthstring) and - // bug id: 4728756 for details - if (len == 0) - return new String(""); - - len--; - char[] c = new char[len]; - - int n = 0; - while (n < len) { - int avail; - int bytes; - int wanted; - - avail = bbwi.buflen - bbwi.position(); - if (avail <= 0) { - grow(1, 1); - avail = bbwi.buflen - bbwi.position(); - } - wanted = len - n; - bytes = (wanted < avail) ? wanted : avail; - // Microbenchmarks are showing a loop of ByteBuffer.get(int) being - // faster than ByteBuffer.get(byte[], int, int). - for (int i=0; i bbwi.buflen) - alignAndCheck(1, 1); - bbwi.position(bbwi.position() + 1); - - return new String(c); - } - public final String read_string() { return readStringOrIndirection(false); } @@ -1045,7 +994,7 @@ public class CDRInputStream_1_0 extends CDRInputStreamBase try { if (valueHandler == null) - valueHandler = ORBUtility.createValueHandler(orb); + valueHandler = ORBUtility.createValueHandler(); value = valueHandler.readValue(parent, indirection, diff --git a/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDROutputStream_1_0.java b/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDROutputStream_1_0.java index 25e15286978..3e60c4801b0 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDROutputStream_1_0.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDROutputStream_1_0.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -189,18 +189,8 @@ public class CDROutputStream_1_0 extends CDROutputStreamBase private final void createRepositoryIdHandlers() { - if (orb != null) { - // Get the appropriate versions based on the ORB version. The - // ORB versioning info is only in the core ORB. - repIdUtil - = RepositoryIdFactory.getRepIdUtility(orb); - repIdStrs - = RepositoryIdFactory.getRepIdStringsFactory(orb); - } else { - // Get the latest versions - repIdUtil = RepositoryIdFactory.getRepIdUtility(); - repIdStrs = RepositoryIdFactory.getRepIdStringsFactory(); - } + repIdUtil = RepositoryIdFactory.getRepIdUtility(); + repIdStrs = RepositoryIdFactory.getRepIdStringsFactory(); } public BufferManagerWrite getBufferManager() @@ -705,7 +695,7 @@ public class CDROutputStream_1_0 extends CDROutputStreamBase private void writeArray(Serializable array, Class clazz) { if (valueHandler == null) - valueHandler = ORBUtility.createValueHandler(orb); //d11638 + valueHandler = ORBUtility.createValueHandler(); //d11638 // Write value_tag int indirection = writeValueTag(mustChunk, true, @@ -768,7 +758,7 @@ public class CDROutputStream_1_0 extends CDROutputStreamBase private void writeRMIIIOPValueType(Serializable object, Class clazz) { if (valueHandler == null) - valueHandler = ORBUtility.createValueHandler(orb); //d11638 + valueHandler = ORBUtility.createValueHandler(); //d11638 Serializable key = object; diff --git a/corba/src/share/classes/com/sun/corba/se/impl/io/FVDCodeBaseImpl.java b/corba/src/share/classes/com/sun/corba/se/impl/io/FVDCodeBaseImpl.java index f87ef71d45d..c69fb42421b 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/io/FVDCodeBaseImpl.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/io/FVDCodeBaseImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,7 +86,7 @@ public class FVDCodeBaseImpl extends _CodeBaseImplBase // default to using the current ORB version in case the // vhandler is not set if (vhandler == null) { - vhandler = new ValueHandlerImpl(false); + vhandler = ValueHandlerImpl.getInstance(false); } // Util.getCodebase may return null which would @@ -120,7 +120,7 @@ public class FVDCodeBaseImpl extends _CodeBaseImplBase // default to using the current ORB version in case the // vhandler is not set if (vhandler == null) { - vhandler = new ValueHandlerImpl(false); + vhandler = ValueHandlerImpl.getInstance(false); } try{ @@ -161,7 +161,7 @@ public class FVDCodeBaseImpl extends _CodeBaseImplBase // default to using the current ORB version in case the // vhandler is not set if (vhandler == null) { - vhandler = new ValueHandlerImpl(false); + vhandler = ValueHandlerImpl.getInstance(false); } Stack repIds = new Stack(); diff --git a/corba/src/share/classes/com/sun/corba/se/impl/io/ValueHandlerImpl.java b/corba/src/share/classes/com/sun/corba/se/impl/io/ValueHandlerImpl.java index e1c82cf9bfc..fdf35018275 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/io/ValueHandlerImpl.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/io/ValueHandlerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -53,7 +53,7 @@ import com.sun.corba.se.spi.logging.CORBALogDomains; import com.sun.corba.se.impl.logging.OMGSystemException; import com.sun.corba.se.impl.logging.UtilSystemException; -public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat { +public final class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat { // Property to override our maximum stream format version public static final String FORMAT_VERSION_PROPERTY @@ -150,14 +150,22 @@ public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat writeValueWithVersion(out, value, streamFormatVersion); } - public ValueHandlerImpl(){} + private ValueHandlerImpl(){} - public ValueHandlerImpl(boolean isInputStream) { + private ValueHandlerImpl(boolean isInputStream) { this(); useHashtables = false; this.isInputStream = isInputStream; } + static ValueHandlerImpl getInstance() { + return new ValueHandlerImpl(); + } + + static ValueHandlerImpl getInstance(boolean isInputStream) { + return new ValueHandlerImpl(isInputStream); + } + /** * Writes the value to the stream using java semantics. * @param out The stream to write the value to @@ -458,12 +466,7 @@ public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat return ObjectStreamClass.lookup(value.getClass()).writeReplace(value); } - /** - * Encapsulates writing of Java char arrays so that the 1.3 subclass - * can override it without exposing internals across packages. This - * is a fix for bug 4367783. - */ - protected void writeCharArray(org.omg.CORBA_2_3.portable.OutputStream out, + private void writeCharArray(org.omg.CORBA_2_3.portable.OutputStream out, char[] array, int offset, int length) @@ -576,12 +579,7 @@ public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat } } - /** - * Encapsulates reading of Java char arrays so that the 1.3 subclass - * can override it without exposing internals across packages. This - * is a fix for bug 4367783. - */ - protected void readCharArray(org.omg.CORBA_2_3.portable.InputStream in, + private void readCharArray(org.omg.CORBA_2_3.portable.InputStream in, char[] array, int offset, int length) @@ -795,7 +793,7 @@ public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat return RepositoryId.cache.getId(repId).isSequence(); } - protected String getOutputStreamClassName() { + private String getOutputStreamClassName() { return "com.sun.corba.se.impl.io.IIOPOutputStream"; } @@ -843,29 +841,11 @@ public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat private IIOPOutputStream createOutputStreamBuiltInNoPriv( final String name ) throws IOException { - return - name.equals( - IIOPOutputStream - .class.getName() - ) ? - new IIOPOutputStream() : - - name.equals( - com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3 - .class.getName() - ) ? - new com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3() : - - name.equals( - com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3_1 - .class.getName() - ) ? - new com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3_1() : - - null; + return name.equals(IIOPOutputStream.class.getName()) ? + new IIOPOutputStream() : null; } - protected String getInputStreamClassName() { + private String getInputStreamClassName() { return "com.sun.corba.se.impl.io.IIOPInputStream"; } @@ -913,26 +893,8 @@ public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat private IIOPInputStream createInputStreamBuiltInNoPriv( final String name ) throws IOException { - return - name.equals( - IIOPInputStream - .class.getName() - ) ? - new IIOPInputStream() : - - name.equals( - com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3 - .class.getName() - ) ? - new com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3() : - - name.equals( - com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3_1 - .class.getName() - ) ? - new com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3_1() : - - null; + return name.equals(IIOPInputStream.class.getName()) ? + new IIOPInputStream() : null; } /** @@ -958,12 +920,7 @@ public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat } - /** - * Our JDK 1.3 and JDK 1.3.1 behavior subclasses override this. - * The correct behavior is for a Java char to map to a CORBA wchar, - * but our older code mapped it to a CORBA char. - */ - protected TCKind getJavaCharTCKind() { + TCKind getJavaCharTCKind() { return TCKind.tk_wchar; } } diff --git a/corba/src/share/classes/com/sun/corba/se/impl/io/ValueUtility.java b/corba/src/share/classes/com/sun/corba/se/impl/io/ValueUtility.java index 84bb1685515..41d85a265fc 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/io/ValueUtility.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/io/ValueUtility.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -93,6 +93,14 @@ public class ValueUtility { null, // tk_abstract_interface 32 }; + static { + sun.corba.SharedSecrets.setJavaCorbaAccess(new sun.corba.JavaCorbaAccess() { + public ValueHandlerImpl newValueHandlerImpl() { + return ValueHandlerImpl.getInstance(); + } + }); + } + public static String getSignature(ValueMember member) throws ClassNotFoundException { diff --git a/corba/src/share/classes/com/sun/corba/se/impl/javax/rmi/CORBA/Util.java b/corba/src/share/classes/com/sun/corba/se/impl/javax/rmi/CORBA/Util.java index 7721999591c..aa2c6483804 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/javax/rmi/CORBA/Util.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/javax/rmi/CORBA/Util.java @@ -112,6 +112,9 @@ import com.sun.corba.se.impl.util.JDKBridge; import com.sun.corba.se.impl.orbutil.ORBClassLoader; import com.sun.corba.se.impl.logging.UtilSystemException; import com.sun.corba.se.spi.logging.CORBALogDomains; +import sun.corba.SharedSecrets; +import sun.corba.JavaCorbaAccess; + /** * Provides utility methods that can be used by stubs and ties to @@ -125,7 +128,8 @@ public class Util implements javax.rmi.CORBA.UtilDelegate // Maps targets to ties. private static IdentityHashtable exportedServants = new IdentityHashtable(); - private static ValueHandlerImpl valueHandlerSingleton = new ValueHandlerImpl(); + private static final ValueHandlerImpl valueHandlerSingleton = + SharedSecrets.getJavaCorbaAccess().newValueHandlerImpl(); private UtilSystemException utilWrapper = UtilSystemException.get( CORBALogDomains.RPC_ENCODING); diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orb/ORBImpl.java b/corba/src/share/classes/com/sun/corba/se/impl/orb/ORBImpl.java index 9c03173238b..5db85734a95 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/orb/ORBImpl.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/orb/ORBImpl.java @@ -840,7 +840,7 @@ public class ORBImpl extends com.sun.corba.se.spi.orb.ORB // backward compatability 4365188 CodeBase cb; - ValueHandler vh = ORBUtility.createValueHandler(this); + ValueHandler vh = ORBUtility.createValueHandler(); cb = (CodeBase)vh.getRunTimeCodeBase(); return ORBUtility.connectAndGetIOR( this, cb ) ; diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPInputStream_1_3.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPInputStream_1_3.java deleted file mode 100644 index 235d7343c9b..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPInputStream_1_3.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2000, 2002, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.corba.se.impl.orbutil; - -import java.io.*; -import java.util.Hashtable; - -/** - * Implements legacy behavior from before Ladybird to maintain - * backwards compatibility. - */ -public class IIOPInputStream_1_3 extends com.sun.corba.se.impl.io.IIOPInputStream -{ - // The newer version in the io package correctly reads a wstring instead. - // This concerns bug 4379597. - protected String internalReadUTF(org.omg.CORBA.portable.InputStream stream) - { - return stream.read_string(); - } - - /** - * Before JDK 1.3.1_01, the PutField/GetField implementation - * actually sent a Hashtable. - */ - public ObjectInputStream.GetField readFields() - throws IOException, ClassNotFoundException, NotActiveException { - Hashtable fields = (Hashtable)readObject(); - return new LegacyHookGetFields(fields); - } - - public IIOPInputStream_1_3() - throws java.io.IOException { - super(); - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPOutputStream_1_3.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPOutputStream_1_3.java deleted file mode 100644 index e9d81cdd254..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPOutputStream_1_3.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2000, 2002, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.corba.se.impl.orbutil; - -import java.io.*; - -/** - * Implements legacy behavior from before Ladybird to maintain - * backwards compatibility. - */ -public class IIOPOutputStream_1_3 extends com.sun.corba.se.impl.io.IIOPOutputStream -{ - // We can't assume that the superclass's putFields - // member will be non-private. We must allow - // the RI to run on JDK 1.3.1 FCS as well as - // the JDK 1.3.1_01 patch. - private ObjectOutputStream.PutField putFields_1_3; - - // The newer version in the io package correctly writes a wstring instead. - // This concerns bug 4379597. - protected void internalWriteUTF(org.omg.CORBA.portable.OutputStream stream, - String data) - { - stream.write_string(data); - } - - public IIOPOutputStream_1_3() - throws java.io.IOException { - super(); - } - - /** - * Before JDK 1.3.1_01, the PutField/GetField implementation - * actually sent a Hashtable. - */ - public ObjectOutputStream.PutField putFields() - throws IOException { - putFields_1_3 = new LegacyHookPutFields(); - return putFields_1_3; - } - - public void writeFields() - throws IOException { - putFields_1_3.write(this); - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPOutputStream_1_3_1.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPOutputStream_1_3_1.java deleted file mode 100644 index 6c7bfd46fd0..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPOutputStream_1_3_1.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2001, 2002, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - */ -package com.sun.corba.se.impl.orbutil; - -import java.io.*; -import java.util.Hashtable; - -/** - * Implements legacy behavior from Ladybird to maintain - * backwards compatibility. - */ -public class IIOPOutputStream_1_3_1 extends com.sun.corba.se.impl.io.IIOPOutputStream -{ - // We can't assume that the superclass's putFields - // member will be non-private. We must allow - // the RI to run on JDK 1.3.1 FCS as well as - // the JDK 1.3.1_01 patch. - private ObjectOutputStream.PutField putFields_1_3_1; - - public IIOPOutputStream_1_3_1() - throws java.io.IOException { - super(); - } - - /** - * Before JDK 1.3.1_01, the PutField/GetField implementation - * actually sent a Hashtable. - */ - public ObjectOutputStream.PutField putFields() - throws IOException { - - putFields_1_3_1 = new LegacyHookPutFields(); - return putFields_1_3_1; - } - - public void writeFields() - throws IOException { - - putFields_1_3_1.write(this); - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ORBUtility.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ORBUtility.java index b4cc902ee7a..23d51f9008a 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ORBUtility.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ORBUtility.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -160,44 +160,12 @@ public final class ORBUtility { } /** - * Creates the correct ValueHandler for the given ORB, - * querying ORBVersion information. If the ORB or - * ORBVersion is null, gets the ValueHandler from - * Util.createValueHandler. + * Return default ValueHandler */ - public static ValueHandler createValueHandler(ORB orb) { - - if (orb == null) - return Util.createValueHandler(); - - ORBVersion version = orb.getORBVersion(); - - if (version == null) - return Util.createValueHandler(); - - if (version.equals(ORBVersionFactory.getOLD())) - return new ValueHandlerImpl_1_3(); - if (version.equals(ORBVersionFactory.getNEW())) - return new ValueHandlerImpl_1_3_1(); - + public static ValueHandler createValueHandler() { return Util.createValueHandler(); } - /** - * Returns true if the given ORB could accurately be determined to be a - * Kestrel or earlier ORB. Note: If passed the ORBSingleton, this will return - * false. - */ - public static boolean isLegacyORB(ORB orb) - { - try { - ORBVersion currentORB = orb.getORBVersion(); - return currentORB.equals( ORBVersionFactory.getOLD() ) ; - } catch (SecurityException se) { - return false; - } - } - /** * Returns true if it was accurately determined that the remote ORB is * a foreign (non-JavaSoft) ORB. Note: If passed the ORBSingleton, this diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3.java deleted file mode 100644 index c4e218304cb..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2000, 2004, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.corba.se.impl.orbutil; - -import org.omg.CORBA.ORB; -import java.io.Serializable; -import java.util.Hashtable; -import java.net.MalformedURLException; -import com.sun.corba.se.impl.io.TypeMismatchException; -import com.sun.corba.se.impl.util.RepositoryId; - -/** - * Delegates to the RepositoryId_1_3 implementation in - * com.sun.corba.se.impl.orbutil. This is necessary to - * overcome the fact that many of RepositoryId's methods - * are static. - */ -public final class RepIdDelegator_1_3 - implements RepositoryIdStrings, - RepositoryIdUtility, - RepositoryIdInterface -{ - // RepositoryIdFactory methods - - public String createForAnyType(Class type) { - return RepositoryId_1_3.createForAnyType(type); - } - - public String createForJavaType(Serializable ser) - throws TypeMismatchException - { - return RepositoryId_1_3.createForJavaType(ser); - } - - public String createForJavaType(Class clz) - throws TypeMismatchException - { - return RepositoryId_1_3.createForJavaType(clz); - } - - public String createSequenceRepID(java.lang.Object ser) { - return RepositoryId_1_3.createSequenceRepID(ser); - } - - public String createSequenceRepID(Class clazz) { - return RepositoryId_1_3.createSequenceRepID(clazz); - } - - public RepositoryIdInterface getFromString(String repIdString) { - return new RepIdDelegator_1_3(RepositoryId_1_3.cache.getId(repIdString)); - } - - // RepositoryIdUtility methods - - public boolean isChunkedEncoding(int valueTag) { - return RepositoryId.isChunkedEncoding(valueTag); - } - - public boolean isCodeBasePresent(int valueTag) { - return RepositoryId.isCodeBasePresent(valueTag); - } - - public String getClassDescValueRepId() { - return RepositoryId_1_3.kClassDescValueRepID; - } - - public String getWStringValueRepId() { - return RepositoryId_1_3.kWStringValueRepID; - } - - public int getTypeInfo(int valueTag) { - return RepositoryId.getTypeInfo(valueTag); - } - - public int getStandardRMIChunkedNoRepStrId() { - return RepositoryId.kPreComputed_StandardRMIChunked_NoRep; - } - - public int getCodeBaseRMIChunkedNoRepStrId() { - return RepositoryId.kPreComputed_CodeBaseRMIChunked_NoRep; - } - - public int getStandardRMIChunkedId() { - return RepositoryId.kPreComputed_StandardRMIChunked; - } - - public int getCodeBaseRMIChunkedId() { - return RepositoryId.kPreComputed_CodeBaseRMIChunked; - } - - public int getStandardRMIUnchunkedId() { - return RepositoryId.kPreComputed_StandardRMIUnchunked; - } - - public int getCodeBaseRMIUnchunkedId() { - return RepositoryId.kPreComputed_CodeBaseRMIUnchunked; - } - - public int getStandardRMIUnchunkedNoRepStrId() { - return RepositoryId.kPreComputed_StandardRMIUnchunked_NoRep; - } - - public int getCodeBaseRMIUnchunkedNoRepStrId() { - return RepositoryId.kPreComputed_CodeBaseRMIUnchunked_NoRep; - } - - // RepositoryIdInterface methods - - public Class getClassFromType() throws ClassNotFoundException { - return delegate.getClassFromType(); - } - - public Class getClassFromType(String codebaseURL) - throws ClassNotFoundException, MalformedURLException - { - return delegate.getClassFromType(codebaseURL); - } - - public Class getClassFromType(Class expectedType, - String codebaseURL) - throws ClassNotFoundException, MalformedURLException - { - return delegate.getClassFromType(expectedType, codebaseURL); - } - - public String getClassName() { - return delegate.getClassName(); - } - - // Constructor used for factory/utility cases - public RepIdDelegator_1_3() {} - - // Constructor used by getIdFromString. All non-static - // RepositoryId methods will use the provided delegate. - private RepIdDelegator_1_3(RepositoryId_1_3 _delegate) { - this.delegate = _delegate; - } - - private RepositoryId_1_3 delegate = null; - - public String toString() { - if (delegate != null) - return delegate.toString(); - else - return this.getClass().getName(); - } - - public boolean equals(Object obj) { - if (delegate != null) - return delegate.equals(obj); - else - return super.equals(obj); - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3_1.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3_1.java deleted file mode 100644 index dc1195fa073..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3_1.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2001, 2004, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.corba.se.impl.orbutil; - -import org.omg.CORBA.ORB; -import java.io.Serializable; -import java.util.Hashtable; -import java.net.MalformedURLException; -import com.sun.corba.se.impl.io.TypeMismatchException; -import com.sun.corba.se.impl.util.RepositoryId; - -/** - * Delegates to the RepositoryId_1_3_1 implementation in - * com.sun.corba.se.impl.orbutil. This is necessary to - * overcome the fact that many of RepositoryId's methods - * are static. - */ -public final class RepIdDelegator_1_3_1 - implements RepositoryIdStrings, - RepositoryIdUtility, - RepositoryIdInterface -{ - // RepositoryIdFactory methods - - public String createForAnyType(Class type) { - return RepositoryId_1_3_1.createForAnyType(type); - } - - public String createForJavaType(Serializable ser) - throws TypeMismatchException - { - return RepositoryId_1_3_1.createForJavaType(ser); - } - - public String createForJavaType(Class clz) - throws TypeMismatchException - { - return RepositoryId_1_3_1.createForJavaType(clz); - } - - public String createSequenceRepID(java.lang.Object ser) { - return RepositoryId_1_3_1.createSequenceRepID(ser); - } - - public String createSequenceRepID(Class clazz) { - return RepositoryId_1_3_1.createSequenceRepID(clazz); - } - - public RepositoryIdInterface getFromString(String repIdString) { - return new RepIdDelegator_1_3_1(RepositoryId_1_3_1.cache.getId(repIdString)); - } - - // RepositoryIdUtility methods - - public boolean isChunkedEncoding(int valueTag) { - return RepositoryId.isChunkedEncoding(valueTag); - } - - public boolean isCodeBasePresent(int valueTag) { - return RepositoryId.isCodeBasePresent(valueTag); - } - - public String getClassDescValueRepId() { - return RepositoryId_1_3_1.kClassDescValueRepID; - } - - public String getWStringValueRepId() { - return RepositoryId_1_3_1.kWStringValueRepID; - } - - public int getTypeInfo(int valueTag) { - return RepositoryId.getTypeInfo(valueTag); - } - - public int getStandardRMIChunkedNoRepStrId() { - return RepositoryId.kPreComputed_StandardRMIChunked_NoRep; - } - - public int getCodeBaseRMIChunkedNoRepStrId() { - return RepositoryId.kPreComputed_CodeBaseRMIChunked_NoRep; - } - - public int getStandardRMIChunkedId() { - return RepositoryId.kPreComputed_StandardRMIChunked; - } - - public int getCodeBaseRMIChunkedId() { - return RepositoryId.kPreComputed_CodeBaseRMIChunked; - } - - public int getStandardRMIUnchunkedId() { - return RepositoryId.kPreComputed_StandardRMIUnchunked; - } - - public int getCodeBaseRMIUnchunkedId() { - return RepositoryId.kPreComputed_CodeBaseRMIUnchunked; - } - - public int getStandardRMIUnchunkedNoRepStrId() { - return RepositoryId.kPreComputed_StandardRMIUnchunked_NoRep; - } - - public int getCodeBaseRMIUnchunkedNoRepStrId() { - return RepositoryId.kPreComputed_CodeBaseRMIUnchunked_NoRep; - } - - // RepositoryIdInterface methods - - public Class getClassFromType() throws ClassNotFoundException { - return delegate.getClassFromType(); - } - - public Class getClassFromType(String codebaseURL) - throws ClassNotFoundException, MalformedURLException - { - return delegate.getClassFromType(codebaseURL); - } - - public Class getClassFromType(Class expectedType, - String codebaseURL) - throws ClassNotFoundException, MalformedURLException - { - return delegate.getClassFromType(expectedType, codebaseURL); - } - - public String getClassName() { - return delegate.getClassName(); - } - - // Constructor used for factory/utility cases - public RepIdDelegator_1_3_1() {} - - // Constructor used by getIdFromString. All non-static - // RepositoryId methods will use the provided delegate. - private RepIdDelegator_1_3_1(RepositoryId_1_3_1 _delegate) { - this.delegate = _delegate; - } - - private RepositoryId_1_3_1 delegate = null; - - public String toString() { - if (delegate != null) - return delegate.toString(); - else - return this.getClass().getName(); - } - - public boolean equals(Object obj) { - if (delegate != null) - return delegate.equals(obj); - else - return super.equals(obj); - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3.java deleted file mode 100644 index 3a35b33a645..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2000, 2002, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -/* - * Licensed Materials - Property of IBM - * RMI-IIOP v1.0 - * Copyright IBM Corp. 1998 1999 All Rights Reserved - * - */ - -package com.sun.corba.se.impl.orbutil; - -import java.util.Stack; -import java.util.Hashtable; -import java.util.EmptyStackException; -import java.util.Enumeration; - -// Really limited pool - in this case just creating several at a time... -class RepositoryIdPool_1_3 extends Stack { - - private static int MAX_CACHE_SIZE = 4; - private RepositoryIdCache_1_3 cache; - - public final synchronized RepositoryId_1_3 popId() { - - try { - return (RepositoryId_1_3)super.pop(); - } - catch(EmptyStackException e) { - increasePool(5); - return (RepositoryId_1_3)super.pop(); - } - - } - - // Pool management - final void increasePool(int size) { - //if (cache.size() <= MAX_CACHE_SIZE) - for (int i = size; i > 0; i--) - push(new RepositoryId_1_3()); - /* - // _REVISIT_ This will not work w/out either thread tracing or weak references. I am - // betting that thread tracing almost completely negates benefit of reuse. Until either - // 1.2 only inclusion or proof to the contrary, I'll leave it this way... - else { - int numToReclaim = cache.size() / 2; - Enumeration keys = cache.keys(); - Enumeration elements = cache.elements(); - for (int i = numToReclaim; i > 0; i--) { - Object key = keys.nextElement(); - Object element = elements.nextElement(); - - push(element); - cache.remove(key); - } - } - */ - } - - final void setCaches(RepositoryIdCache_1_3 cache) { - this.cache = cache; - } - -} - -public class RepositoryIdCache_1_3 extends Hashtable { - - private RepositoryIdPool_1_3 pool = new RepositoryIdPool_1_3(); - - public RepositoryIdCache_1_3() { - pool.setCaches(this); - } - - public final synchronized RepositoryId_1_3 getId(String key) { - RepositoryId_1_3 repId = (RepositoryId_1_3)super.get(key); - - if (repId != null) - return repId; - else { - //repId = pool.popId().init(key); - repId = new RepositoryId_1_3(key); - put(key, repId); - return repId; - } - - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3_1.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3_1.java deleted file mode 100644 index 11acc5b522a..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3_1.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2001, 2002, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.corba.se.impl.orbutil; - -import java.util.Stack; -import java.util.Hashtable; -import java.util.EmptyStackException; -import java.util.Enumeration; - -// Really limited pool - in this case just creating several at a time... -class RepositoryIdPool_1_3_1 extends Stack { - - private static int MAX_CACHE_SIZE = 4; - private RepositoryIdCache_1_3_1 cache; - - public final synchronized RepositoryId_1_3_1 popId() { - - try { - return (RepositoryId_1_3_1)super.pop(); - } - catch(EmptyStackException e) { - increasePool(5); - return (RepositoryId_1_3_1)super.pop(); - } - - } - - // Pool management - final void increasePool(int size) { - //if (cache.size() <= MAX_CACHE_SIZE) - for (int i = size; i > 0; i--) - push(new RepositoryId_1_3_1()); - /* - // _REVISIT_ This will not work w/out either thread tracing or weak references. I am - // betting that thread tracing almost completely negates benefit of reuse. Until either - // 1.2 only inclusion or proof to the contrary, I'll leave it this way... - else { - int numToReclaim = cache.size() / 2; - Enumeration keys = cache.keys(); - Enumeration elements = cache.elements(); - for (int i = numToReclaim; i > 0; i--) { - Object key = keys.nextElement(); - Object element = elements.nextElement(); - - push(element); - cache.remove(key); - } - } - */ - } - - final void setCaches(RepositoryIdCache_1_3_1 cache) { - this.cache = cache; - } - -} - -public class RepositoryIdCache_1_3_1 extends Hashtable { - - private RepositoryIdPool_1_3_1 pool = new RepositoryIdPool_1_3_1(); - - public RepositoryIdCache_1_3_1() { - pool.setCaches(this); - } - - public final synchronized RepositoryId_1_3_1 getId(String key) { - RepositoryId_1_3_1 repId = (RepositoryId_1_3_1)super.get(key); - - if (repId != null) - return repId; - else { - //repId = pool.popId().init(key); - repId = new RepositoryId_1_3_1(key); - put(key, repId); - return repId; - } - - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdFactory.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdFactory.java index 35014680527..5f3a237e995 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdFactory.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -30,12 +30,6 @@ import com.sun.corba.se.spi.orb.ORB; public abstract class RepositoryIdFactory { - private static final RepIdDelegator_1_3 legacyDelegator - = new RepIdDelegator_1_3(); - - private static final RepIdDelegator_1_3_1 ladybirdDelegator - = new RepIdDelegator_1_3_1(); - private static final RepIdDelegator currentDelegator = new RepIdDelegator(); @@ -47,29 +41,6 @@ public abstract class RepositoryIdFactory return currentDelegator; } - /** - * Checks the version of the ORB and returns the appropriate - * RepositoryIdStrings instance. - */ - public static RepositoryIdStrings getRepIdStringsFactory(ORB orb) - { - if (orb != null) { - switch (orb.getORBVersion().getORBType()) { - case ORBVersion.NEWER: - case ORBVersion.FOREIGN: - case ORBVersion.JDK1_3_1_01: - return currentDelegator; - case ORBVersion.OLD: - return legacyDelegator; - case ORBVersion.NEW: - return ladybirdDelegator; - default: - return currentDelegator; - } - } else - return currentDelegator; - } - /** * Returns the latest version RepositoryIdUtility instance */ @@ -78,26 +49,4 @@ public abstract class RepositoryIdFactory return currentDelegator; } - /** - * Checks the version of the ORB and returns the appropriate - * RepositoryIdUtility instance. - */ - public static RepositoryIdUtility getRepIdUtility(ORB orb) - { - if (orb != null) { - switch (orb.getORBVersion().getORBType()) { - case ORBVersion.NEWER: - case ORBVersion.FOREIGN: - case ORBVersion.JDK1_3_1_01: - return currentDelegator; - case ORBVersion.OLD: - return legacyDelegator; - case ORBVersion.NEW: - return ladybirdDelegator; - default: - return currentDelegator; - } - } else - return currentDelegator; - } } diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryId_1_3.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryId_1_3.java deleted file mode 100644 index 8cf9edd4834..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryId_1_3.java +++ /dev/null @@ -1,990 +0,0 @@ -/* - * Copyright (c) 2000, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -/* - * Licensed Materials - Property of IBM - * RMI-IIOP v1.0 - * Copyright IBM Corp. 1998 1999 All Rights Reserved - * - */ - -package com.sun.corba.se.impl.orbutil; - -import java.util.StringTokenizer; -import java.util.Hashtable; -import java.io.IOException; -import java.lang.reflect.Method; - -// Imports for using codebase URL to load class -import java.net.MalformedURLException; -import org.omg.CORBA.portable.ValueBase; -import org.omg.CORBA.portable.IDLEntity; - -import com.sun.corba.se.impl.util.JDKBridge; -import com.sun.corba.se.impl.util.Utility; -import com.sun.corba.se.impl.util.PackagePrefixChecker; -import com.sun.corba.se.impl.util.IdentityHashtable; -import com.sun.corba.se.impl.io.ObjectStreamClass; - -import javax.rmi.CORBA.Util; - -// keeping the original RepositoryId class that was shipped in -// JDK 1.3. It has interoperability bugs - -public class RepositoryId_1_3 { - - // Legal IDL Identifier characters (1 = legal). Note - // that '.' (2E) is marked as legal even though it is - // not legal in IDL. This allows us to treat a fully - // qualified Java name with '.' package separators - // uniformly, and is safe because that is the only - // legal use of '.' in a Java name. - - public static final RepositoryIdCache_1_3 cache = new RepositoryIdCache_1_3(); - private static final byte[] IDL_IDENTIFIER_CHARS = { - - // 0 1 2 3 4 5 6 7 8 9 a b c d e f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 00-0f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 10-1f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,1,0, // 20-2f - 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0, // 30-3f - 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // 40-4f - 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, // 50-5f - 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // 60-6f - 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0, // 70-7f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 80-8f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 90-9f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // a0-af - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // b0-bf - 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // c0-cf - 0,1,1,1, 1,1,1,0, 1,1,1,1, 1,0,0,1, // d0-df - 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // e0-ef - 0,1,1,1, 1,1,1,0, 1,1,1,1, 1,0,0,1, // f0-ff - }; - - private static String defaultServerURL = null; - private static boolean useCodebaseOnly = false; - - static { - if (defaultServerURL == null) - defaultServerURL = (String)JDKBridge.getLocalCodebase(); - useCodebaseOnly = JDKBridge.useCodebaseOnly(); - - } - - private static IdentityHashtable classToRepStr = new IdentityHashtable(); - private static IdentityHashtable classIDLToRepStr = new IdentityHashtable(); - private static IdentityHashtable classSeqToRepStr = new IdentityHashtable(); - - private static IdentityHashtable repStrToByteArray = new IdentityHashtable(); - private static Hashtable repStrToClass = new Hashtable(); - - private String repId = null; - private boolean isSupportedFormat = true; - private String typeString = null; - private String versionString = null; - private boolean isSequence = false; - private boolean isRMIValueType = false; - private boolean isIDLType = false; - private String completeClassName = null; - private String unqualifiedName = null; - private String definedInId = null; - private Class clazz = null; - private String suid = null, actualSuid = null; - private long suidLong = ObjectStreamClass.kDefaultUID, actualSuidLong = ObjectStreamClass.kDefaultUID; - - // Repository ID fragments - private static final String kValuePrefix = "RMI:"; - private static final String kIDLPrefix = "IDL:"; - private static final String kIDLNamePrefix = "omg.org/"; - private static final String kIDLClassnamePrefix = "org.omg."; - private static final String kSequencePrefix = "["; - private static final String kCORBAPrefix = "CORBA/"; - private static final String kArrayPrefix = kValuePrefix + kSequencePrefix + kCORBAPrefix; - private static final int kValuePrefixLength = kValuePrefix.length(); - private static final int kIDLPrefixLength = kIDLPrefix.length(); - private static final int kSequencePrefixLength = kSequencePrefix.length(); - private static final String kInterfaceHashCode = ":0000000000000000"; - private static final String kInterfaceOnlyHashStr = "0000000000000000"; - private static final String kExternalizableHashStr = "0000000000000001"; - - // Value tag utility methods and constants - public static final int kInitialValueTag= 0x7fffff00; - public static final int kNoTypeInfo = 0; - public static final int kSingleRepTypeInfo = 0x02; - public static final int kPartialListTypeInfo = 0x06; - public static final int kChunkedMask = 0x08; - - // Public, well known repository IDs - - // _REVISIT_ : A table structure with a good search routine for all of this - // would be more efficient and easier to maintain... - - // String - public static final String kWStringValueVersion = "1.0"; - public static final String kWStringValueHash = ":"+kWStringValueVersion; - public static final String kWStringStubValue = "WStringValue"; - public static final String kWStringTypeStr = "omg.org/CORBA/"+kWStringStubValue; - public static final String kWStringValueRepID = kIDLPrefix + kWStringTypeStr + kWStringValueHash; - - // Any - public static final String kAnyRepID = kIDLPrefix + "omg.org/CORBA/Any"; - - // Class - public static final String kClassDescValueHash = ":" + Long.toHexString( - ObjectStreamClass.getSerialVersionUID(javax.rmi.CORBA.ClassDesc.class)); - public static final String kClassDescStubValue = "ClassDesc"; - public static final String kClassDescTypeStr = "javax.rmi.CORBA."+kClassDescStubValue; - public static final String kClassDescValueRepID = kValuePrefix + kClassDescTypeStr + kClassDescValueHash; - - // Object - public static final String kObjectValueHash = ":1.0"; - public static final String kObjectStubValue = "Object"; - - // Sequence - public static final String kSequenceValueHash = ":1.0"; - public static final String kPrimitiveSequenceValueHash = ":0000000000000000"; - - // Serializable - public static final String kSerializableValueHash = ":1.0"; - public static final String kSerializableStubValue = "Serializable"; - - // Externalizable - public static final String kExternalizableValueHash = ":1.0"; - public static final String kExternalizableStubValue = "Externalizable"; - - // Remote (The empty string is used for java.rmi.Remote) - public static final String kRemoteValueHash = ""; - public static final String kRemoteStubValue = ""; - public static final String kRemoteTypeStr = ""; - public static final String kRemoteValueRepID = ""; - - private static final Hashtable kSpecialArrayTypeStrings = new Hashtable(); - - static { - kSpecialArrayTypeStrings.put("CORBA.WStringValue", new StringBuffer(java.lang.String.class.getName())); - kSpecialArrayTypeStrings.put("javax.rmi.CORBA.ClassDesc", new StringBuffer(java.lang.Class.class.getName())); - kSpecialArrayTypeStrings.put("CORBA.Object", new StringBuffer(java.rmi.Remote.class.getName())); - - } - - private static final Hashtable kSpecialCasesRepIDs = new Hashtable(); - - static { - kSpecialCasesRepIDs.put(java.lang.String.class, kWStringValueRepID); - kSpecialCasesRepIDs.put(java.lang.Class.class, kClassDescValueRepID); - kSpecialCasesRepIDs.put(java.rmi.Remote.class, kRemoteValueRepID); - } - - private static final Hashtable kSpecialCasesStubValues = new Hashtable(); - - static { - kSpecialCasesStubValues.put(java.lang.String.class, kWStringStubValue); - kSpecialCasesStubValues.put(java.lang.Class.class, kClassDescStubValue); - kSpecialCasesStubValues.put(java.lang.Object.class, kObjectStubValue); - kSpecialCasesStubValues.put(java.io.Serializable.class, kSerializableStubValue); - kSpecialCasesStubValues.put(java.io.Externalizable.class, kExternalizableStubValue); - kSpecialCasesStubValues.put(java.rmi.Remote.class, kRemoteStubValue); - } - - - private static final Hashtable kSpecialCasesVersions = new Hashtable(); - - static { - kSpecialCasesVersions.put(java.lang.String.class, kWStringValueHash); - kSpecialCasesVersions.put(java.lang.Class.class, kClassDescValueHash); - kSpecialCasesVersions.put(java.lang.Object.class, kObjectValueHash); - kSpecialCasesVersions.put(java.io.Serializable.class, kSerializableValueHash); - kSpecialCasesVersions.put(java.io.Externalizable.class, kExternalizableValueHash); - kSpecialCasesVersions.put(java.rmi.Remote.class, kRemoteValueHash); - } - - private static final Hashtable kSpecialCasesClasses = new Hashtable(); - - static { - kSpecialCasesClasses.put(kWStringTypeStr, java.lang.String.class); - kSpecialCasesClasses.put(kClassDescTypeStr, java.lang.Class.class); - kSpecialCasesClasses.put(kRemoteTypeStr, java.rmi.Remote.class); - - kSpecialCasesClasses.put("org.omg.CORBA.WStringValue", java.lang.String.class); - kSpecialCasesClasses.put("javax.rmi.CORBA.ClassDesc", java.lang.Class.class); - //kSpecialCasesClasses.put(kRemoteTypeStr, java.rmi.Remote.class); - } - - private static final Hashtable kSpecialCasesArrayPrefix = new Hashtable(); - - static { - kSpecialCasesArrayPrefix.put(java.lang.String.class, kValuePrefix + kSequencePrefix + kCORBAPrefix); - kSpecialCasesArrayPrefix.put(java.lang.Class.class, kValuePrefix + kSequencePrefix + "javax/rmi/CORBA/"); - kSpecialCasesArrayPrefix.put(java.lang.Object.class, kValuePrefix + kSequencePrefix + "java/lang/"); - kSpecialCasesArrayPrefix.put(java.io.Serializable.class, kValuePrefix + kSequencePrefix + "java/io/"); - kSpecialCasesArrayPrefix.put(java.io.Externalizable.class, kValuePrefix + kSequencePrefix + "java/io/"); - kSpecialCasesArrayPrefix.put(java.rmi.Remote.class, kValuePrefix + kSequencePrefix + kCORBAPrefix); - } - - private static final Hashtable kSpecialPrimitives = new Hashtable(); - - static { - kSpecialPrimitives.put("int","long"); - kSpecialPrimitives.put("long","longlong"); - kSpecialPrimitives.put("byte","octet"); - } - - /** - * Used to convert ascii to hex. - */ - private static final byte ASCII_HEX[] = { - (byte)'0', - (byte)'1', - (byte)'2', - (byte)'3', - (byte)'4', - (byte)'5', - (byte)'6', - (byte)'7', - (byte)'8', - (byte)'9', - (byte)'A', - (byte)'B', - (byte)'C', - (byte)'D', - (byte)'E', - (byte)'F', - }; - - - // Interface Rep ID Strings - public static final String kjava_rmi_Remote = createForAnyType(java.rmi.Remote.class); - public static final String korg_omg_CORBA_Object = createForAnyType(org.omg.CORBA.Object.class); - - // Dummy arguments for getIdFromHelper method - public static final Class kNoParamTypes[] ={}; - public static final Object kNoArgs[] = {}; - - - RepositoryId_1_3(){} - - RepositoryId_1_3(String aRepId){ - init(aRepId); - } - - RepositoryId_1_3 init(String aRepId){ - - this.repId = aRepId; - - // Special case for remote - if (aRepId.length() == 0) { - clazz = java.rmi.Remote.class; - typeString = ""; - isRMIValueType = true; - suid = kInterfaceOnlyHashStr; - return this; - } - else if (aRepId.equals(kWStringValueRepID)) { - clazz = java.lang.String.class; - typeString = kWStringTypeStr; - isIDLType = true; - versionString = kWStringValueVersion; - return this; - } - else { - - String repId = convertFromISOLatin1(aRepId); - - versionString = repId.substring(repId.indexOf(':', repId.indexOf(':')+1)); - if (repId.startsWith(kIDLPrefix)) { - typeString = - repId.substring(kIDLPrefixLength, repId.indexOf(':', kIDLPrefixLength)); - isIDLType = true; - if (typeString.startsWith(kIDLNamePrefix)) - completeClassName = kIDLClassnamePrefix + - typeString.substring(kIDLNamePrefix.length()).replace('/','.'); - else completeClassName = typeString.replace('/','.'); - - } - else if (repId.startsWith(kValuePrefix)) { - typeString = - repId.substring(kValuePrefixLength, repId.indexOf(':', kValuePrefixLength)); - isRMIValueType = true; - - if (versionString.indexOf('.') == -1) { - actualSuid = versionString.substring(1); - suid = actualSuid; // default if not explicitly specified - - if (actualSuid.indexOf(':') != -1){ - // we have a declared hash also - int pos = actualSuid.indexOf(':')+1; - // actualSuid = suid.substring(pos); - // suid = suid.substring(0, pos-1); - suid = actualSuid.substring(pos); - actualSuid = actualSuid.substring(0, pos-1); - } - - } - else { - // _REVISIT_ : Special case version failure ? - } - } - else isSupportedFormat = false; - - if (typeString.startsWith(kSequencePrefix)) { - isSequence = true; - } - - - return this; - } - } - - public final String getUnqualifiedName() { - if (unqualifiedName == null){ - String className = getClassName(); - int index = (className != null) ? className.lastIndexOf('.') : -1; - if (index == -1){ - unqualifiedName = className; - definedInId = "IDL::1.0"; - } - else { - unqualifiedName = className.substring(index); - definedInId = "IDL:" + className.substring(0, index).replace('.','/') + ":1.0"; - } - } - - return unqualifiedName; - } - - public final String getDefinedInId() { - if (definedInId == null){ - getUnqualifiedName(); - } - - return definedInId; - } - - public final String getTypeString() { - return typeString; - } - - public final String getVersionString() { - return versionString; - } - - public final String getSerialVersionUID() { - return suid; - } - - public final String getActualSerialVersionUID() { - return actualSuid; - } - public final long getSerialVersionUIDAsLong() { - return suidLong; - } - - public final long getActualSerialVersionUIDAsLong() { - return actualSuidLong; - } - - public final boolean isRMIValueType() { - return isRMIValueType; - } - - public final boolean isIDLType() { - return isIDLType; - } - - public final String getRepositoryId() { - return repId; - } - - public static byte[] getByteArray(String repStr) { - synchronized (repStrToByteArray){ - return (byte[]) repStrToByteArray.get(repStr); - } - } - - public static void setByteArray(String repStr, byte[] repStrBytes) { - synchronized (repStrToByteArray){ - repStrToByteArray.put(repStr, repStrBytes); - } - } - - public final boolean isSequence() { - return isSequence; - } - - public final boolean isSupportedFormat() { - return isSupportedFormat; - } - - - // This method will return the classname from the typestring OR if the classname turns out to be - // a special class "pseudo" name, then the matching real classname is returned. - public final String getClassName() { - - if (isRMIValueType) - return typeString; - else if (isIDLType) - return completeClassName; - else return null; - - } - - // This method calls getClazzFromType() and falls back to the repStrToClass - // cache if no class was found. It's used where any class matching the - // given repid is an acceptable result. - public final Class getAnyClassFromType() throws ClassNotFoundException { - try { - return getClassFromType(); - } catch (ClassNotFoundException cnfe) { - Class clz = (Class)repStrToClass.get(repId); - if (clz != null) - return clz; - else - throw cnfe; - } - } - - public final Class getClassFromType() - throws ClassNotFoundException { - if (clazz != null) - return clazz; - - Class specialCase = (Class)kSpecialCasesClasses.get(getClassName()); - - if (specialCase != null){ - clazz = specialCase; - return specialCase; - } - else - { - try{ - return Util.loadClass(getClassName(), null, null); - } - catch(ClassNotFoundException cnfe){ - if (defaultServerURL != null) { - try{ - return getClassFromType(defaultServerURL); - } - catch(MalformedURLException mue){ - throw cnfe; - } - } - else throw cnfe; - } - } - - } - - public final Class getClassFromType(Class expectedType, String codebase) - throws ClassNotFoundException { - if (clazz != null) - return clazz; - - Class specialCase = (Class)kSpecialCasesClasses.get(getClassName()); - - if (specialCase != null){ - clazz = specialCase; - return specialCase; - } else { - ClassLoader expectedTypeClassLoader = (expectedType == null ? null : expectedType.getClassLoader()); - return loadClassOfType(getClassName(), - codebase, - expectedTypeClassLoader, - expectedType, - expectedTypeClassLoader); - } - - } - - public final Class getClassFromType(String url) - throws ClassNotFoundException, MalformedURLException { - return Util.loadClass(getClassName(), url, null); - } - - public final String toString() { - return repId; - } - - private static String createHashString(java.io.Serializable ser) { - - return createHashString(ser.getClass()); - } - - private static String createHashString(java.lang.Class clazz) { - - if (clazz.isInterface() || !java.io.Serializable.class.isAssignableFrom(clazz)) - return kInterfaceHashCode; - - - long actualLong = ObjectStreamClassUtil_1_3.computeStructuralUID(false, clazz); - String hash = null; - if (actualLong == 0) - hash = kInterfaceOnlyHashStr; - else if (actualLong == 1) - hash = kExternalizableHashStr; - else - hash = Long.toHexString(actualLong).toUpperCase(); - while(hash.length() < 16){ - hash = "0" + hash; - } - - long declaredLong = ObjectStreamClassUtil_1_3.computeSerialVersionUID(clazz); - String declared = null; - if (declaredLong == 0) - declared = kInterfaceOnlyHashStr; - else if (declaredLong == 1) - declared = kExternalizableHashStr; - else - declared = Long.toHexString(declaredLong).toUpperCase(); - while (declared.length() < 16){ - declared = "0" + declared; - } - hash = hash + ":" + declared; - - return ":" + hash; - } - - /** - * Creates a repository ID for a sequence. This is for expert users only as - * this method assumes the object passed is an array. If passed an object - * that is not an array, it will produce a rep id for a sequence of zero - * length. This would be an error. - * @param ser The Java object to create a repository ID for - **/ - public static String createSequenceRepID(java.lang.Object ser){ - return createSequenceRepID(ser.getClass()); - } - - /** - * Creates a repository ID for a sequence. This is for expert users only as - * this method assumes the object passed is an array. If passed an object - * that is not an array, it will produce a malformed rep id. - * @param clazz The Java class to create a repository ID for - **/ - public static String createSequenceRepID(java.lang.Class clazz){ - synchronized (classSeqToRepStr){ - - String repid = (String)classSeqToRepStr.get(clazz); - if (repid != null) - return repid; - - Class originalClazz = clazz; - - Class type = null; - int numOfDims = 0; - - while ((type = clazz.getComponentType()) != null) { - numOfDims++; - clazz = type; - } - - if (clazz.isPrimitive()) - repid = kValuePrefix + originalClazz.getName() + kPrimitiveSequenceValueHash; - else { - StringBuffer buf = new StringBuffer(); - buf.append(kValuePrefix); - while(numOfDims-- > 0) { - buf.append("["); - } - buf.append("L"); - buf.append(convertToISOLatin1(clazz.getName())); - buf.append(";"); - buf.append(createHashString(clazz)); - repid = buf.toString(); - } - classSeqToRepStr.put(originalClazz,repid); - return repid; - } - - } - - - public static String createForSpecialCase(java.lang.Class clazz){ - if (clazz.isArray()){ - return createSequenceRepID(clazz); - } - else { - return (String)kSpecialCasesRepIDs.get(clazz); - } - } - - public static String createForSpecialCase(java.io.Serializable ser){ - Class clazz = ser.getClass(); - if (clazz.isArray()){ - return createSequenceRepID(ser); - } - else - return createForSpecialCase(clazz); - } - - /** - * Creates a repository ID for a normal Java Type. - * @param ser The Java object to create a repository ID for - * @exception com.sun.corba.se.impl.io.TypeMismatchException if ser implements the - * org.omg.CORBA.portable.IDLEntity interface which indicates it is an IDL Value type. - **/ - public static String createForJavaType(java.io.Serializable ser) - throws com.sun.corba.se.impl.io.TypeMismatchException - { - synchronized (classToRepStr) { - String repid = createForSpecialCase(ser); - if (repid != null) - return repid; - Class clazz = ser.getClass(); - repid = (String)classToRepStr.get(clazz); - - if (repid != null) - return repid; - - repid = kValuePrefix + convertToISOLatin1(clazz.getName()) + - createHashString(clazz); - - classToRepStr.put(clazz, repid); - repStrToClass.put(repid, clazz); - return repid; - } - } - - /** - * Creates a repository ID for a normal Java Type. - * @param clz The Java class to create a repository ID for - * @exception com.sun.corba.se.impl.io.TypeMismatchException if ser implements the - * org.omg.CORBA.portable.IDLEntity interface which indicates it is an IDL Value type. - **/ - public static String createForJavaType(Class clz) - throws com.sun.corba.se.impl.io.TypeMismatchException - { - synchronized (classToRepStr){ - String repid = createForSpecialCase(clz); - if (repid != null) - return repid; - - repid = (String)classToRepStr.get(clz); - if (repid != null) - return repid; - - repid = kValuePrefix + convertToISOLatin1(clz.getName()) + - createHashString(clz); - - classToRepStr.put(clz, repid); - repStrToClass.put(repid, clz); - return repid; - } - } - - /** - * Creates a repository ID for an IDL Java Type. - * @param ser The IDL Value object to create a repository ID for - * @param major The major version number - * @param minor The minor version number - * @exception com.sun.corba.se.impl.io.TypeMismatchException if ser does not implement the - * org.omg.CORBA.portable.IDLEntity interface which indicates it is an IDL Value type. - **/ - public static String createForIDLType(Class ser, int major, int minor) - throws com.sun.corba.se.impl.io.TypeMismatchException - { - synchronized (classIDLToRepStr){ - String repid = (String)classIDLToRepStr.get(ser); - if (repid != null) - return repid; - - repid = kIDLPrefix + convertToISOLatin1(ser.getName()).replace('.','/') + - ":" + major + "." + minor; - classIDLToRepStr.put(ser, repid); - return repid; - } - } - - private static String getIdFromHelper(Class clazz){ - try { - Class helperClazz = Utility.loadClassForClass(clazz.getName()+"Helper", null, - clazz.getClassLoader(), clazz, clazz.getClassLoader()); - Method idMethod = helperClazz.getDeclaredMethod("id", kNoParamTypes); - return (String)idMethod.invoke(null, kNoArgs); - } - catch(java.lang.ClassNotFoundException cnfe) - { - throw new org.omg.CORBA.MARSHAL(cnfe.toString()); - } - catch(java.lang.NoSuchMethodException nsme) - { - throw new org.omg.CORBA.MARSHAL(nsme.toString()); - } - catch(java.lang.reflect.InvocationTargetException ite) - { - throw new org.omg.CORBA.MARSHAL(ite.toString()); - } - catch(java.lang.IllegalAccessException iae) - { - throw new org.omg.CORBA.MARSHAL(iae.toString()); - } - } - - /** - * Createa a repository ID for the type if it is either a java type - * or an IDL type. - * @param type The type to create rep. id for - * @return The rep. id. - **/ - public static String createForAnyType(Class type) { - try{ - if (type.isArray()) - return createSequenceRepID(type); - else if (IDLEntity.class.isAssignableFrom(type)) - { - try{ - return getIdFromHelper(type); - } - catch(Throwable t) { - return createForIDLType(type, 1, 0); - } - } - else return createForJavaType(type); - } - catch(com.sun.corba.se.impl.io.TypeMismatchException e){ - return null; - } - - } - - public static boolean isAbstractBase(Class clazz) { - return (clazz.isInterface() && - IDLEntity.class.isAssignableFrom(clazz) && - (!ValueBase.class.isAssignableFrom(clazz)) && - (!org.omg.CORBA.Object.class.isAssignableFrom(clazz))); - - } - - /** - * Convert strings with illegal IDL identifier characters. - *

- * Section 5.5.7 of OBV spec. - */ - private static String convertToISOLatin1 (String name) { - - int length = name.length(); - if (length == 0) { - return name; - } - StringBuffer buffer = null; - - for (int i = 0; i < length; i++) { - - char c = name.charAt(i); - - if (c > 255 || IDL_IDENTIFIER_CHARS[c] == 0) { - - // We gotta convert. Have we already started? - - if (buffer == null) { - - // No, so get set up... - - buffer = new StringBuffer(name.substring(0,i)); - } - - // Convert the character into the IDL escape syntax... - buffer.append( - "\\U" + - (char)ASCII_HEX[(c & 0xF000) >>> 12] + - (char)ASCII_HEX[(c & 0x0F00) >>> 8] + - (char)ASCII_HEX[(c & 0x00F0) >>> 4] + - (char)ASCII_HEX[(c & 0x000F)]); - - } else { - if (buffer != null) { - buffer.append(c); - } - } - } - - if (buffer != null) { - name = buffer.toString(); - } - - return name; - } - - /** - * Convert strings with ISO Latin 1 escape sequences back to original strings. - *

- * Section 5.5.7 of OBV spec. - */ - private static String convertFromISOLatin1 (String name) { - - int index = -1; - StringBuffer buf = new StringBuffer(name); - - while ((index = buf.toString().indexOf("\\U")) != -1){ - String str = "0000" + buf.toString().substring(index+2, index+6); - - // Convert Hexadecimal - byte[] buffer = new byte[(str.length() - 4) / 2]; - for (int i=4, j=0; i < str.length(); i +=2, j++) { - buffer[j] = (byte)((ORBUtility.hexOf(str.charAt(i)) << 4) & 0xF0); - buffer[j] |= (byte)((ORBUtility.hexOf(str.charAt(i+1)) << 0) & 0x0F); - } - buf = new StringBuffer(delete(buf.toString(), index, index+6)); - buf.insert(index, (char)buffer[1]); - } - - return buf.toString(); - - - } - - private static String delete(String str, int from, int to) - { - return str.substring(0, from) + str.substring(to, str.length()); - } - - private static String replace(String target, String arg, String source) - { - int i = 0; - i = target.indexOf(arg); - - while(i != -1) - { - String left = target.substring(0, i); - String right = target.substring(i+arg.length()); - target = new String(left+source+right); - i = target.indexOf(arg); - } - return target; - } - - /* - * Load a class and check that it is assignable to a given type. - * @param className the class name. - * @param remoteCodebase the codebase to use. May be null. - * @param loader the class loader of last resort. May be null. - * @param expectedType the expected type. May be null. - * @return the loaded class. - */ - private Class loadClassOfType (String className, - String remoteCodebase, - ClassLoader loader, - Class expectedType, - ClassLoader expectedTypeClassLoader) - throws ClassNotFoundException { - - Class loadedClass = null; - - try { - //Sequence finding of the stubs according to spec - try{ - //If-else is put here for speed up of J2EE. - //According to the OMG spec, the if clause is not dead code. - //It can occur if some compiler has allowed generation - //into org.omg.stub hierarchy for non-offending - //classes. This will encourage people to - //produce non-offending class stubs in their own hierarchy. - if(!PackagePrefixChecker - .hasOffendingPrefix(PackagePrefixChecker - .withoutPackagePrefix(className))){ - loadedClass = Util.loadClass - (PackagePrefixChecker.withoutPackagePrefix(className), - remoteCodebase, - loader); - } else { - loadedClass = Util.loadClass - (className, - remoteCodebase, - loader); - } - } catch (ClassNotFoundException cnfe) { - loadedClass = Util.loadClass - (className, - remoteCodebase, - loader); - } - if (expectedType == null) - return loadedClass; - } catch (ClassNotFoundException cnfe) { - if (expectedType == null) - throw cnfe; - } - - // If no class was not loaded, or if the loaded class is not of the - // correct type, make a further attempt to load the correct class - // using the classloader of the expected type. - // _REVISIT_ Is this step necessary, or should the Util,loadClass - // algorithm always produce a valid class if the setup is correct? - // Does the OMG standard algorithm need to be changed to include - // this step? - if (loadedClass == null || !expectedType.isAssignableFrom(loadedClass)) { - if (expectedType.getClassLoader() != expectedTypeClassLoader) - throw new IllegalArgumentException("expectedTypeClassLoader not class loader of expectedType."); - - if (expectedTypeClassLoader != null) - loadedClass = expectedTypeClassLoader.loadClass(className); - else - loadedClass = ORBClassLoader.loadClass(className); - } - - return loadedClass; - } - - /** - * Checks to see if the FullValueDescription should be retrieved. - * @exception Throws IOException if suids do not match or if the repositoryID - * is not an RMIValueType - */ - public static boolean useFullValueDescription(Class clazz, String repositoryID) - throws IOException{ - - String clazzRepIDStr = createForAnyType(clazz); - - if (clazzRepIDStr.equals(repositoryID)) - return false; - - RepositoryId_1_3 targetRepid; - RepositoryId_1_3 clazzRepid; - - synchronized(cache) { - // to avoid race condition where multiple threads could be - // accessing this method, and their access to the cache may - // be interleaved giving unexpected results - - targetRepid = cache.getId(repositoryID); - clazzRepid = cache.getId(clazzRepIDStr); - } - - if ((targetRepid.isRMIValueType()) && (clazzRepid.isRMIValueType())){ - if (!targetRepid.getSerialVersionUID().equals(clazzRepid.getSerialVersionUID())) { - - String mssg = "Mismatched serialization UIDs : Source (Rep. ID" + - clazzRepid + ") = " + - clazzRepid.getSerialVersionUID() + " whereas Target (Rep. ID " + repositoryID + - ") = " + targetRepid.getSerialVersionUID(); - throw new IOException(mssg); - } else { - return true; - } - } else { - - throw new IOException("The repository ID is not of an RMI value type (Expected ID = " + clazzRepIDStr + "; Received ID = " + repositoryID +")"); - } - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryId_1_3_1.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryId_1_3_1.java deleted file mode 100644 index 8c1ab6e7390..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryId_1_3_1.java +++ /dev/null @@ -1,1065 +0,0 @@ -/* - * Copyright (c) 2001, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - */ -package com.sun.corba.se.impl.orbutil; - -import java.util.StringTokenizer; -import java.util.Hashtable; -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import org.omg.CORBA.portable.ValueBase; -import org.omg.CORBA.portable.IDLEntity; - -//d11638 files in the same package, therefore remove their reference -//import com.sun.corba.se.impl.util.JDKBridge; -//import com.sun.corba.se.impl.util.IdentityHashtable; -import com.sun.corba.se.impl.util.JDKBridge; -import com.sun.corba.se.impl.util.Utility; -import com.sun.corba.se.impl.util.PackagePrefixChecker; -import com.sun.corba.se.impl.util.IdentityHashtable; - -import javax.rmi.CORBA.Util; - -/** - * Because all methods in RepositoryId are static, we have - * to duplicate all of this code, freezing it in its 1.3.1 - * form for backwards compatibility. - * - * For security reasons, we can't expose enough of - * io/ObjectStreamClass, so it has to be duplicated in - * orbutil. - */ -public class RepositoryId_1_3_1 { - - // Legal IDL Identifier characters (1 = legal). Note - // that '.' (2E) is marked as legal even though it is - // not legal in IDL. This allows us to treat a fully - // qualified Java name with '.' package separators - // uniformly, and is safe because that is the only - // legal use of '.' in a Java name. - - private static final byte[] IDL_IDENTIFIER_CHARS = { - - // 0 1 2 3 4 5 6 7 8 9 a b c d e f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 00-0f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 10-1f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,1,0, // 20-2f - 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0, // 30-3f - 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // 40-4f - 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, // 50-5f - 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // 60-6f - 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0, // 70-7f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 80-8f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 90-9f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // a0-af - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // b0-bf - 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // c0-cf - 0,1,1,1, 1,1,1,0, 1,1,1,1, 1,0,0,1, // d0-df - 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // e0-ef - 0,1,1,1, 1,1,1,0, 1,1,1,1, 1,0,0,1, // f0-ff - }; - - - private static final long serialVersionUID = 123456789L; - - private static String defaultServerURL = null; - private static boolean useCodebaseOnly = false; - - static { - if (defaultServerURL == null) - defaultServerURL = (String)JDKBridge.getLocalCodebase(); - useCodebaseOnly = JDKBridge.useCodebaseOnly(); - - } - - private static IdentityHashtable classToRepStr = new IdentityHashtable(); - private static IdentityHashtable classIDLToRepStr = new IdentityHashtable(); - private static IdentityHashtable classSeqToRepStr = new IdentityHashtable(); - - private static IdentityHashtable repStrToByteArray = new IdentityHashtable(); - private static Hashtable repStrToClass = new Hashtable(); - - private String repId = null; - private boolean isSupportedFormat = true; - private String typeString = null; - private String versionString = null; - private boolean isSequence = false; - private boolean isRMIValueType = false; - private boolean isIDLType = false; - private String completeClassName = null; - private String unqualifiedName = null; - private String definedInId = null; - private Class clazz = null; - private String suid = null, actualSuid = null; - private long suidLong = ObjectStreamClass_1_3_1.kDefaultUID, actualSuidLong = ObjectStreamClass_1_3_1.kDefaultUID; - - // Repository ID fragments - private static final String kSequenceKeyword = "seq"; - private static final String kValuePrefix = "RMI:"; - private static final String kIDLPrefix = "IDL:"; - private static final String kIDLNamePrefix = "omg.org/"; - private static final String kIDLClassnamePrefix = "org.omg."; - private static final String kSequencePrefix = "["; - private static final String kCORBAPrefix = "CORBA/"; - private static final String kArrayPrefix = kValuePrefix + kSequencePrefix + kCORBAPrefix; - private static final int kValuePrefixLength = kValuePrefix.length(); - private static final int kIDLPrefixLength = kIDLPrefix.length(); - private static final int kSequencePrefixLength = kSequencePrefix.length(); - private static final String kInterfaceHashCode = ":0000000000000000"; - private static final String kInterfaceOnlyHashStr = "0000000000000000"; - private static final String kExternalizableHashStr = "0000000000000001"; - - // Value tag utility methods and constants - public static final int kInitialValueTag= 0x7fffff00; - public static final int kNoTypeInfo = 0; - public static final int kSingleRepTypeInfo = 0x02; - public static final int kPartialListTypeInfo = 0x06; - public static final int kChunkedMask = 0x08; - public static final int kPreComputed_StandardRMIUnchunked = RepositoryId_1_3_1.computeValueTag(false, RepositoryId_1_3_1.kSingleRepTypeInfo, false); - public static final int kPreComputed_CodeBaseRMIUnchunked = RepositoryId_1_3_1.computeValueTag(true, RepositoryId_1_3_1.kSingleRepTypeInfo, false); - public static final int kPreComputed_StandardRMIChunked = RepositoryId_1_3_1.computeValueTag(false, RepositoryId_1_3_1.kSingleRepTypeInfo, true); - public static final int kPreComputed_CodeBaseRMIChunked = RepositoryId_1_3_1.computeValueTag(true, RepositoryId_1_3_1.kSingleRepTypeInfo, true); - - public static final int kPreComputed_StandardRMIUnchunked_NoRep = RepositoryId_1_3_1.computeValueTag(false, RepositoryId_1_3_1.kNoTypeInfo, false); - public static final int kPreComputed_CodeBaseRMIUnchunked_NoRep = RepositoryId_1_3_1.computeValueTag(true, RepositoryId_1_3_1.kNoTypeInfo, false); - public static final int kPreComputed_StandardRMIChunked_NoRep = RepositoryId_1_3_1.computeValueTag(false, RepositoryId_1_3_1.kNoTypeInfo, true); - public static final int kPreComputed_CodeBaseRMIChunked_NoRep = RepositoryId_1_3_1.computeValueTag(true, RepositoryId_1_3_1.kNoTypeInfo, true); - - // Public, well known repository IDs - - // _REVISIT_ : A table structure with a good search routine for all of this - // would be more efficient and easier to maintain... - - // String - public static final String kWStringValueVersion = "1.0"; - public static final String kWStringValueHash = ":"+kWStringValueVersion; - public static final String kWStringStubValue = "WStringValue"; - public static final String kWStringTypeStr = "omg.org/CORBA/"+kWStringStubValue; - public static final String kWStringValueRepID = kIDLPrefix + kWStringTypeStr + kWStringValueHash; - - // Any - public static final String kAnyRepID = kIDLPrefix + "omg.org/CORBA/Any"; - - // Class - // Anita4: convert to uppercase - public static final String kClassDescValueHash = ":" + - Long.toHexString( - ObjectStreamClass_1_3_1.getActualSerialVersionUID(javax.rmi.CORBA.ClassDesc.class)).toUpperCase() + ":" + - Long.toHexString( - ObjectStreamClass_1_3_1.getSerialVersionUID(javax.rmi.CORBA.ClassDesc.class)).toUpperCase(); - public static final String kClassDescStubValue = "ClassDesc"; - public static final String kClassDescTypeStr = "javax.rmi.CORBA."+kClassDescStubValue; - public static final String kClassDescValueRepID = kValuePrefix + kClassDescTypeStr + kClassDescValueHash; - - // Object - public static final String kObjectValueHash = ":1.0"; - public static final String kObjectStubValue = "Object"; - - // Sequence - public static final String kSequenceValueHash = ":1.0"; - public static final String kPrimitiveSequenceValueHash = ":0000000000000000"; - - // Serializable - public static final String kSerializableValueHash = ":1.0"; - public static final String kSerializableStubValue = "Serializable"; - - // Externalizable - public static final String kExternalizableValueHash = ":1.0"; - public static final String kExternalizableStubValue = "Externalizable"; - - // Remote (The empty string is used for java.rmi.Remote) - public static final String kRemoteValueHash = ""; - public static final String kRemoteStubValue = ""; - public static final String kRemoteTypeStr = ""; - public static final String kRemoteValueRepID = ""; - - private static final Hashtable kSpecialArrayTypeStrings = new Hashtable(); - - static { - kSpecialArrayTypeStrings.put("CORBA.WStringValue", new StringBuffer(java.lang.String.class.getName())); - kSpecialArrayTypeStrings.put("javax.rmi.CORBA.ClassDesc", new StringBuffer(java.lang.Class.class.getName())); - kSpecialArrayTypeStrings.put("CORBA.Object", new StringBuffer(java.rmi.Remote.class.getName())); - - } - - private static final Hashtable kSpecialCasesRepIDs = new Hashtable(); - - static { - kSpecialCasesRepIDs.put(java.lang.String.class, kWStringValueRepID); - kSpecialCasesRepIDs.put(java.lang.Class.class, kClassDescValueRepID); - kSpecialCasesRepIDs.put(java.rmi.Remote.class, kRemoteValueRepID); - } - - private static final Hashtable kSpecialCasesStubValues = new Hashtable(); - - static { - kSpecialCasesStubValues.put(java.lang.String.class, kWStringStubValue); - kSpecialCasesStubValues.put(java.lang.Class.class, kClassDescStubValue); - kSpecialCasesStubValues.put(java.lang.Object.class, kObjectStubValue); - kSpecialCasesStubValues.put(java.io.Serializable.class, kSerializableStubValue); - kSpecialCasesStubValues.put(java.io.Externalizable.class, kExternalizableStubValue); - kSpecialCasesStubValues.put(java.rmi.Remote.class, kRemoteStubValue); - } - - - private static final Hashtable kSpecialCasesVersions = new Hashtable(); - - static { - kSpecialCasesVersions.put(java.lang.String.class, kWStringValueHash); - kSpecialCasesVersions.put(java.lang.Class.class, kClassDescValueHash); - kSpecialCasesVersions.put(java.lang.Object.class, kObjectValueHash); - kSpecialCasesVersions.put(java.io.Serializable.class, kSerializableValueHash); - kSpecialCasesVersions.put(java.io.Externalizable.class, kExternalizableValueHash); - kSpecialCasesVersions.put(java.rmi.Remote.class, kRemoteValueHash); - } - - private static final Hashtable kSpecialCasesClasses = new Hashtable(); - - static { - kSpecialCasesClasses.put(kWStringTypeStr, java.lang.String.class); - kSpecialCasesClasses.put(kClassDescTypeStr, java.lang.Class.class); - kSpecialCasesClasses.put(kRemoteTypeStr, java.rmi.Remote.class); - - kSpecialCasesClasses.put("org.omg.CORBA.WStringValue", java.lang.String.class); - kSpecialCasesClasses.put("javax.rmi.CORBA.ClassDesc", java.lang.Class.class); - //kSpecialCasesClasses.put(kRemoteTypeStr, java.rmi.Remote.class); - } - - private static final Hashtable kSpecialCasesArrayPrefix = new Hashtable(); - - static { - kSpecialCasesArrayPrefix.put(java.lang.String.class, kValuePrefix + kSequencePrefix + kCORBAPrefix); - kSpecialCasesArrayPrefix.put(java.lang.Class.class, kValuePrefix + kSequencePrefix + "javax/rmi/CORBA/"); - kSpecialCasesArrayPrefix.put(java.lang.Object.class, kValuePrefix + kSequencePrefix + "java/lang/"); - kSpecialCasesArrayPrefix.put(java.io.Serializable.class, kValuePrefix + kSequencePrefix + "java/io/"); - kSpecialCasesArrayPrefix.put(java.io.Externalizable.class, kValuePrefix + kSequencePrefix + "java/io/"); - kSpecialCasesArrayPrefix.put(java.rmi.Remote.class, kValuePrefix + kSequencePrefix + kCORBAPrefix); - } - - private static final Hashtable kSpecialPrimitives = new Hashtable(); - - static { - kSpecialPrimitives.put("int","long"); - kSpecialPrimitives.put("long","longlong"); - kSpecialPrimitives.put("byte","octet"); - } - - /** - * Used to convert ascii to hex. - */ - private static final byte ASCII_HEX[] = { - (byte)'0', - (byte)'1', - (byte)'2', - (byte)'3', - (byte)'4', - (byte)'5', - (byte)'6', - (byte)'7', - (byte)'8', - (byte)'9', - (byte)'A', - (byte)'B', - (byte)'C', - (byte)'D', - (byte)'E', - (byte)'F', - }; - - - // bug fix for 4328952; to eliminate possibility of overriding this - // in a subclass. - public static final RepositoryIdCache_1_3_1 cache = new RepositoryIdCache_1_3_1(); - - // Interface Rep ID Strings - public static final String kjava_rmi_Remote = createForAnyType(java.rmi.Remote.class); - public static final String korg_omg_CORBA_Object = createForAnyType(org.omg.CORBA.Object.class); - - // Dummy arguments for getIdFromHelper method - public static final Class kNoParamTypes[] ={}; - public static final Object kNoArgs[] = {}; - - - // To create a RepositoryID, use code similar to the following: - // RepositoryId.cache.getId( id ); - - RepositoryId_1_3_1(){} - - RepositoryId_1_3_1(String aRepId){ - init(aRepId); - } - - RepositoryId_1_3_1 init(String aRepId){ - - this.repId = aRepId; - - // Special case for remote - if (aRepId.length() == 0) { - clazz = java.rmi.Remote.class; - typeString = ""; - isRMIValueType = true; - suid = kInterfaceOnlyHashStr; - return this; - } - else if (aRepId.equals(kWStringValueRepID)) { - clazz = java.lang.String.class; - typeString = kWStringTypeStr; - isIDLType = true; - // fix where Attempting to obtain a FullValueDescription - // for an RMI value type with a String field causes an exception. - completeClassName = "java.lang.String"; - versionString = kWStringValueVersion; - return this; - } - else { - - String repId = convertFromISOLatin1(aRepId); - - versionString = repId.substring(repId.indexOf(':', repId.indexOf(':')+1)); - if (repId.startsWith(kIDLPrefix)) { - typeString = - repId.substring(kIDLPrefixLength, repId.indexOf(':', kIDLPrefixLength)); - isIDLType = true; - if (typeString.startsWith(kIDLNamePrefix)) - completeClassName = kIDLClassnamePrefix + - typeString.substring(kIDLNamePrefix.length()).replace('/','.'); - else completeClassName = typeString.replace('/','.'); - - } - else if (repId.startsWith(kValuePrefix)) { - typeString = - repId.substring(kValuePrefixLength, repId.indexOf(':', kValuePrefixLength)); - isRMIValueType = true; - - if (versionString.indexOf('.') == -1) { - actualSuid = versionString.substring(1); - suid = actualSuid; // default if not explicitly specified - - if (actualSuid.indexOf(':') != -1){ - // we have a declared hash also - int pos = actualSuid.indexOf(':')+1; - // actualSuid = suid.substring(pos); - // suid = suid.substring(0, pos-1); - suid = actualSuid.substring(pos); - actualSuid = actualSuid.substring(0, pos-1); - } - - } - else { - // _REVISIT_ : Special case version failure ? - } - } - else isSupportedFormat = false; - - if (typeString.startsWith(kSequencePrefix)) { - isSequence = true; - } - - - return this; - } - } - - public final String getUnqualifiedName() { - if (unqualifiedName == null){ - String className = getClassName(); - int index = className.lastIndexOf('.'); - if (index == -1){ - unqualifiedName = className; - definedInId = "IDL::1.0"; - } - else { - unqualifiedName = className.substring(index); - definedInId = "IDL:" + className.substring(0, index).replace('.','/') + ":1.0"; - } - } - - return unqualifiedName; - } - - public final String getDefinedInId() { - if (definedInId == null){ - getUnqualifiedName(); - } - - return definedInId; - } - - public final String getTypeString() { - return typeString; - } - - public final String getVersionString() { - return versionString; - } - - public final String getSerialVersionUID() { - return suid; - } - - public final String getActualSerialVersionUID() { - return actualSuid; - } - public final long getSerialVersionUIDAsLong() { - return suidLong; - } - - public final long getActualSerialVersionUIDAsLong() { - return actualSuidLong; - } - - public final boolean isRMIValueType() { - return isRMIValueType; - } - - public final boolean isIDLType() { - return isIDLType; - } - - public final String getRepositoryId() { - return repId; - } - - public static byte[] getByteArray(String repStr) { - synchronized (repStrToByteArray){ - return (byte[]) repStrToByteArray.get(repStr); - } - } - - public static void setByteArray(String repStr, byte[] repStrBytes) { - synchronized (repStrToByteArray){ - repStrToByteArray.put(repStr, repStrBytes); - } - } - - public final boolean isSequence() { - return isSequence; - } - - public final boolean isSupportedFormat() { - return isSupportedFormat; - } - - - // This method will return the classname from the typestring OR if the classname turns out to be - // a special class "pseudo" name, then the matching real classname is returned. - public final String getClassName() { - - if (isRMIValueType) - return typeString; - else if (isIDLType) - return completeClassName; - else return null; - - } - - // This method calls getClazzFromType() and falls back to the repStrToClass - // cache if no class was found. It's used where any class matching the - // given repid is an acceptable result. - public final Class getAnyClassFromType() throws ClassNotFoundException { - try { - return getClassFromType(); - } catch (ClassNotFoundException cnfe) { - Class clz = (Class)repStrToClass.get(repId); - if (clz != null) - return clz; - else - throw cnfe; - } - } - - public final Class getClassFromType() - throws ClassNotFoundException { - if (clazz != null) - return clazz; - - Class specialCase = (Class)kSpecialCasesClasses.get(getClassName()); - - if (specialCase != null){ - clazz = specialCase; - return specialCase; - } - else - { - try{ - return Util.loadClass(getClassName(), null, null); - } - catch(ClassNotFoundException cnfe){ - if (defaultServerURL != null) { - try{ - return getClassFromType(defaultServerURL); - } - catch(MalformedURLException mue){ - throw cnfe; - } - } - else throw cnfe; - } - } - - } - - public final Class getClassFromType(Class expectedType, String codebase) - throws ClassNotFoundException { - if (clazz != null) - return clazz; - - Class specialCase = (Class)kSpecialCasesClasses.get(getClassName()); - - if (specialCase != null){ - clazz = specialCase; - return specialCase; - } else { - ClassLoader expectedTypeClassLoader = (expectedType == null ? null : expectedType.getClassLoader()); - return loadClassOfType(getClassName(), - codebase, - expectedTypeClassLoader, - expectedType, - expectedTypeClassLoader); - } - - } - - public final Class getClassFromType(String url) - throws ClassNotFoundException, MalformedURLException { - return Util.loadClass(getClassName(), url, null); - } - - public final String toString() { - return repId; - } - - /** - * Checks to see if the FullValueDescription should be retrieved. - * @exception Throws IOException if suids do not match or if the repositoryID - * is not an RMIValueType - */ - public static boolean useFullValueDescription(Class clazz, String repositoryID) - throws IOException{ - - String clazzRepIDStr = createForAnyType(clazz); - - if (clazzRepIDStr.equals(repositoryID)) - return false; - - RepositoryId_1_3_1 targetRepid; - RepositoryId_1_3_1 clazzRepid; - - synchronized(cache) { - // to avoid race condition where multiple threads could be - // accessing this method, and their access to the cache may - // be interleaved giving unexpected results - - targetRepid = cache.getId(repositoryID); - clazzRepid = cache.getId(clazzRepIDStr); - } - //ObjectStreamClass osc = ObjectStreamClass.lookup(clazz); - - if ((targetRepid.isRMIValueType()) && (clazzRepid.isRMIValueType())){ - if (!targetRepid.getSerialVersionUID().equals(clazzRepid.getSerialVersionUID())) { - - String mssg = "Mismatched serialization UIDs : Source (Rep. ID" + - clazzRepid + ") = " + - clazzRepid.getSerialVersionUID() + " whereas Target (Rep. ID " + repositoryID + - ") = " + targetRepid.getSerialVersionUID(); - //com.sun.corba.se.impl.io.ValueUtility.log("RepositoryId",mssg); - throw new IOException(mssg); - } - else { - return true; - } - } - else { - - throw new IOException("The repository ID is not of an RMI value type (Expected ID = " + clazzRepIDStr + "; Received ID = " + repositoryID +")"); - } - } - - private static String createHashString(java.io.Serializable ser) { - - return createHashString(ser.getClass()); - } - - private static String createHashString(java.lang.Class clazz) { - - if (clazz.isInterface() || !java.io.Serializable.class.isAssignableFrom(clazz)) - return kInterfaceHashCode; - - //ObjectStreamClass osc = ObjectStreamClass.lookup(clazz); - - long actualLong = ObjectStreamClass_1_3_1.getActualSerialVersionUID(clazz); - String hash = null; - if (actualLong == 0) - hash = kInterfaceOnlyHashStr; - else if (actualLong == 1) - hash = kExternalizableHashStr; - else - hash = Long.toHexString(actualLong).toUpperCase(); - while(hash.length() < 16){ - hash = "0" + hash; - } - - long declaredLong = ObjectStreamClass_1_3_1.getSerialVersionUID(clazz); - String declared = null; - if (declaredLong == 0) - declared = kInterfaceOnlyHashStr; - else if (declaredLong == 1) - declared = kExternalizableHashStr; - else - declared = Long.toHexString(declaredLong).toUpperCase(); - while (declared.length() < 16){ - declared = "0" + declared; - } - hash = hash + ":" + declared; - - return ":" + hash; - } - - /** - * Creates a repository ID for a sequence. This is for expert users only as - * this method assumes the object passed is an array. If passed an object - * that is not an array, it will produce a rep id for a sequence of zero - * length. This would be an error. - * @param ser The Java object to create a repository ID for - **/ - public static String createSequenceRepID(java.lang.Object ser){ - return createSequenceRepID(ser.getClass()); - } - - /** - * Creates a repository ID for a sequence. This is for expert users only as - * this method assumes the object passed is an array. If passed an object - * that is not an array, it will produce a malformed rep id. - * @param clazz The Java class to create a repository ID for - **/ - public static String createSequenceRepID(java.lang.Class clazz){ - synchronized (classSeqToRepStr){ - - String repid = (String)classSeqToRepStr.get(clazz); - if (repid != null) - return repid; - - Class originalClazz = clazz; - - Class type = null; - int numOfDims = 0; - - while ((type = clazz.getComponentType()) != null) { - numOfDims++; - clazz = type; - } - - if (clazz.isPrimitive()) - repid = kValuePrefix + originalClazz.getName() + kPrimitiveSequenceValueHash; - else { - StringBuffer buf = new StringBuffer(); - buf.append(kValuePrefix); - while(numOfDims-- > 0) { - buf.append("["); - } - buf.append("L"); - buf.append(convertToISOLatin1(clazz.getName())); - buf.append(";"); - buf.append(createHashString(clazz)); - repid = buf.toString(); - } - classSeqToRepStr.put(originalClazz,repid); - return repid; - } - - } - - - public static String createForSpecialCase(java.lang.Class clazz){ - if (clazz.isArray()){ - return createSequenceRepID(clazz); - } - else { - return (String)kSpecialCasesRepIDs.get(clazz); - } - } - - public static String createForSpecialCase(java.io.Serializable ser){ - Class clazz = ser.getClass(); - if (clazz.isArray()){ - return createSequenceRepID(ser); - } - else - return createForSpecialCase(clazz); - } - - /** - * Creates a repository ID for a normal Java Type. - * @param ser The Java object to create a repository ID for - * @exception com.sun.corba.se.impl.io.TypeMismatchException if ser implements the - * org.omg.CORBA.portable.IDLEntity interface which indicates it is an IDL Value type. - **/ - public static String createForJavaType(java.io.Serializable ser) - throws com.sun.corba.se.impl.io.TypeMismatchException - { - synchronized (classToRepStr) { - String repid = createForSpecialCase(ser); - if (repid != null) - return repid; - Class clazz = ser.getClass(); - repid = (String)classToRepStr.get(clazz); - - if (repid != null) - return repid; - - repid = kValuePrefix + convertToISOLatin1(clazz.getName()) + - createHashString(clazz); - - classToRepStr.put(clazz, repid); - repStrToClass.put(repid, clazz); - return repid; - } - } - - /** - * Creates a repository ID for a normal Java Type. - * @param clz The Java class to create a repository ID for - * @exception com.sun.corba.se.impl.io.TypeMismatchException if ser implements the - * org.omg.CORBA.portable.IDLEntity interface which indicates it is an IDL Value type. - **/ - public static String createForJavaType(Class clz) - throws com.sun.corba.se.impl.io.TypeMismatchException - { - synchronized (classToRepStr){ - String repid = createForSpecialCase(clz); - if (repid != null) - return repid; - - repid = (String)classToRepStr.get(clz); - if (repid != null) - return repid; - - repid = kValuePrefix + convertToISOLatin1(clz.getName()) + - createHashString(clz); - - classToRepStr.put(clz, repid); - repStrToClass.put(repid, clz); - return repid; - } - } - - /** - * Creates a repository ID for an IDL Java Type. - * @param ser The IDL Value object to create a repository ID for - * @param major The major version number - * @param minor The minor version number - * @exception com.sun.corba.se.impl.io.TypeMismatchException if ser does not implement the - * org.omg.CORBA.portable.IDLEntity interface which indicates it is an IDL Value type. - **/ - public static String createForIDLType(Class ser, int major, int minor) - throws com.sun.corba.se.impl.io.TypeMismatchException - { - synchronized (classIDLToRepStr){ - String repid = (String)classIDLToRepStr.get(ser); - if (repid != null) - return repid; - - repid = kIDLPrefix + convertToISOLatin1(ser.getName()).replace('.','/') + - ":" + major + "." + minor; - classIDLToRepStr.put(ser, repid); - return repid; - } - } - - private static String getIdFromHelper(Class clazz){ - try { - Class helperClazz = Utility.loadClassForClass(clazz.getName()+"Helper", null, - clazz.getClassLoader(), clazz, clazz.getClassLoader()); - Method idMethod = helperClazz.getDeclaredMethod("id", kNoParamTypes); - return (String)idMethod.invoke(null, kNoArgs); - } - catch(java.lang.ClassNotFoundException cnfe) - { - throw new org.omg.CORBA.MARSHAL(cnfe.toString()); - } - catch(java.lang.NoSuchMethodException nsme) - { - throw new org.omg.CORBA.MARSHAL(nsme.toString()); - } - catch(java.lang.reflect.InvocationTargetException ite) - { - throw new org.omg.CORBA.MARSHAL(ite.toString()); - } - catch(java.lang.IllegalAccessException iae) - { - throw new org.omg.CORBA.MARSHAL(iae.toString()); - } - } - - /** - * Createa a repository ID for the type if it is either a java type - * or an IDL type. - * @param type The type to create rep. id for - * @return The rep. id. - **/ - public static String createForAnyType(Class type) { - try{ - if (type.isArray()) - return createSequenceRepID(type); - else if (IDLEntity.class.isAssignableFrom(type)) - { - try{ - return getIdFromHelper(type); - } - catch(Throwable t) { - return createForIDLType(type, 1, 0); - } - } - else return createForJavaType(type); - } - catch(com.sun.corba.se.impl.io.TypeMismatchException e){ - return null; - } - - } - - public static boolean isAbstractBase(Class clazz) { - return (clazz.isInterface() && - IDLEntity.class.isAssignableFrom(clazz) && - (!ValueBase.class.isAssignableFrom(clazz)) && - (!org.omg.CORBA.Object.class.isAssignableFrom(clazz))); - - } - - public static boolean isAnyRequired(Class clazz) { - return ((clazz == java.lang.Object.class) || - (clazz == java.io.Serializable.class) || - (clazz == java.io.Externalizable.class)); - } - - public static long fromHex(String hexNumber) { - if (hexNumber.startsWith("0x")) - return Long.valueOf(hexNumber.substring(2), 16).longValue(); - else return Long.valueOf(hexNumber, 16).longValue(); - } - - /** - * Convert strings with illegal IDL identifier characters. - *

- * Section 5.5.7 of OBV spec. - */ - private static String convertToISOLatin1 (String name) { - - int length = name.length(); - if (length == 0) { - return name; - } - StringBuffer buffer = null; - - for (int i = 0; i < length; i++) { - - char c = name.charAt(i); - - if (c > 255 || IDL_IDENTIFIER_CHARS[c] == 0) { - - // We gotta convert. Have we already started? - - if (buffer == null) { - - // No, so get set up... - - buffer = new StringBuffer(name.substring(0,i)); - } - - // Convert the character into the IDL escape syntax... - buffer.append( - "\\U" + - (char)ASCII_HEX[(c & 0xF000) >>> 12] + - (char)ASCII_HEX[(c & 0x0F00) >>> 8] + - (char)ASCII_HEX[(c & 0x00F0) >>> 4] + - (char)ASCII_HEX[(c & 0x000F)]); - - } else { - if (buffer != null) { - buffer.append(c); - } - } - } - - if (buffer != null) { - name = buffer.toString(); - } - - return name; - } - - /** - * Convert strings with ISO Latin 1 escape sequences back to original strings. - *

- * Section 5.5.7 of OBV spec. - */ - private static String convertFromISOLatin1 (String name) { - - int index = -1; - StringBuffer buf = new StringBuffer(name); - - while ((index = buf.toString().indexOf("\\U")) != -1){ - String str = "0000" + buf.toString().substring(index+2, index+6); - - // Convert Hexadecimal - byte[] buffer = new byte[(str.length() - 4) / 2]; - for (int i=4, j=0; i < str.length(); i +=2, j++) { - buffer[j] = (byte)((ORBUtility.hexOf(str.charAt(i)) << 4) & 0xF0); - buffer[j] |= (byte)((ORBUtility.hexOf(str.charAt(i+1)) << 0) & 0x0F); - } - buf = new StringBuffer(delete(buf.toString(), index, index+6)); - buf.insert(index, (char)buffer[1]); - } - - return buf.toString(); - - - } - - private static String delete(String str, int from, int to) - { - return str.substring(0, from) + str.substring(to, str.length()); - } - - private static String replace(String target, String arg, String source) - { - int i = 0; - i = target.indexOf(arg); - - while(i != -1) - { - String left = target.substring(0, i); - String right = target.substring(i+arg.length()); - target = new String(left+source+right); - i = target.indexOf(arg); - } - return target; - } - - public static int computeValueTag(boolean codeBasePresent, int typeInfo, boolean chunkedEncoding){ - int value_tag = kInitialValueTag; - - if (codeBasePresent) - value_tag = value_tag | 0x00000001; - - value_tag = value_tag | typeInfo; - - if (chunkedEncoding) - value_tag = value_tag | kChunkedMask; - - return value_tag; - } - - public static boolean isCodeBasePresent(int value_tag){ - return ((value_tag & 0x00000001) == 1); - } - - public static int getTypeInfo(int value_tag){ - return (value_tag & 0x00000006); - } - - public static boolean isChunkedEncoding(int value_tag){ - return ((value_tag & kChunkedMask) != 0); - } - - public static String getServerURL(){ - return defaultServerURL; - } - - /* - * Load a class and check that it is assignable to a given type. - * @param className the class name. - * @param remoteCodebase the codebase to use. May be null. - * @param loader the class loader of last resort. May be null. - * @param expectedType the expected type. May be null. - * @return the loaded class. - */ - private Class loadClassOfType (String className, - String remoteCodebase, - ClassLoader loader, - Class expectedType, - ClassLoader expectedTypeClassLoader) - throws ClassNotFoundException { - - Class loadedClass = null; - - try { - //Sequence finding of the stubs according to spec - try{ - //If-else is put here for speed up of J2EE. - //According to the OMG spec, the if clause is not dead code. - //It can occur if some compiler has allowed generation - //into org.omg.stub hierarchy for non-offending - //classes. This will encourage people to - //produce non-offending class stubs in their own hierarchy. - if(!PackagePrefixChecker - .hasOffendingPrefix(PackagePrefixChecker - .withoutPackagePrefix(className))){ - loadedClass = Util.loadClass - (PackagePrefixChecker.withoutPackagePrefix(className), - remoteCodebase, - loader); - } else { - loadedClass = Util.loadClass - (className, - remoteCodebase, - loader); - } - } catch (ClassNotFoundException cnfe) { - loadedClass = Util.loadClass - (className, - remoteCodebase, - loader); - } - if (expectedType == null) - return loadedClass; - } catch (ClassNotFoundException cnfe) { - if (expectedType == null) - throw cnfe; - } - - // If no class was not loaded, or if the loaded class is not of the - // correct type, make a further attempt to load the correct class - // using the classloader of the expected type. - // _REVISIT_ Is this step necessary, or should the Util,loadClass - // algorithm always produce a valid class if the setup is correct? - // Does the OMG standard algorithm need to be changed to include - // this step? - if (loadedClass == null || !expectedType.isAssignableFrom(loadedClass)) { - if (expectedType.getClassLoader() != expectedTypeClassLoader) - throw new IllegalArgumentException("expectedTypeClassLoader not class loader of expectedType."); - - if (expectedTypeClassLoader != null) - loadedClass = expectedTypeClassLoader.loadClass(className); - else - loadedClass = Class.forName(className); - } - - return loadedClass; - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3.java deleted file mode 100644 index 68b53c32c46..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2000, 2003, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -/* - * Licensed Materials - Property of IBM - * RMI-IIOP v1.0 - * Copyright IBM Corp. 1998 1999 All Rights Reserved - * - */ - -package com.sun.corba.se.impl.orbutil; - -import javax.rmi.CORBA.Util; -import javax.rmi.PortableRemoteObject; - -import java.util.Hashtable; -import java.util.Stack; -import java.io.IOException; -import java.util.EmptyStackException; - -import com.sun.corba.se.impl.util.Utility; -import com.sun.corba.se.impl.io.IIOPInputStream; -import com.sun.corba.se.impl.io.IIOPOutputStream; -import com.sun.corba.se.impl.util.RepositoryId; -import com.sun.corba.se.impl.util.Utility; - -import org.omg.CORBA.TCKind; -import org.omg.CORBA.MARSHAL; -import org.omg.CORBA.CompletionStatus; -import org.omg.CORBA.portable.IndirectionException; -import com.sun.org.omg.SendingContext.CodeBase; - -import java.security.AccessController; -import java.security.PrivilegedAction; - -/** - * This class overrides behavior of our current ValueHandlerImpl to - * provide backwards compatibility with JDK 1.3.0. - */ -public class ValueHandlerImpl_1_3 extends com.sun.corba.se.impl.io.ValueHandlerImpl { - - public ValueHandlerImpl_1_3(){ - super(); - } - - public ValueHandlerImpl_1_3(boolean isInputStream) { - super(isInputStream); - } - - /** - * Writes the value to the stream using java semantics. - * @param out The stream to write the value to - * @param value The value to be written to the stream - **/ - public void writeValue(org.omg.CORBA.portable.OutputStream _out, java.io.Serializable value) { - super.writeValue(_out, value); - } - - /** - * Reads a value from the stream using java semantics. - * @param in The stream to read the value from - * @param clazz The type of the value to be read in - * @param sender The sending context runtime - **/ - public java.io.Serializable readValue(org.omg.CORBA.portable.InputStream _in, - int offset, - java.lang.Class clazz, - String repositoryID, - org.omg.SendingContext.RunTime _sender) - { - return super.readValue(_in, offset, clazz, repositoryID, _sender); - } - - /** - * Returns the repository ID for the given RMI value Class. - * @param clz The class to return a repository ID for. - * @return the repository ID of the Class. - **/ - public java.lang.String getRMIRepositoryID(java.lang.Class clz) { - return RepositoryId_1_3.createForJavaType(clz); - } - - /** - * Indicates whether the given Class performs custom or - * default marshaling. - * @param clz The class to test for custom marshaling. - * @return True if the class performs custom marshaling, false - * if it does not. - **/ - public boolean isCustomMarshaled(java.lang.Class clz) { - return super.isCustomMarshaled(clz); - } - - /** - * Returns the CodeBase for this ValueHandler. This is used by - * the ORB runtime. The server sends the service context containing - * the IOR for this CodeBase on the first GIOP reply. The clients - * do the same on the first GIOP request. - * @return the SendingContext.CodeBase of this ValueHandler. - **/ - public org.omg.SendingContext.RunTime getRunTimeCodeBase() { - return super.getRunTimeCodeBase(); - } - - /** - * If the value contains a writeReplace method then the result - * is returned. Otherwise, the value itself is returned. - * @return the true value to marshal on the wire. - **/ - public java.io.Serializable writeReplace(java.io.Serializable value) { - return super.writeReplace(value); - } - - // methods supported for backward compatability so that the appropriate - // Rep-id calculations take place based on the ORB version - - /** - * Returns a boolean of whether or not RepositoryId indicates - * FullValueDescriptor. - * used for backward compatability - */ - - public boolean useFullValueDescription(Class clazz, String repositoryID) - throws IOException - - { - return RepositoryId_1_3.useFullValueDescription(clazz, repositoryID); - } - - public String getClassName(String id) - { - RepositoryId_1_3 repID = RepositoryId_1_3.cache.getId(id); - return repID.getClassName(); - } - - public Class getClassFromType(String id) - throws ClassNotFoundException - { - RepositoryId_1_3 repId = RepositoryId_1_3.cache.getId(id); - return repId.getClassFromType(); - } - - public Class getAnyClassFromType(String id) - throws ClassNotFoundException - { - RepositoryId_1_3 repId = RepositoryId_1_3.cache.getId(id); - return repId.getAnyClassFromType(); - } - - public String createForAnyType(Class cl) - { - return RepositoryId_1_3.createForAnyType(cl); - } - - public String getDefinedInId(String id) - { - RepositoryId_1_3 repId = RepositoryId_1_3.cache.getId(id); - return repId.getDefinedInId(); - } - - public String getUnqualifiedName(String id) - { - RepositoryId_1_3 repId = RepositoryId_1_3.cache.getId(id); - return repId.getUnqualifiedName(); - } - - public String getSerialVersionUID(String id) - { - RepositoryId_1_3 repId = RepositoryId_1_3.cache.getId(id); - return repId.getSerialVersionUID(); - } - - public boolean isAbstractBase(Class clazz) - { - return RepositoryId_1_3.isAbstractBase(clazz); - } - - public boolean isSequence(String id) - { - RepositoryId_1_3 repId = RepositoryId_1_3.cache.getId(id); - return repId.isSequence(); - } - - /** - * Preserves the incorrect 1.3 behavior which truncates Java chars in - * arrays to 8-bit CORBA chars. Bug 4367783. This enables us to - * continue interoperating with our legacy ORBs. If this goes into - * Ladybird, then Ladybird and Kestrel will interoperate as long as - * people don't use chars greater than 8-bits. - */ - protected void writeCharArray(org.omg.CORBA_2_3.portable.OutputStream out, - char[] array, - int offset, - int length) - { - out.write_char_array(array, offset, length); - } - - /** - * Preserves the incorrect 1.3 behavior which truncates Java chars in - * arrays to 8-bit CORBA chars. Bug 4367783. This enables us to - * continue interoperating with our legacy ORBs. If this goes into - * Ladybird, then Ladybird and Kestrel will interoperate as long as - * people don't use chars greater than 8-bits. - */ - protected void readCharArray(org.omg.CORBA_2_3.portable.InputStream in, - char[] array, - int offset, - int length) - { - in.read_char_array(array, offset, length); - } - - protected final String getOutputStreamClassName() { - return "com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3"; - } - - protected final String getInputStreamClassName() { - return "com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3"; - } - - /** - * Our JDK 1.3 and JDK 1.3.1 behavior subclasses override this. - * The correct behavior is for a Java char to map to a CORBA wchar, - * but our older code mapped it to a CORBA char. - */ - protected TCKind getJavaCharTCKind() { - return TCKind.tk_char; - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3_1.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3_1.java deleted file mode 100644 index 7309ec14c5e..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3_1.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2001, 2002, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.corba.se.impl.orbutil; - -import org.omg.CORBA.TCKind; - -/** - * This class overrides behavior of our current ValueHandlerImpl to - * provide backwards compatibility with JDK 1.3.1. - */ -public class ValueHandlerImpl_1_3_1 - extends com.sun.corba.se.impl.io.ValueHandlerImpl -{ - public ValueHandlerImpl_1_3_1() {} - - public ValueHandlerImpl_1_3_1(boolean isInputStream) { - super(isInputStream); - } - - /** - * Our JDK 1.3 and JDK 1.3.1 behavior subclasses override this. - * The correct behavior is for a Java char to map to a CORBA wchar, - * but our older code mapped it to a CORBA char. - */ - protected TCKind getJavaCharTCKind() { - return TCKind.tk_char; - } - - /** - * RepositoryId_1_3_1 performs an incorrect repId calculation - * when using serialPersistentFields and one of the fields no longer - * exists on the class itself. - */ - public boolean useFullValueDescription(Class clazz, String repositoryID) - throws java.io.IOException - { - return RepositoryId_1_3_1.useFullValueDescription(clazz, repositoryID); - } - - /** - * Installs the legacy IIOPOutputStream_1_3_1 which does - * PutFields/GetFields incorrectly. Bug 4407244. - */ - protected final String getOutputStreamClassName() { - return "com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3_1"; - } - - /** - * Installs the legacy IIOPInputStream_1_3_1 which does - * PutFields/GetFields incorrectly. Bug 4407244. - */ - protected final String getInputStreamClassName() { - return "com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3_1"; - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPInputStream_1_3_1.java b/corba/src/share/classes/sun/corba/JavaCorbaAccess.java similarity index 58% rename from corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPInputStream_1_3_1.java rename to corba/src/share/classes/sun/corba/JavaCorbaAccess.java index 1946f5e48e1..046453f2767 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPInputStream_1_3_1.java +++ b/corba/src/share/classes/sun/corba/JavaCorbaAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,32 +23,10 @@ * questions. */ -/* - */ -package com.sun.corba.se.impl.orbutil; +package sun.corba; -import java.io.*; -import java.util.Hashtable; +import com.sun.corba.se.impl.io.ValueHandlerImpl; -/** - * Implements legacy behavior from Ladybird to maintain - * backwards compatibility. - */ -public class IIOPInputStream_1_3_1 extends com.sun.corba.se.impl.io.IIOPInputStream -{ - public IIOPInputStream_1_3_1() - throws java.io.IOException { - super(); - } - - /** - * Before JDK 1.3.1_01, the PutField/GetField implementation - * actually sent a Hashtable. - */ - public ObjectInputStream.GetField readFields() - throws IOException, ClassNotFoundException, NotActiveException { - - Hashtable fields = (Hashtable)readObject(); - return new LegacyHookGetFields(fields); - } +public interface JavaCorbaAccess { + public ValueHandlerImpl newValueHandlerImpl(); } diff --git a/corba/src/share/classes/sun/corba/SharedSecrets.java b/corba/src/share/classes/sun/corba/SharedSecrets.java new file mode 100644 index 00000000000..aba3ee0767a --- /dev/null +++ b/corba/src/share/classes/sun/corba/SharedSecrets.java @@ -0,0 +1,60 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.corba; + +import com.sun.corba.se.impl.io.ValueUtility; +import sun.misc.Unsafe; + +import java.security.AccessController; + +/** A repository of "shared secrets", which are a mechanism for + calling implementation-private methods in another package without + using reflection. A package-private class implements a public + interface and provides the ability to call package-private methods + within that package; the object implementing that interface is + provided through a third package to which access is restricted. + This framework avoids the primary disadvantage of using reflection + for this purpose, namely the loss of compile-time checking. */ + +// SharedSecrets cloned in corba repo to avoid build issues +public class SharedSecrets { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static JavaCorbaAccess javaCorbaAccess; + + public static JavaCorbaAccess getJavaCorbaAccess() { + if (javaCorbaAccess == null) { + // Ensure ValueUtility is initialized; we know that that class + // provides the shared secret + unsafe.ensureClassInitialized(ValueUtility.class); + } + return javaCorbaAccess; + } + + public static void setJavaCorbaAccess(JavaCorbaAccess access) { + javaCorbaAccess = access; + } + +} From f50507bccf9128588567a6d1050f75be6afb1331 Mon Sep 17 00:00:00 2001 From: Neil Richards Date: Tue, 30 Oct 2012 17:15:13 +0000 Subject: [PATCH 017/180] 8000540: Improve IIOP type reuse management Reviewed-by: alanb, ahgross, coffeys --- .../corba/se/impl/io/ObjectStreamClass.java | 110 +++++++----------- 1 file changed, 39 insertions(+), 71 deletions(-) diff --git a/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java b/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java index c2e23a41387..95412a11257 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -25,7 +25,7 @@ /* * Licensed Materials - Property of IBM * RMI-IIOP v1.0 - * Copyright IBM Corp. 1998 1999 All Rights Reserved + * Copyright IBM Corp. 1998 2012 All Rights Reserved * */ @@ -56,7 +56,6 @@ import java.io.Serializable; import java.util.Arrays; import java.util.Comparator; -import java.util.Hashtable; import com.sun.corba.se.impl.util.RepositoryId; @@ -83,8 +82,6 @@ public class ObjectStreamClass implements java.io.Serializable { private static Object noArgsList[] = {}; private static Class noTypesList[] = {}; - private static Hashtable translatedFields; - /** true if represents enum type */ private boolean isEnum; @@ -384,6 +381,42 @@ public class ObjectStreamClass implements java.io.Serializable { */ } + private static final class PersistentFieldsValue + extends ClassValue { + PersistentFieldsValue() { } + + protected ObjectStreamField[] computeValue(Class type) { + try { + Field pf = type.getDeclaredField("serialPersistentFields"); + int mods = pf.getModifiers(); + if (Modifier.isPrivate(mods) && Modifier.isStatic(mods) && + Modifier.isFinal(mods)) { + pf.setAccessible(true); + java.io.ObjectStreamField[] fields = + (java.io.ObjectStreamField[])pf.get(type); + return translateFields(fields); + } + } catch (NoSuchFieldException | IllegalAccessException | + IllegalArgumentException | ClassCastException e) { + } + return null; + } + + private static ObjectStreamField[] translateFields( + java.io.ObjectStreamField[] fields) { + ObjectStreamField[] translation = + new ObjectStreamField[fields.length]; + for (int i = 0; i < fields.length; i++) { + translation[i] = new ObjectStreamField(fields[i].getName(), + fields[i].getType()); + } + return translation; + } + } + + private static final PersistentFieldsValue persistentFieldsValue = + new PersistentFieldsValue(); + /* * Initialize class descriptor. This method is only invoked on class * descriptors created via calls to lookupInternal(). This method is kept @@ -416,35 +449,7 @@ public class ObjectStreamClass implements java.io.Serializable { * If it is declared, use the declared serialPersistentFields. * Otherwise, extract the fields from the class itself. */ - try { - Field pf = cl.getDeclaredField("serialPersistentFields"); - // serial bug 7; the serialPersistentFields were not - // being read and stored as Accessible bit was not set - pf.setAccessible(true); - // serial bug 7; need to find if the field is of type - // java.io.ObjectStreamField - java.io.ObjectStreamField[] f = - (java.io.ObjectStreamField[])pf.get(cl); - int mods = pf.getModifiers(); - if ((Modifier.isPrivate(mods)) && - (Modifier.isStatic(mods)) && - (Modifier.isFinal(mods))) - { - fields = (ObjectStreamField[])translateFields((Object[])pf.get(cl)); - } - } catch (NoSuchFieldException e) { - fields = null; - } catch (IllegalAccessException e) { - fields = null; - } catch (IllegalArgumentException e) { - fields = null; - } catch (ClassCastException e) { - /* Thrown if a field serialPersistentField exists - * but it is not of type ObjectStreamField. - */ - fields = null; - } - + fields = persistentFieldsValue.get(cl); if (fields == null) { /* Get all of the declared fields for this @@ -641,43 +646,6 @@ public class ObjectStreamClass implements java.io.Serializable { superclass = null; } - private static Object[] translateFields(Object objs[]) - throws NoSuchFieldException { - try{ - java.io.ObjectStreamField fields[] = (java.io.ObjectStreamField[])objs; - Object translation[] = null; - - if (translatedFields == null) - translatedFields = new Hashtable(); - - translation = (Object[])translatedFields.get(fields); - - if (translation != null) - return translation; - else { - Class osfClass = Class.forName("com.sun.corba.se.impl.io.ObjectStreamField"); - translation = (Object[])java.lang.reflect.Array.newInstance(osfClass, objs.length); - Object arg[] = new Object[2]; - Class types[] = {String.class, Class.class}; - Constructor constructor = osfClass.getDeclaredConstructor(types); - for (int i = fields.length -1; i >= 0; i--){ - arg[0] = fields[i].getName(); - arg[1] = fields[i].getType(); - - translation[i] = constructor.newInstance(arg); - } - translatedFields.put(fields, translation); - - } - - return (Object[])translation; - } - catch(Throwable t){ - NoSuchFieldException nsfe = new NoSuchFieldException(); - nsfe.initCause( t ) ; - throw nsfe ; - } - } /* * Set the class this version descriptor matches. From d3ccd20d1fc444e6ea7b314d5aaf23a718ab5054 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Fri, 2 Nov 2012 16:50:23 -0700 Subject: [PATCH 018/180] 7197546: (proxy) Reflect about creating reflective proxies Reviewed-by: alanb, jdn, jrose --- jdk/src/share/classes/java/lang/Class.java | 50 +++--- .../java/lang/invoke/MethodHandleProxies.java | 73 ++++++--- .../classes/java/lang/reflect/Proxy.java | 154 +++++++++++++++++- .../classes/sun/reflect/misc/ReflectUtil.java | 25 +++ .../loadProxyClasses/security.policy | 1 + 5 files changed, 254 insertions(+), 49 deletions(-) diff --git a/jdk/src/share/classes/java/lang/Class.java b/jdk/src/share/classes/java/lang/Class.java index ec9d9725655..a22493feb6f 100644 --- a/jdk/src/share/classes/java/lang/Class.java +++ b/jdk/src/share/classes/java/lang/Class.java @@ -60,7 +60,9 @@ import sun.reflect.generics.repository.ConstructorRepository; import sun.reflect.generics.scope.ClassScope; import sun.security.util.SecurityConstants; import java.lang.annotation.Annotation; +import java.lang.reflect.Proxy; import sun.reflect.annotation.*; +import sun.reflect.misc.ReflectUtil; /** * Instances of the class {@code Class} represent classes and @@ -247,11 +249,11 @@ public final ClassLoader loader) throws ClassNotFoundException { - if (loader == null) { + if (sun.misc.VM.isSystemDomainLoader(loader)) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { ClassLoader ccl = ClassLoader.getCallerClassLoader(); - if (ccl != null) { + if (!sun.misc.VM.isSystemDomainLoader(ccl)) { sm.checkPermission( SecurityConstants.GET_CLASSLOADER_PERMISSION); } @@ -316,7 +318,7 @@ public final throws InstantiationException, IllegalAccessException { if (System.getSecurityManager() != null) { - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), false); } return newInstance0(); } @@ -1295,7 +1297,7 @@ public final // be very careful not to change the stack depth of this // checkMemberAccess call for security reasons // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), false); // Privileged so this implementation can look at DECLARED classes, // something the caller might not have privilege to do. The code here @@ -1370,7 +1372,7 @@ public final // be very careful not to change the stack depth of this // checkMemberAccess call for security reasons // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); return copyFields(privateGetPublicFields(null)); } @@ -1421,7 +1423,7 @@ public final // be very careful not to change the stack depth of this // checkMemberAccess call for security reasons // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); return copyMethods(privateGetPublicMethods()); } @@ -1470,7 +1472,7 @@ public final // be very careful not to change the stack depth of this // checkMemberAccess call for security reasons // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); return copyConstructors(privateGetDeclaredConstructors(true)); } @@ -1529,7 +1531,7 @@ public final // be very careful not to change the stack depth of this // checkMemberAccess call for security reasons // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); Field field = getField0(name); if (field == null) { throw new NoSuchFieldException(name); @@ -1614,7 +1616,7 @@ public final // be very careful not to change the stack depth of this // checkMemberAccess call for security reasons // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); Method method = getMethod0(name, parameterTypes); if (method == null) { throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); @@ -1668,7 +1670,7 @@ public final // be very careful not to change the stack depth of this // checkMemberAccess call for security reasons // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), true); return getConstructor0(parameterTypes, Member.PUBLIC); } @@ -1710,7 +1712,7 @@ public final // be very careful not to change the stack depth of this // checkMemberAccess call for security reasons // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader()); + checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), false); return getDeclaredClasses0(); } @@ -1754,7 +1756,7 @@ public final // be very careful not to change the stack depth of this // checkMemberAccess call for security reasons // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader()); + checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); return copyFields(privateGetDeclaredFields(false)); } @@ -1802,7 +1804,7 @@ public final // be very careful not to change the stack depth of this // checkMemberAccess call for security reasons // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader()); + checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); return copyMethods(privateGetDeclaredMethods(false)); } @@ -1847,7 +1849,7 @@ public final // be very careful not to change the stack depth of this // checkMemberAccess call for security reasons // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader()); + checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); return copyConstructors(privateGetDeclaredConstructors(false)); } @@ -1891,7 +1893,7 @@ public final // be very careful not to change the stack depth of this // checkMemberAccess call for security reasons // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader()); + checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); Field field = searchFields(privateGetDeclaredFields(false), name); if (field == null) { throw new NoSuchFieldException(name); @@ -1946,7 +1948,7 @@ public final // be very careful not to change the stack depth of this // checkMemberAccess call for security reasons // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader()); + checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes); if (method == null) { throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); @@ -1996,7 +1998,7 @@ public final // be very careful not to change the stack depth of this // checkMemberAccess call for security reasons // see java.lang.SecurityManager.checkMemberAccess - checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader()); + checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader(), true); return getConstructor0(parameterTypes, Member.DECLARED); } @@ -2166,18 +2168,26 @@ public final *

Default policy: allow all clients access with normal Java access * control. */ - private void checkMemberAccess(int which, ClassLoader ccl) { + private void checkMemberAccess(int which, ClassLoader ccl, boolean checkProxyInterfaces) { SecurityManager s = System.getSecurityManager(); if (s != null) { s.checkMemberAccess(this, which); ClassLoader cl = getClassLoader0(); - if (sun.reflect.misc.ReflectUtil.needsPackageAccessCheck(ccl, cl)) { + if (ReflectUtil.needsPackageAccessCheck(ccl, cl)) { String name = this.getName(); int i = name.lastIndexOf('.'); if (i != -1) { - s.checkPackageAccess(name.substring(0, i)); + // skip the package access check on a proxy class in default proxy package + String pkg = name.substring(0, i); + if (!Proxy.isProxyClass(this) || !pkg.equals(ReflectUtil.PROXY_PACKAGE)) { + s.checkPackageAccess(pkg); + } } } + // check package access on the proxy interfaces + if (checkProxyInterfaces && Proxy.isProxyClass(this)) { + ReflectUtil.checkProxyPackageAccess(ccl, this.getInterfaces()); + } } } diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java index 8e068238b1f..e305ced7de4 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java @@ -26,8 +26,12 @@ package java.lang.invoke; import java.lang.reflect.*; +import java.security.AccessController; +import java.security.PrivilegedAction; import sun.invoke.WrapperInstance; import java.util.ArrayList; +import sun.reflect.Reflection; +import sun.reflect.misc.ReflectUtil; /** * This class consists exclusively of static methods that help adapt @@ -137,6 +141,18 @@ public class MethodHandleProxies { T asInterfaceInstance(final Class intfc, final MethodHandle target) { if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers())) throw new IllegalArgumentException("not a public interface: "+intfc.getName()); + SecurityManager smgr = System.getSecurityManager(); + if (smgr != null) { + final int CALLER_FRAME = 2; // 0: Reflection, 1: asInterfaceInstance, 2: caller + final Class caller = Reflection.getCallerClass(CALLER_FRAME); + final ClassLoader ccl = caller.getClassLoader(); + ReflectUtil.checkProxyPackageAccess(ccl, intfc); + } + ClassLoader proxyLoader = intfc.getClassLoader(); + if (proxyLoader == null) { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); // avoid use of BCP + proxyLoader = cl != null ? cl : ClassLoader.getSystemClassLoader(); + } final Method[] methods = getSingleNameMethods(intfc); if (methods == null) throw new IllegalArgumentException("not a single-method interface: "+intfc.getName()); @@ -148,27 +164,44 @@ public class MethodHandleProxies { checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class)); vaTargets[i] = checkTarget.asSpreader(Object[].class, smMT.parameterCount()); } - return intfc.cast(Proxy.newProxyInstance( - intfc.getClassLoader(), - new Class[]{ intfc, WrapperInstance.class }, - new InvocationHandler() { - private Object getArg(String name) { - if ((Object)name == "getWrapperInstanceTarget") return target; - if ((Object)name == "getWrapperInstanceType") return intfc; - throw new AssertionError(); + final InvocationHandler ih = new InvocationHandler() { + private Object getArg(String name) { + if ((Object)name == "getWrapperInstanceTarget") return target; + if ((Object)name == "getWrapperInstanceType") return intfc; + throw new AssertionError(); + } + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + for (int i = 0; i < methods.length; i++) { + if (method.equals(methods[i])) + return vaTargets[i].invokeExact(args); } - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - for (int i = 0; i < methods.length; i++) { - if (method.equals(methods[i])) - return vaTargets[i].invokeExact(args); - } - if (method.getDeclaringClass() == WrapperInstance.class) - return getArg(method.getName()); - if (isObjectMethod(method)) - return callObjectMethod(proxy, method, args); - throw new InternalError("bad proxy method: "+method); - } - })); + if (method.getDeclaringClass() == WrapperInstance.class) + return getArg(method.getName()); + if (isObjectMethod(method)) + return callObjectMethod(proxy, method, args); + throw new InternalError("bad proxy method: "+method); + } + }; + + Object proxy; + if (smgr != null) { + // sun.invoke.WrapperInstance is a restricted interface not accessible + // by any non-null class loader. + final ClassLoader loader = proxyLoader; + proxy = AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return Proxy.newProxyInstance( + loader, + new Class[]{ intfc, WrapperInstance.class }, + ih); + } + }); + } else { + proxy = Proxy.newProxyInstance(proxyLoader, + new Class[]{ intfc, WrapperInstance.class }, + ih); + } + return intfc.cast(proxy); } /** diff --git a/jdk/src/share/classes/java/lang/reflect/Proxy.java b/jdk/src/share/classes/java/lang/reflect/Proxy.java index c2420915031..d7299b20dbb 100644 --- a/jdk/src/share/classes/java/lang/reflect/Proxy.java +++ b/jdk/src/share/classes/java/lang/reflect/Proxy.java @@ -27,6 +27,9 @@ package java.lang.reflect; import java.lang.ref.Reference; import java.lang.ref.WeakReference; +import java.security.AccessController; +import java.security.Permission; +import java.security.PrivilegedAction; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -36,6 +39,9 @@ import java.util.Set; import java.util.List; import java.util.WeakHashMap; import sun.misc.ProxyGenerator; +import sun.reflect.Reflection; +import sun.reflect.misc.ReflectUtil; +import sun.security.util.SecurityConstants; /** * {@code Proxy} provides static methods for creating dynamic proxy @@ -265,9 +271,69 @@ public class Proxy implements java.io.Serializable { * @param h the invocation handler for this proxy instance */ protected Proxy(InvocationHandler h) { + doNewInstanceCheck(); this.h = h; } + private static class ProxyAccessHelper { + // The permission is implementation specific. + static final Permission PROXY_PERMISSION = + new ReflectPermission("proxyConstructorNewInstance"); + // These system properties are defined to provide a short-term + // workaround if customers need to disable the new security checks. + static final boolean allowNewInstance; + static final boolean allowNullLoader; + static { + allowNewInstance = getBooleanProperty("sun.reflect.proxy.allowsNewInstance"); + allowNullLoader = getBooleanProperty("sun.reflect.proxy.allowsNullLoader"); + } + + private static boolean getBooleanProperty(final String key) { + String s = AccessController.doPrivileged(new PrivilegedAction() { + public String run() { + return System.getProperty(key); + } + }); + return Boolean.valueOf(s); + } + + static boolean needsNewInstanceCheck(Class proxyClass) { + if (!Proxy.isProxyClass(proxyClass) || allowNewInstance) { + return false; + } + + if (proxyClass.getName().startsWith(ReflectUtil.PROXY_PACKAGE + ".")) { + // all proxy interfaces are public + return false; + } + for (Class intf : proxyClass.getInterfaces()) { + if (!Modifier.isPublic(intf.getModifiers())) { + return true; + } + } + return false; + } + } + + /* + * Access check on a proxy class that implements any non-public interface. + * + * @throws SecurityException if a security manager exists, and + * the caller does not have the permission. + */ + private void doNewInstanceCheck() { + SecurityManager sm = System.getSecurityManager(); + Class proxyClass = this.getClass(); + if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(proxyClass)) { + try { + sm.checkPermission(ProxyAccessHelper.PROXY_PERMISSION); + } catch (SecurityException e) { + throw new SecurityException("Not allowed to construct a Proxy " + + "instance that implements a non-public interface", e); + } + } + } + /** * Returns the {@code java.lang.Class} object for a proxy class * given a class loader and an array of interfaces. The proxy class @@ -346,6 +412,51 @@ public class Proxy implements java.io.Serializable { Class... interfaces) throws IllegalArgumentException { + return getProxyClass0(loader, interfaces); // stack walk magic: do not refactor + } + + private static void checkProxyLoader(ClassLoader ccl, + ClassLoader loader) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + if (loader == null && ccl != null) { + if (!ProxyAccessHelper.allowNullLoader) { + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + } + } + } + + /* + * Generate a proxy class (caller-sensitive). + * + * To define a proxy class, it performs the access checks as in + * Class.forName (VM will invoke ClassLoader.checkPackageAccess): + * 1. "getClassLoader" permission check if loader == null + * 2. checkPackageAccess on the interfaces it implements + * + * To get a constructor and new instance of a proxy class, it performs + * the package access check on the interfaces it implements + * as in Class.getConstructor. + * + * If an interface is non-public, the proxy class must be defined by + * the defining loader of the interface. If the caller's class loader + * is not the same as the defining loader of the interface, the VM + * will throw IllegalAccessError when the generated proxy class is + * being defined via the defineClass0 method. + */ + private static Class getProxyClass0(ClassLoader loader, + Class... interfaces) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + final int CALLER_FRAME = 3; // 0: Reflection, 1: getProxyClass0 2: Proxy 3: caller + final Class caller = Reflection.getCallerClass(CALLER_FRAME); + final ClassLoader ccl = caller.getClassLoader(); + checkProxyLoader(ccl, loader); + ReflectUtil.checkProxyPackageAccess(ccl, interfaces); + } + if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } @@ -497,8 +608,9 @@ public class Proxy implements java.io.Serializable { } } - if (proxyPkg == null) { // if no non-public proxy interfaces, - proxyPkg = ""; // use the unnamed package + if (proxyPkg == null) { + // if no non-public proxy interfaces, use sun.proxy package + proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } { @@ -598,22 +710,46 @@ public class Proxy implements java.io.Serializable { /* * Look up or generate the designated proxy class. */ - Class cl = getProxyClass(loader, interfaces); + Class cl = getProxyClass0(loader, interfaces); // stack walk magic: do not refactor /* * Invoke its constructor with the designated invocation handler. */ try { - Constructor cons = cl.getConstructor(constructorParams); - return cons.newInstance(new Object[] { h }); - } catch (NoSuchMethodException | - IllegalAccessException | - InstantiationException | - InvocationTargetException e) { + final Constructor cons = cl.getConstructor(constructorParams); + final InvocationHandler ih = h; + SecurityManager sm = System.getSecurityManager(); + if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { + // create proxy instance with doPrivilege as the proxy class may + // implement non-public interfaces that requires a special permission + return AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return newInstance(cons, ih); + } + }); + } else { + return newInstance(cons, ih); + } + } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } } + private static Object newInstance(Constructor cons, InvocationHandler h) { + try { + return cons.newInstance(new Object[] {h} ); + } catch (IllegalAccessException | InstantiationException e) { + throw new InternalError(e.toString(), e); + } catch (InvocationTargetException e) { + Throwable t = e.getCause(); + if (t instanceof RuntimeException) { + throw (RuntimeException) t; + } else { + throw new InternalError(t.toString(), t); + } + } + } + /** * Returns true if and only if the specified class was dynamically * generated to be a proxy class using the {@code getProxyClass} diff --git a/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java b/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java index 5a90c28db41..06956101dcc 100644 --- a/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java +++ b/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java @@ -178,4 +178,29 @@ public final class ReflectUtil { return !isAncestor(from, to); } + + /** + * Access check on the interfaces that a proxy class implements and throw + * {@code SecurityException} if it accesses a restricted package. + * + * @param ccl the caller's class loader + * @param interfaces the list of interfaces that a proxy class implements + * + * @see Proxy#checkProxyAccess + */ + public static void checkProxyPackageAccess(ClassLoader ccl, + Class... interfaces) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + for (Class intf : interfaces) { + ClassLoader cl = intf.getClassLoader(); + if (needsPackageAccessCheck(ccl, cl)) { + checkPackageAccess(intf); + } + } + } + } + + public static final String PROXY_PACKAGE = "sun.proxy"; } diff --git a/jdk/test/java/rmi/server/RMIClassLoader/loadProxyClasses/security.policy b/jdk/test/java/rmi/server/RMIClassLoader/loadProxyClasses/security.policy index f6e312ec696..3ba44491aca 100644 --- a/jdk/test/java/rmi/server/RMIClassLoader/loadProxyClasses/security.policy +++ b/jdk/test/java/rmi/server/RMIClassLoader/loadProxyClasses/security.policy @@ -13,6 +13,7 @@ grant { permission java.io.FilePermission ".${/}-", "read,write,delete"; permission java.lang.RuntimePermission "createClassLoader"; + permission java.lang.RuntimePermission "getClassLoader"; permission java.lang.RuntimePermission "setContextClassLoader"; // used by TestLibrary to determine test environment From c1be65b49cbc31b30dfe6fac38a2459cee7c75fb Mon Sep 17 00:00:00 2001 From: Keith McGuigan Date: Mon, 5 Nov 2012 17:03:33 -0500 Subject: [PATCH 019/180] 8001307: Modify ACC_SUPER behavior Disallow non-virtual calls even when ACC_SUPER is absent. Reviewed-by: kvn, acorn --- hotspot/src/share/vm/interpreter/linkResolver.cpp | 2 +- hotspot/src/share/vm/runtime/globals.hpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index c794f06e175..c77d27189a2 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp @@ -786,7 +786,7 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, methodHandle if (check_access && // a) check if ACC_SUPER flag is set for the current class - current_klass->is_super() && + (current_klass->is_super() || !AllowNonVirtualCalls) && // b) check if the method class is a superclass of the current class (superclass relation is not reflexive!) current_klass->is_subtype_of(method_klass()) && current_klass() != method_klass() && // c) check if the method is not diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index e783883ebe0..f3a75e31d00 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -3602,7 +3602,10 @@ class CommandLineFlags { "Enable internal testing APIs") \ \ product(bool, PrintGCCause, true, \ - "Include GC cause in GC logging") + "Include GC cause in GC logging") \ + \ + product(bool, AllowNonVirtualCalls, false, \ + "Obey the ACC_SUPER flag and allow invokenonvirtual calls") /* * Macros for factoring of globals From ec9f5edf2ffc128e326fe56b056c6bfa45c7532e Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Tue, 6 Nov 2012 15:30:34 +0400 Subject: [PATCH 020/180] 7200491: Tighten up JTable layout code Reviewed-by: art, skoivu --- jdk/src/share/classes/javax/swing/JTable.java | 14 +++++--------- .../javax/swing/plaf/nimbus/NimbusLookAndFeel.java | 7 ++++++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/jdk/src/share/classes/javax/swing/JTable.java b/jdk/src/share/classes/javax/swing/JTable.java index fbd61d9a9fc..05fc918e9eb 100644 --- a/jdk/src/share/classes/javax/swing/JTable.java +++ b/jdk/src/share/classes/javax/swing/JTable.java @@ -781,15 +781,11 @@ public class JTable extends JComponent implements TableModelListener, Scrollable scrollPane.getCorner(JScrollPane.UPPER_TRAILING_CORNER); if (corner == null || corner instanceof UIResource){ corner = null; - Object componentClass = UIManager.get( - "Table.scrollPaneCornerComponent"); - if (componentClass instanceof Class){ - try { - corner = (Component) - ((Class)componentClass).newInstance(); - } catch (Exception e) { - // just ignore and don't set corner - } + try { + corner = (Component) UIManager.get( + "Table.scrollPaneCornerComponent"); + } catch (Exception e) { + // just ignore and don't set corner } scrollPane.setCorner(JScrollPane.UPPER_TRAILING_CORNER, corner); diff --git a/jdk/src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java b/jdk/src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java index b03bf653fc5..402a6885982 100644 --- a/jdk/src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java +++ b/jdk/src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java @@ -159,7 +159,12 @@ public class NimbusLookAndFeel extends SynthLookAndFeel { // Store Table ScrollPane Corner Component uiDefaults.put("Table.scrollPaneCornerComponent", - TableScrollPaneCorner.class); + new UIDefaults.ActiveValue() { + @Override + public Object createValue(UIDefaults table) { + return new TableScrollPaneCorner(); + } + }); // Setup the settings for ToolBarSeparator which is custom // installed for Nimbus From e3b2bdd16f1cc4e8618b53866a51cadce6e26c47 Mon Sep 17 00:00:00 2001 From: Mala Bankal Date: Mon, 17 Dec 2012 07:43:20 -0800 Subject: [PATCH 021/180] 7141694: Improving CORBA internals Reviewed-by: coffeys, ahgross --- .../classes/com/sun/corba/se/spi/orb/ORB.java | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java b/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java index 22b89e73f22..306a9f7d2bf 100644 --- a/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java +++ b/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java @@ -98,6 +98,7 @@ import com.sun.corba.se.impl.logging.OMGSystemException ; import com.sun.corba.se.impl.presentation.rmi.PresentationManagerImpl ; import com.sun.corba.se.impl.orbutil.ORBClassLoader ; +import sun.awt.AppContext; public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB implements Broker, TypeCodeFactory @@ -173,14 +174,7 @@ public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB protected MonitoringManager monitoringManager; - // There is only one instance of the PresentationManager - // that is shared between all ORBs. This is necessary - // because RMI-IIOP requires the PresentationManager in - // places where no ORB is available, so the PresentationManager - // must be global. It is initialized here as well. - protected static PresentationManager globalPM = null ; - - static { + private static PresentationManager setupPresentationManager() { staticWrapper = ORBUtilSystemException.get( CORBALogDomains.RPC_PRESENTATION ) ; @@ -220,10 +214,11 @@ public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB } ) ; - globalPM = new PresentationManagerImpl( useDynamicStub ) ; - globalPM.setStubFactoryFactory( false, + PresentationManager pm = new PresentationManagerImpl( useDynamicStub ) ; + pm.setStubFactoryFactory( false, PresentationDefaults.getStaticStubFactoryFactory() ) ; - globalPM.setStubFactoryFactory( true, dynamicStubFactoryFactory ) ; + pm.setStubFactoryFactory( true, dynamicStubFactoryFactory ) ; + return pm; } public void destroy() { @@ -234,11 +229,19 @@ public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB byteBufferPool = null; } - /** Get the single instance of the PresentationManager + /** + * Returns the Presentation Manager for the current thread group, using the ThreadGroup-specific + * AppContext to hold it. Creates and records one if needed. */ public static PresentationManager getPresentationManager() { - return globalPM ; + AppContext ac = AppContext.getAppContext(); + PresentationManager pm = (PresentationManager) ac.get(PresentationManager.class); + if (pm == null) { + pm = setupPresentationManager(); + ac.put(PresentationManager.class, pm); + } + return pm; } /** Get the appropriate StubFactoryFactory. This @@ -248,8 +251,9 @@ public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB public static PresentationManager.StubFactoryFactory getStubFactoryFactory() { - boolean useDynamicStubs = globalPM.useDynamicStubs() ; - return globalPM.getStubFactoryFactory( useDynamicStubs ) ; + PresentationManager gPM = getPresentationManager(); + boolean useDynamicStubs = gPM.useDynamicStubs() ; + return gPM.getStubFactoryFactory( useDynamicStubs ) ; } protected ORB() From 8e50f0daf950c6be4cf322c635c92b1ee5d57fde Mon Sep 17 00:00:00 2001 From: Sean Coffey Date: Tue, 6 Nov 2012 15:50:14 +0000 Subject: [PATCH 022/180] 7201066: Change modifiers on unused fields Reviewed-by: alanb, skoivu --- .../com/sun/corba/se/impl/activation/ServerMain.java | 8 ++++---- .../com/sun/corba/se/impl/io/ObjectStreamClass.java | 4 ++-- .../corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/corba/src/share/classes/com/sun/corba/se/impl/activation/ServerMain.java b/corba/src/share/classes/com/sun/corba/se/impl/activation/ServerMain.java index c51b08966bd..cd6d534af49 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/activation/ServerMain.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/activation/ServerMain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -322,9 +322,9 @@ class ServerCallback extends com.sun.corba.se.spi.activation._ServerImplBase { private ORB orb; - private Method installMethod ; - private Method uninstallMethod ; - private Method shutdownMethod ; + private transient Method installMethod ; + private transient Method uninstallMethod ; + private transient Method shutdownMethod ; private Object methodArgs[] ; ServerCallback(ORB orb, Method installMethod, Method uninstallMethod, diff --git a/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java b/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java index 95412a11257..2c6e3bc08bb 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java @@ -1523,8 +1523,8 @@ public class ObjectStreamClass implements java.io.Serializable { private boolean hasExternalizableBlockData; Method writeObjectMethod; Method readObjectMethod; - private Method writeReplaceObjectMethod; - private Method readResolveObjectMethod; + private transient Method writeReplaceObjectMethod; + private transient Method readResolveObjectMethod; private Constructor cons ; /** diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java index c9a6f8f1d51..891a4887123 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -1119,8 +1119,8 @@ public class ObjectStreamClass_1_3_1 implements java.io.Serializable { private boolean hasExternalizableBlockData; Method writeObjectMethod; Method readObjectMethod; - private Method writeReplaceObjectMethod; - private Method readResolveObjectMethod; + private transient Method writeReplaceObjectMethod; + private transient Method readResolveObjectMethod; /* * ObjectStreamClass_1_3_1 that this one was built from. From 90f2168fa25b2cf418cfd789161daa0ae4e38400 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Wed, 7 Nov 2012 14:26:41 +0000 Subject: [PATCH 023/180] 7201071: InetSocketAddress serialization issue Reviewed-by: alanb, michaelm, skoivu --- .../classes/java/net/InetSocketAddress.java | 272 ++++++++++++------ .../sun/nio/ch/DatagramChannelImpl.java | 18 +- .../sun/nio/ch/sctp/SctpChannelImpl.java | 14 +- .../sun/nio/ch/sctp/SctpMultiChannelImpl.java | 16 +- .../native/sun/nio/ch/DatagramChannelImpl.c | 9 +- .../native/sun/nio/ch/sctp/SctpChannelImpl.c | 27 +- .../native/sun/nio/ch/DatagramChannelImpl.c | 10 +- .../DatagramChannel/SendToUnresolved.java | 2 +- 8 files changed, 225 insertions(+), 143 deletions(-) diff --git a/jdk/src/share/classes/java/net/InetSocketAddress.java b/jdk/src/share/classes/java/net/InetSocketAddress.java index b250b18ce5a..d4322e9b427 100644 --- a/jdk/src/share/classes/java/net/InetSocketAddress.java +++ b/jdk/src/share/classes/java/net/InetSocketAddress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -24,9 +24,12 @@ */ package java.net; -import java.io.ObjectInputStream; import java.io.IOException; import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.ObjectStreamField; /** * @@ -46,23 +49,105 @@ import java.io.InvalidObjectException; * @see java.net.ServerSocket * @since 1.4 */ -public class InetSocketAddress extends SocketAddress { - /* The hostname of the Socket Address - * @serial - */ - private String hostname = null; - /* The IP address of the Socket Address - * @serial - */ - private InetAddress addr = null; - /* The port number of the Socket Address - * @serial - */ - private int port; +public class InetSocketAddress + extends SocketAddress +{ + // Private implementation class pointed to by all public methods. + private static class InetSocketAddressHolder { + // The hostname of the Socket Address + private String hostname; + // The IP address of the Socket Address + private InetAddress addr; + // The port number of the Socket Address + private int port; + + private InetSocketAddressHolder(String hostname, InetAddress addr, int port) { + this.hostname = hostname; + this.addr = addr; + this.port = port; + } + + private int getPort() { + return port; + } + + private InetAddress getAddress() { + return addr; + } + + private String getHostName() { + if (hostname != null) + return hostname; + if (addr != null) + return addr.getHostName(); + return null; + } + + private String getHostString() { + if (hostname != null) + return hostname; + if (addr != null) { + if (addr.hostName != null) + return addr.hostName; + else + return addr.getHostAddress(); + } + return null; + } + + private boolean isUnresolved() { + return addr == null; + } + + @Override + public String toString() { + if (isUnresolved()) { + return hostname + ":" + port; + } else { + return addr.toString() + ":" + port; + } + } + + @Override + public final boolean equals(Object obj) { + if (obj == null || !(obj instanceof InetSocketAddressHolder)) + return false; + InetSocketAddressHolder that = (InetSocketAddressHolder)obj; + boolean sameIP; + if (addr != null) + sameIP = addr.equals(that.addr); + else if (hostname != null) + sameIP = (that.addr == null) && + hostname.equalsIgnoreCase(that.hostname); + else + sameIP = (that.addr == null) && (that.hostname == null); + return sameIP && (port == that.port); + } + + @Override + public final int hashCode() { + if (addr != null) + return addr.hashCode() + port; + if (hostname != null) + return hostname.toLowerCase().hashCode() + port; + return port; + } + } + + private final transient InetSocketAddressHolder holder; private static final long serialVersionUID = 5076001401234631237L; - private InetSocketAddress() { + private static int checkPort(int port) { + if (port < 0 || port > 0xFFFF) + throw new IllegalArgumentException("port out of range:" + port); + return port; + } + + private static String checkHost(String hostname) { + if (hostname == null) + throw new IllegalArgumentException("hostname can't be null"); + return hostname; } /** @@ -97,14 +182,10 @@ public class InetSocketAddress extends SocketAddress { * range of valid port values. */ public InetSocketAddress(InetAddress addr, int port) { - if (port < 0 || port > 0xFFFF) { - throw new IllegalArgumentException("port out of range:" + port); - } - this.port = port; - if (addr == null) - this.addr = InetAddress.anyLocalAddress(); - else - this.addr = addr; + holder = new InetSocketAddressHolder( + null, + addr == null ? InetAddress.anyLocalAddress() : addr, + checkPort(port)); } /** @@ -132,19 +213,20 @@ public class InetSocketAddress extends SocketAddress { * @see #isUnresolved() */ public InetSocketAddress(String hostname, int port) { - if (port < 0 || port > 0xFFFF) { - throw new IllegalArgumentException("port out of range:" + port); - } - if (hostname == null) { - throw new IllegalArgumentException("hostname can't be null"); - } + checkHost(hostname); + InetAddress addr = null; + String host = null; try { addr = InetAddress.getByName(hostname); } catch(UnknownHostException e) { - this.hostname = hostname; - addr = null; + host = hostname; } - this.port = port; + holder = new InetSocketAddressHolder(host, addr, checkPort(port)); + } + + // private constructor for creating unresolved instances + private InetSocketAddress(int port, String hostname) { + holder = new InetSocketAddressHolder(hostname, null, port); } /** @@ -169,31 +251,67 @@ public class InetSocketAddress extends SocketAddress { * @since 1.5 */ public static InetSocketAddress createUnresolved(String host, int port) { - if (port < 0 || port > 0xFFFF) { - throw new IllegalArgumentException("port out of range:" + port); - } - if (host == null) { - throw new IllegalArgumentException("hostname can't be null"); - } - InetSocketAddress s = new InetSocketAddress(); - s.port = port; - s.hostname = host; - s.addr = null; - return s; + return new InetSocketAddress(checkPort(port), checkHost(host)); } - private void readObject(ObjectInputStream s) - throws IOException, ClassNotFoundException { - s.defaultReadObject(); + /** + * @serialField hostname String + * @serialField addr InetAddress + * @serialField port int + */ + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("hostname", String.class), + new ObjectStreamField("addr", InetAddress.class), + new ObjectStreamField("port", int.class)}; + + private void writeObject(ObjectOutputStream out) + throws IOException + { + // Don't call defaultWriteObject() + ObjectOutputStream.PutField pfields = out.putFields(); + pfields.put("hostname", holder.hostname); + pfields.put("addr", holder.addr); + pfields.put("port", holder.port); + out.writeFields(); + } + + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException + { + // Don't call defaultReadObject() + ObjectInputStream.GetField oisFields = in.readFields(); + final String oisHostname = (String)oisFields.get("hostname", null); + final InetAddress oisAddr = (InetAddress)oisFields.get("addr", null); + final int oisPort = oisFields.get("port", -1); // Check that our invariants are satisfied - if (port < 0 || port > 0xFFFF) { - throw new InvalidObjectException("port out of range:" + port); - } - - if (hostname == null && addr == null) { + checkPort(oisPort); + if (oisHostname == null && oisAddr == null) throw new InvalidObjectException("hostname and addr " + "can't both be null"); + + InetSocketAddressHolder h = new InetSocketAddressHolder(oisHostname, + oisAddr, + oisPort); + UNSAFE.putObject(this, FIELDS_OFFSET, h); + } + + private void readObjectNoData() + throws ObjectStreamException + { + throw new InvalidObjectException("Stream data required"); + } + + private static final long FIELDS_OFFSET; + private static final sun.misc.Unsafe UNSAFE; + static { + try { + sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe(); + FIELDS_OFFSET = unsafe.objectFieldOffset( + InetSocketAddress.class.getDeclaredField("holder")); + UNSAFE = unsafe; + } catch (ReflectiveOperationException e) { + throw new Error(e); } } @@ -203,7 +321,7 @@ public class InetSocketAddress extends SocketAddress { * @return the port number. */ public final int getPort() { - return port; + return holder.getPort(); } /** @@ -213,7 +331,7 @@ public class InetSocketAddress extends SocketAddress { * @return the InetAdress or null if it is unresolved. */ public final InetAddress getAddress() { - return addr; + return holder.getAddress(); } /** @@ -224,31 +342,19 @@ public class InetSocketAddress extends SocketAddress { * @return the hostname part of the address. */ public final String getHostName() { - if (hostname != null) - return hostname; - if (addr != null) - return addr.getHostName(); - return null; + return holder.getHostName(); } /** * Returns the hostname, or the String form of the address if it * doesn't have a hostname (it was created using a literal). - * This has the benefit of not attemptimg a reverse lookup. + * This has the benefit of not attempting a reverse lookup. * * @return the hostname, or String representation of the address. * @since 1.7 */ public final String getHostString() { - if (hostname != null) - return hostname; - if (addr != null) { - if (addr.hostName != null) - return addr.hostName; - else - return addr.getHostAddress(); - } - return null; + return holder.getHostString(); } /** @@ -258,7 +364,7 @@ public class InetSocketAddress extends SocketAddress { * an InetAddress. */ public final boolean isUnresolved() { - return addr == null; + return holder.isUnresolved(); } /** @@ -269,12 +375,9 @@ public class InetSocketAddress extends SocketAddress { * * @return a string representation of this object. */ + @Override public String toString() { - if (isUnresolved()) { - return hostname + ":" + port; - } else { - return addr.toString() + ":" + port; - } + return holder.toString(); } /** @@ -297,19 +400,11 @@ public class InetSocketAddress extends SocketAddress { * false otherwise. * @see java.net.InetAddress#equals(java.lang.Object) */ + @Override public final boolean equals(Object obj) { if (obj == null || !(obj instanceof InetSocketAddress)) return false; - InetSocketAddress sockAddr = (InetSocketAddress) obj; - boolean sameIP = false; - if (this.addr != null) - sameIP = this.addr.equals(sockAddr.addr); - else if (this.hostname != null) - sameIP = (sockAddr.addr == null) && - this.hostname.equalsIgnoreCase(sockAddr.hostname); - else - sameIP = (sockAddr.addr == null) && (sockAddr.hostname == null); - return sameIP && (this.port == sockAddr.port); + return holder.equals(((InetSocketAddress) obj).holder); } /** @@ -317,11 +412,8 @@ public class InetSocketAddress extends SocketAddress { * * @return a hash code value for this socket address. */ + @Override public final int hashCode() { - if (addr != null) - return addr.hashCode() + port; - if (hostname != null) - return hostname.toLowerCase().hashCode() + port; - return port; + return holder.hashCode(); } } diff --git a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java index 3d60a38d74c..ff2ee589600 100644 --- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -421,7 +421,7 @@ class DatagramChannelImpl synchronized (writeLock) { ensureOpen(); - InetSocketAddress isa = (InetSocketAddress)target; + InetSocketAddress isa = Net.checkAddress(target); InetAddress ia = isa.getAddress(); if (ia == null) throw new IOException("Target address not resolved"); @@ -432,9 +432,9 @@ class DatagramChannelImpl SecurityManager sm = System.getSecurityManager(); if (sm != null) { if (ia.isMulticastAddress()) { - sm.checkMulticast(isa.getAddress()); + sm.checkMulticast(ia); } else { - sm.checkConnect(isa.getAddress().getHostAddress(), + sm.checkConnect(ia.getHostAddress(), isa.getPort()); } } @@ -454,7 +454,7 @@ class DatagramChannelImpl return 0; writerThread = NativeThread.current(); do { - n = send(fd, src, target); + n = send(fd, src, isa); } while ((n == IOStatus.INTERRUPTED) && isOpen()); synchronized (stateLock) { @@ -471,7 +471,7 @@ class DatagramChannelImpl } } - private int send(FileDescriptor fd, ByteBuffer src, SocketAddress target) + private int send(FileDescriptor fd, ByteBuffer src, InetSocketAddress target) throws IOException { if (src instanceof DirectBuffer) @@ -502,7 +502,7 @@ class DatagramChannelImpl } private int sendFromNativeBuffer(FileDescriptor fd, ByteBuffer bb, - SocketAddress target) + InetSocketAddress target) throws IOException { int pos = bb.position(); @@ -514,7 +514,7 @@ class DatagramChannelImpl int written; try { written = send0(preferIPv6, fd, ((DirectBuffer)bb).address() + pos, - rem, target); + rem, target.getAddress(), target.getPort()); } catch (PortUnreachableException pue) { if (isConnected()) throw pue; @@ -1116,8 +1116,8 @@ class DatagramChannelImpl boolean connected) throws IOException; - private native int send0(boolean preferIPv6, FileDescriptor fd, long address, int len, - SocketAddress sa) + private native int send0(boolean preferIPv6, FileDescriptor fd, long address, + int len, InetAddress addr, int port) throws IOException; static { diff --git a/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpChannelImpl.java index 92f17cb3e8b..411e33c4e84 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpChannelImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpChannelImpl.java @@ -1026,13 +1026,21 @@ public class SctpChannelImpl extends SctpChannel boolean unordered, int ppid) throws IOException { + InetAddress addr = null; // no preferred address + int port = 0; + if (target != null) { + InetSocketAddress isa = Net.checkAddress(target); + addr = isa.getAddress(); + port = isa.getPort(); + } + int pos = bb.position(); int lim = bb.limit(); assert (pos <= lim); int rem = (pos <= lim ? lim - pos : 0); - int written = send0(fd, ((DirectBuffer)bb).address() + pos, - rem, target, -1 /*121*/, streamNumber, unordered, ppid); + int written = send0(fd, ((DirectBuffer)bb).address() + pos, rem, addr, + port, -1 /*121*/, streamNumber, unordered, ppid); if (written > 0) bb.position(pos + written); return written; @@ -1091,7 +1099,7 @@ public class SctpChannelImpl extends SctpChannel long address, int length, boolean peek) throws IOException; static native int send0(int fd, long address, int length, - SocketAddress target, int assocId, int streamNumber, + InetAddress addr, int port, int assocId, int streamNumber, boolean unordered, int ppid) throws IOException; private static native int checkConnect(FileDescriptor fd, boolean block, diff --git a/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpMultiChannelImpl.java b/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpMultiChannelImpl.java index fa44072f4dc..63dc94931da 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpMultiChannelImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpMultiChannelImpl.java @@ -889,13 +889,20 @@ public class SctpMultiChannelImpl extends SctpMultiChannel boolean unordered, int ppid) throws IOException { + InetAddress addr = null; // no preferred address + int port = 0; + if (target != null) { + InetSocketAddress isa = Net.checkAddress(target); + addr = isa.getAddress(); + port = isa.getPort(); + } int pos = bb.position(); int lim = bb.limit(); assert (pos <= lim); int rem = (pos <= lim ? lim - pos : 0); - int written = send0(fd, ((DirectBuffer)bb).address() + pos, - rem, target, assocId, streamNumber, unordered, ppid); + int written = send0(fd, ((DirectBuffer)bb).address() + pos, rem, addr, + port, assocId, streamNumber, unordered, ppid); if (written > 0) bb.position(pos + written); return written; @@ -976,13 +983,14 @@ public class SctpMultiChannelImpl extends SctpMultiChannel private static int send0(int fd, long address, int length, - SocketAddress target, + InetAddress addr, + int port, int assocId, int streamNumber, boolean unordered, int ppid) throws IOException { - return SctpChannelImpl.send0(fd, address, length, target, assocId, + return SctpChannelImpl.send0(fd, address, length, addr, port, assocId, streamNumber, unordered, ppid); } diff --git a/jdk/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c b/jdk/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c index 3bccd574871..c460d61f9c4 100644 --- a/jdk/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c +++ b/jdk/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c @@ -46,8 +46,6 @@ #include "sun_nio_ch_DatagramChannelImpl.h" -static jfieldID isa_addrID; /* address in java.net.InetSocketAddress */ -static jfieldID isa_portID; /* port in java.net.InetSocketAddress */ static jfieldID dci_senderID; /* sender in sun.nio.ch.DatagramChannelImpl */ static jfieldID dci_senderAddrID; /* sender InetAddress in sun.nio.ch.DatagramChannelImpl */ static jfieldID dci_senderPortID; /* sender port in sun.nio.ch.DatagramChannelImpl */ @@ -61,9 +59,6 @@ Java_sun_nio_ch_DatagramChannelImpl_initIDs(JNIEnv *env, jclass clazz) isa_class = (*env)->NewGlobalRef(env, clazz); isa_ctorID = (*env)->GetMethodID(env, clazz, "", "(Ljava/net/InetAddress;I)V"); - isa_addrID = (*env)->GetFieldID(env, clazz, "addr", - "Ljava/net/InetAddress;"); - isa_portID = (*env)->GetFieldID(env, clazz, "port", "I"); clazz = (*env)->FindClass(env, "sun/nio/ch/DatagramChannelImpl"); dci_senderID = (*env)->GetFieldID(env, clazz, "sender", @@ -212,15 +207,13 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this, JNIEXPORT jint JNICALL Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this, jboolean preferIPv6, jobject fdo, jlong address, - jint len, jobject dest) + jint len, jobject destAddress, jint destPort) { jint fd = fdval(env, fdo); void *buf = (void *)jlong_to_ptr(address); SOCKADDR sa; int sa_len = SOCKADDR_LEN; jint n = 0; - jobject destAddress = (*env)->GetObjectField(env, dest, isa_addrID); - jint destPort = (*env)->GetIntField(env, dest, isa_portID); if (len > MAX_PACKET_LEN) { len = MAX_PACKET_LEN; diff --git a/jdk/src/solaris/native/sun/nio/ch/sctp/SctpChannelImpl.c b/jdk/src/solaris/native/sun/nio/ch/sctp/SctpChannelImpl.c index 4333720c3d8..77ef9423e5c 100644 --- a/jdk/src/solaris/native/sun/nio/ch/sctp/SctpChannelImpl.c +++ b/jdk/src/solaris/native/sun/nio/ch/sctp/SctpChannelImpl.c @@ -67,8 +67,6 @@ static jclass spc_class; /* sun.nio.ch.sctp.PeerAddressChanged */ static jmethodID spc_ctrID; /* sun.nio.ch.sctp.PeerAddressChanged. */ static jclass ss_class; /* sun.nio.ch.sctp.Shutdown */ static jmethodID ss_ctrID; /* sun.nio.ch.sctp.Shutdown. */ -static jfieldID isa_addrID; /* java.net.InetSocketAddress.addr */ -static jfieldID isa_portID; /* java.net.InetSocketAddress.port */ /* defined in SctpNet.c */ jobject SockAddrToInetSocketAddress(JNIEnv* env, struct sockaddr* addr); @@ -138,13 +136,6 @@ JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpChannelImpl_initIDs CHECK_NULL(ss_class); ss_ctrID = (*env)->GetMethodID(env, cls, "", "(I)V"); CHECK_NULL(ss_ctrID); - - /* InetSocketAddress */ - cls = (*env)->FindClass(env, "java/net/InetSocketAddress"); - CHECK_NULL(cls); - isa_addrID = (*env)->GetFieldID(env, cls, "addr", "Ljava/net/InetAddress;"); - CHECK_NULL(isa_addrID); - isa_portID = (*env)->GetFieldID(env, cls, "port", "I"); } void getControlData @@ -509,12 +500,12 @@ JNIEXPORT jint JNICALL Java_sun_nio_ch_sctp_SctpChannelImpl_receive0 /* * Class: sun_nio_ch_sctp_SctpChannelImpl * Method: send0 - * Signature: (IJILjava/net/SocketAddress;IIZI)I + * Signature: (IJILjava/net/InetAddress;IIIZI)I */ JNIEXPORT jint JNICALL Java_sun_nio_ch_sctp_SctpChannelImpl_send0 (JNIEnv *env, jclass klass, jint fd, jlong address, jint length, - jobject saTarget, jint assocId, jint streamNumber, jboolean unordered, - jint ppid) { + jobject targetAddress, jint targetPort, jint assocId, jint streamNumber, + jboolean unordered, jint ppid) { SOCKADDR sa; int sa_len = sizeof(sa); ssize_t rv = 0; @@ -526,17 +517,13 @@ JNIEXPORT jint JNICALL Java_sun_nio_ch_sctp_SctpChannelImpl_send0 struct controlData cdata[1]; /* SctpChannel: - * saTarget may contain the preferred address or NULL to use primary, + * targetAddress may contain the preferred address or NULL to use primary, * assocId will always be -1 * SctpMultiChannell: - * Setup new association, saTarget will contain address, assocId = -1 - * Association already existing, assocId != -1, saTarget = preferred addr + * Setup new association, targetAddress will contain address, assocId = -1 + * Association already existing, assocId != -1, targetAddress = preferred addr */ - if (saTarget != NULL /*&& assocId <= 0*/) { - - jobject targetAddress = (*env)->GetObjectField(env, saTarget, isa_addrID); - jint targetPort = (*env)->GetIntField(env, saTarget, isa_portID); - + if (targetAddress != NULL /*&& assocId <= 0*/) { if (NET_InetAddressToSockaddr(env, targetAddress, targetPort, (struct sockaddr *)&sa, &sa_len, JNI_TRUE) != 0) { diff --git a/jdk/src/windows/native/sun/nio/ch/DatagramChannelImpl.c b/jdk/src/windows/native/sun/nio/ch/DatagramChannelImpl.c index 555ca9fbbfb..d98032e4e0b 100644 --- a/jdk/src/windows/native/sun/nio/ch/DatagramChannelImpl.c +++ b/jdk/src/windows/native/sun/nio/ch/DatagramChannelImpl.c @@ -34,8 +34,6 @@ #include "net_util.h" #include -static jfieldID isa_addrID; /* address in java.net.InetSocketAddress */ -static jfieldID isa_portID; /* port in java.net.InetSocketAddress */ static jfieldID dci_senderID; /* sender in sun.nio.ch.DatagramChannelImpl */ static jfieldID dci_senderAddrID; /* sender InetAddress in sun.nio.ch.DatagramChannelImpl */ static jfieldID dci_senderPortID; /* sender port in sun.nio.ch.DatagramChannelImpl */ @@ -50,9 +48,6 @@ Java_sun_nio_ch_DatagramChannelImpl_initIDs(JNIEnv *env, jclass clazz) isa_class = (*env)->NewGlobalRef(env, clazz); isa_ctorID = (*env)->GetMethodID(env, clazz, "", "(Ljava/net/InetAddress;I)V"); - isa_addrID = (*env)->GetFieldID(env, clazz, "addr", - "Ljava/net/InetAddress;"); - isa_portID = (*env)->GetFieldID(env, clazz, "port", "I"); clazz = (*env)->FindClass(env, "sun/nio/ch/DatagramChannelImpl"); dci_senderID = (*env)->GetFieldID(env, clazz, "sender", @@ -214,15 +209,14 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this, JNIEXPORT jint JNICALL Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this, jboolean preferIPv6, jobject fdo, - jlong address, jint len, jobject dest) + jlong address, jint len, + jobject destAddress, jint destPort) { jint fd = fdval(env, fdo); void *buf = (void *)jlong_to_ptr(address); SOCKETADDRESS sa; int sa_len; jint rv = 0; - jobject destAddress = (*env)->GetObjectField(env, dest, isa_addrID); - jint destPort = (*env)->GetIntField(env, dest, isa_portID); if (NET_InetAddressToSockaddr(env, destAddress, destPort, (struct sockaddr *)&sa, diff --git a/jdk/test/java/nio/channels/DatagramChannel/SendToUnresolved.java b/jdk/test/java/nio/channels/DatagramChannel/SendToUnresolved.java index c916b2ef8af..7b9ec6a9a36 100644 --- a/jdk/test/java/nio/channels/DatagramChannel/SendToUnresolved.java +++ b/jdk/test/java/nio/channels/DatagramChannel/SendToUnresolved.java @@ -42,7 +42,7 @@ public class SendToUnresolved { try { dc.send(bb, sa); throw new RuntimeException("Expected exception not thrown"); - } catch (IOException e) { + } catch (IOException | UnresolvedAddressException e) { // Correct result } dc.close(); From 39edc8d2b5b7cc550453e5027181b9779ed61bf8 Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Thu, 8 Nov 2012 15:41:01 -0800 Subject: [PATCH 024/180] 7201070: Serialization to conform to protocol Reviewed-by: dmocek, ahgross, skoivu --- jdk/src/share/classes/java/io/ObjectInputStream.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/jdk/src/share/classes/java/io/ObjectInputStream.java b/jdk/src/share/classes/java/io/ObjectInputStream.java index 1963187eaaa..1125bb04616 100644 --- a/jdk/src/share/classes/java/io/ObjectInputStream.java +++ b/jdk/src/share/classes/java/io/ObjectInputStream.java @@ -1752,6 +1752,12 @@ public class ObjectInputStream ObjectStreamClass desc = readClassDesc(false); desc.checkDeserialize(); + Class cl = desc.forClass(); + if (cl == String.class || cl == Class.class + || cl == ObjectStreamClass.class) { + throw new InvalidClassException("invalid class descriptor"); + } + Object obj; try { obj = desc.isInstantiable() ? desc.newInstance() : null; From 695e6ab2e077b530118831cbcb4511596a73a9f9 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Fri, 9 Nov 2012 14:36:10 -0800 Subject: [PATCH 025/180] 8002091: tools/launcher/ToolsOpts.java test started to fail since 7u11 b01 on Windows Reviewed-by: darcy, jjh, mschoene --- jdk/src/share/bin/jli_util.h | 2 +- jdk/src/windows/bin/java_md.c | 39 +++++++++++++++++--------- jdk/test/tools/launcher/ToolsOpts.java | 1 + 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/jdk/src/share/bin/jli_util.h b/jdk/src/share/bin/jli_util.h index dd53e936210..388910407ff 100644 --- a/jdk/src/share/bin/jli_util.h +++ b/jdk/src/share/bin/jli_util.h @@ -66,7 +66,7 @@ int JLI_GetStdArgc(); #include #define JLI_StrCaseCmp(p1, p2) stricmp((p1), (p2)) #define JLI_StrNCaseCmp(p1, p2, p3) strnicmp((p1), (p2), (p3)) -size_t JLI_Snprintf(char *buffer, size_t size, const char *format, ...); +int JLI_Snprintf(char *buffer, size_t size, const char *format, ...); void JLI_CmdToArgs(char *cmdline); #define JLI_Lseek _lseeki64 #else /* NIXES */ diff --git a/jdk/src/windows/bin/java_md.c b/jdk/src/windows/bin/java_md.c index df118717279..4078ecc754b 100644 --- a/jdk/src/windows/bin/java_md.c +++ b/jdk/src/windows/bin/java_md.c @@ -526,27 +526,35 @@ jlong Counter2Micros(jlong counts) } return (counts * 1000 * 1000)/counterFrequency.QuadPart; } - /* * windows snprintf does not guarantee a null terminator in the buffer, * if the computed size is equal to or greater than the buffer size, - * as well as error conditions, this function guarantees a null terminator - * under all these conditions. An unreasonable buffer size will return - * an error value. + * as well as error conditions. This function guarantees a null terminator + * under all these conditions. An unreasonable buffer or size will return + * an error value. Under all other conditions this function will return the + * size of the bytes actually written minus the null terminator, similar + * to ansi snprintf api. Thus when calling this function the caller must + * ensure storage for the null terminator. */ -size_t -JLI_Snprintf(char* buffer, size_t size, const char* format, ...) -{ - size_t rc; +int +JLI_Snprintf(char* buffer, size_t size, const char* format, ...) { + int rc; va_list vl; - if (size <= 0) + if (size == 0 || buffer == NULL) return -1; + buffer[0] = '\0'; va_start(vl, format); - rc = vsnprintf(buffer, size - 1, format, vl); - /* force a null terminator, if something is amiss */ - if (rc < 0 || rc >= size) - buffer[size - 1] = '\0'; + rc = vsnprintf(buffer, size, format, vl); va_end(vl); + /* force a null terminator, if something is amiss */ + if (rc < 0) { + /* apply ansi semantics */ + buffer[size - 1] = '\0'; + return size; + } else if (rc == size) { + /* force a null terminator */ + buffer[size - 1] = '\0'; + } return rc; } @@ -1441,7 +1449,10 @@ CreateApplicationArgs(JNIEnv *env, char **strv, int argc) // we add the indicator tlen = 1 + JLI_StrLen(strv[i]) + 1; nargv[i] = (char *) JLI_MemAlloc(tlen); - JLI_Snprintf(nargv[i], tlen, "%c%s", arg_expand ? 'T' : 'F', strv[i]); + if (JLI_Snprintf(nargv[i], tlen, "%c%s", arg_expand ? 'T' : 'F', + strv[i]) < 0) { + return NULL; + } JLI_TraceLauncher("%s\n", nargv[i]); } diff --git a/jdk/test/tools/launcher/ToolsOpts.java b/jdk/test/tools/launcher/ToolsOpts.java index 4535990dbca..f01931d5482 100644 --- a/jdk/test/tools/launcher/ToolsOpts.java +++ b/jdk/test/tools/launcher/ToolsOpts.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8002091 * @summary Test options patterns for javac,javah,javap and javadoc using * javac as a test launcher. Create a dummy javac and intercept options to check * reception of options as passed through the launcher without having to launch From 1d3d850ee0b3a31197dfff7ee3e124dfc33c5b09 Mon Sep 17 00:00:00 2001 From: Oleg Pekhovskiy Date: Thu, 15 Nov 2012 23:03:31 +0400 Subject: [PATCH 026/180] 7192977: Issue in toolkit thread Reviewed-by: skoivu, rupashka, art --- .../share/classes/java/awt/EventQueue.java | 19 +- jdk/src/share/classes/java/awt/Window.java | 2 +- .../classes/javax/swing/RepaintManager.java | 167 ++++++++++-------- .../share/classes/sun/applet/AppletPanel.java | 60 +++---- .../share/classes/sun/awt/AWTAccessor.java | 8 + .../sun/awt/windows/WComponentPeer.java | 9 +- .../sun/awt/windows/WEmbeddedFrame.java | 13 +- 7 files changed, 164 insertions(+), 114 deletions(-) diff --git a/jdk/src/share/classes/java/awt/EventQueue.java b/jdk/src/share/classes/java/awt/EventQueue.java index 5ba9756a1af..57a2ccfa3b9 100644 --- a/jdk/src/share/classes/java/awt/EventQueue.java +++ b/jdk/src/share/classes/java/awt/EventQueue.java @@ -194,7 +194,8 @@ public class EventQueue { } public void removeSourceEvents(EventQueue eventQueue, Object source, - boolean removeAllEvents) { + boolean removeAllEvents) + { eventQueue.removeSourceEvents(source, removeAllEvents); } public boolean noEvents(EventQueue eventQueue) { @@ -203,6 +204,11 @@ public class EventQueue { public void wakeup(EventQueue eventQueue, boolean isShutdown) { eventQueue.wakeup(isShutdown); } + public void invokeAndWait(Object source, Runnable r) + throws InterruptedException, InvocationTargetException + { + EventQueue.invokeAndWait(source, r); + } }); } @@ -1245,8 +1251,14 @@ public class EventQueue { * @since 1.2 */ public static void invokeAndWait(Runnable runnable) - throws InterruptedException, InvocationTargetException { + throws InterruptedException, InvocationTargetException + { + invokeAndWait(Toolkit.getDefaultToolkit(), runnable); + } + static void invokeAndWait(Object source, Runnable runnable) + throws InterruptedException, InvocationTargetException + { if (EventQueue.isDispatchThread()) { throw new Error("Cannot call invokeAndWait from the event dispatcher thread"); } @@ -1255,8 +1267,7 @@ public class EventQueue { Object lock = new AWTInvocationLock(); InvocationEvent event = - new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock, - true); + new InvocationEvent(source, runnable, lock, true); synchronized (lock) { Toolkit.getEventQueue().postEvent(event); diff --git a/jdk/src/share/classes/java/awt/Window.java b/jdk/src/share/classes/java/awt/Window.java index 984e287bd50..4b966273e0f 100644 --- a/jdk/src/share/classes/java/awt/Window.java +++ b/jdk/src/share/classes/java/awt/Window.java @@ -1206,7 +1206,7 @@ public class Window extends Container implements Accessible { } else { try { - EventQueue.invokeAndWait(action); + EventQueue.invokeAndWait(this, action); } catch (InterruptedException e) { System.err.println("Disposal was interrupted:"); diff --git a/jdk/src/share/classes/javax/swing/RepaintManager.java b/jdk/src/share/classes/javax/swing/RepaintManager.java index aa3f8bdf50c..8f2e6093393 100644 --- a/jdk/src/share/classes/javax/swing/RepaintManager.java +++ b/jdk/src/share/classes/javax/swing/RepaintManager.java @@ -27,11 +27,12 @@ package javax.swing; import java.awt.*; import java.awt.event.*; -import java.awt.peer.ComponentPeer; -import java.awt.peer.ContainerPeer; import java.awt.image.VolatileImage; +import java.security.AccessControlContext; import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import java.applet.*; import sun.awt.AWTAccessor; @@ -39,6 +40,8 @@ import sun.awt.AppContext; import sun.awt.DisplayChangedListener; import sun.awt.SunToolkit; import sun.java2d.SunGraphicsEnvironment; +import sun.misc.JavaSecurityAccess; +import sun.misc.SharedSecrets; import sun.security.action.GetPropertyAction; import com.sun.java.swing.SwingUtilities3; @@ -176,6 +179,9 @@ public class RepaintManager */ private final ProcessingRunnable processingRunnable; + private final static JavaSecurityAccess javaSecurityAccess = + SharedSecrets.getJavaSecurityAccess(); + static { volatileImageBufferEnabled = "true".equals(AccessController. @@ -548,13 +554,26 @@ public class RepaintManager // This is called from the toolkit thread when awt needs to run a // Runnable before we paint. // - void nativeQueueSurfaceDataRunnable(AppContext appContext, Component c, - Runnable r) { + void nativeQueueSurfaceDataRunnable(AppContext appContext, + final Component c, final Runnable r) + { synchronized(this) { if (runnableList == null) { runnableList = new LinkedList(); } - runnableList.add(r); + runnableList.add(new Runnable() { + public void run() { + AccessControlContext stack = AccessController.getContext(); + AccessControlContext acc = + AWTAccessor.getComponentAccessor().getAccessControlContext(c); + javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction() { + public Void run() { + r.run(); + return null; + } + }, stack, acc); + } + }); } scheduleProcessingRunnable(appContext); } @@ -652,9 +671,9 @@ public class RepaintManager * @see #addInvalidComponent */ public void validateInvalidComponents() { - java.util.List ic; + final java.util.List ic; synchronized(this) { - if(invalidComponents == null) { + if (invalidComponents == null) { return; } ic = invalidComponents; @@ -662,7 +681,17 @@ public class RepaintManager } int n = ic.size(); for(int i = 0; i < n; i++) { - ic.get(i).validate(); + final Component c = ic.get(i); + AccessControlContext stack = AccessController.getContext(); + AccessControlContext acc = + AWTAccessor.getComponentAccessor().getAccessControlContext(c); + javaSecurityAccess.doIntersectionPrivilege( + new PrivilegedAction() { + public Void run() { + c.validate(); + return null; + } + }, stack, acc); } } @@ -740,78 +769,78 @@ public class RepaintManager paintDirtyRegions(tmpDirtyComponents); } - private void paintDirtyRegions(Map - tmpDirtyComponents){ - int i, count; - java.util.List roots; - Component dirtyComponent; - - count = tmpDirtyComponents.size(); - if (count == 0) { + private void paintDirtyRegions( + final Map tmpDirtyComponents) + { + if (tmpDirtyComponents.isEmpty()) { return; } - Rectangle rect; - int localBoundsX = 0; - int localBoundsY = 0; - int localBoundsH; - int localBoundsW; - - roots = new ArrayList(count); - + final java.util.List roots = + new ArrayList(tmpDirtyComponents.size()); for (Component dirty : tmpDirtyComponents.keySet()) { collectDirtyComponents(tmpDirtyComponents, dirty, roots); } - count = roots.size(); + final AtomicInteger count = new AtomicInteger(roots.size()); painting = true; try { - for(i=0 ; i < count ; i++) { - dirtyComponent = roots.get(i); - rect = tmpDirtyComponents.get(dirtyComponent); - // Sometimes when RepaintManager is changed during the painting - // we may get null here, see #6995769 for details - if (rect == null) { - continue; - } - localBoundsH = dirtyComponent.getHeight(); - localBoundsW = dirtyComponent.getWidth(); - - SwingUtilities.computeIntersection(localBoundsX, - localBoundsY, - localBoundsW, - localBoundsH, - rect); - if (dirtyComponent instanceof JComponent) { - ((JComponent)dirtyComponent).paintImmediately( - rect.x,rect.y,rect.width, rect.height); - } - else if (dirtyComponent.isShowing()) { - Graphics g = JComponent.safelyGetGraphics( - dirtyComponent, dirtyComponent); - // If the Graphics goes away, it means someone disposed of - // the window, don't do anything. - if (g != null) { - g.setClip(rect.x, rect.y, rect.width, rect.height); - try { - dirtyComponent.paint(g); - } finally { - g.dispose(); + for (int j=0 ; j < count.get(); j++) { + final int i = j; + final Component dirtyComponent = roots.get(j); + AccessControlContext stack = AccessController.getContext(); + AccessControlContext acc = + AWTAccessor.getComponentAccessor().getAccessControlContext(dirtyComponent); + javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction() { + public Void run() { + Rectangle rect = tmpDirtyComponents.get(dirtyComponent); + // Sometimes when RepaintManager is changed during the painting + // we may get null here, see #6995769 for details + if (rect == null) { + return null; } + + int localBoundsH = dirtyComponent.getHeight(); + int localBoundsW = dirtyComponent.getWidth(); + SwingUtilities.computeIntersection(0, + 0, + localBoundsW, + localBoundsH, + rect); + if (dirtyComponent instanceof JComponent) { + ((JComponent)dirtyComponent).paintImmediately( + rect.x,rect.y,rect.width, rect.height); + } + else if (dirtyComponent.isShowing()) { + Graphics g = JComponent.safelyGetGraphics( + dirtyComponent, dirtyComponent); + // If the Graphics goes away, it means someone disposed of + // the window, don't do anything. + if (g != null) { + g.setClip(rect.x, rect.y, rect.width, rect.height); + try { + dirtyComponent.paint(g); + } finally { + g.dispose(); + } + } + } + // If the repaintRoot has been set, service it now and + // remove any components that are children of repaintRoot. + if (repaintRoot != null) { + adjustRoots(repaintRoot, roots, i + 1); + count.set(roots.size()); + paintManager.isRepaintingRoot = true; + repaintRoot.paintImmediately(0, 0, repaintRoot.getWidth(), + repaintRoot.getHeight()); + paintManager.isRepaintingRoot = false; + // Only service repaintRoot once. + repaintRoot = null; + } + + return null; } - } - // If the repaintRoot has been set, service it now and - // remove any components that are children of repaintRoot. - if (repaintRoot != null) { - adjustRoots(repaintRoot, roots, i + 1); - count = roots.size(); - paintManager.isRepaintingRoot = true; - repaintRoot.paintImmediately(0, 0, repaintRoot.getWidth(), - repaintRoot.getHeight()); - paintManager.isRepaintingRoot = false; - // Only service repaintRoot once. - repaintRoot = null; - } + }, stack, acc); } } finally { painting = false; diff --git a/jdk/src/share/classes/sun/applet/AppletPanel.java b/jdk/src/share/classes/sun/applet/AppletPanel.java index e090beec417..5ca566214db 100644 --- a/jdk/src/share/classes/sun/applet/AppletPanel.java +++ b/jdk/src/share/classes/sun/applet/AppletPanel.java @@ -45,6 +45,7 @@ import java.util.*; import java.util.Collections; import java.util.Locale; import java.util.WeakHashMap; +import sun.awt.AWTAccessor; import sun.awt.AppContext; import sun.awt.EmbeddedFrame; import sun.awt.SunToolkit; @@ -448,12 +449,12 @@ abstract class AppletPanel extends Panel implements AppletStub, Runnable { // to avoid deadlock. try { final AppletPanel p = this; - - EventQueue.invokeAndWait(new Runnable() { - public void run() { - p.validate(); - } - }); + Runnable r = new Runnable() { + public void run() { + p.validate(); + } + }; + AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r); } catch(InterruptedException ie) { } @@ -478,18 +479,19 @@ abstract class AppletPanel extends Panel implements AppletStub, Runnable { try { final AppletPanel p = this; final Applet a = applet; + Runnable r = new Runnable() { + public void run() { + p.validate(); + a.setVisible(true); - EventQueue.invokeAndWait(new Runnable() { - public void run() { - p.validate(); - a.setVisible(true); - - // Fix for BugTraq ID 4041703. - // Set the default focus for an applet. - if (hasInitialFocus()) - setDefaultFocus(); + // Fix for BugTraq ID 4041703. + // Set the default focus for an applet. + if (hasInitialFocus()) { + setDefaultFocus(); } - }); + } + }; + AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r); } catch(InterruptedException ie) { } @@ -512,13 +514,12 @@ abstract class AppletPanel extends Panel implements AppletStub, Runnable { // to avoid deadlock. try { final Applet a = applet; - - EventQueue.invokeAndWait(new Runnable() { - public void run() - { - a.setVisible(false); - } - }); + Runnable r = new Runnable() { + public void run() { + a.setVisible(false); + } + }; + AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r); } catch(InterruptedException ie) { } @@ -570,17 +571,14 @@ abstract class AppletPanel extends Panel implements AppletStub, Runnable { } status = APPLET_DISPOSE; - try - { + try { final Applet a = applet; - - EventQueue.invokeAndWait(new Runnable() - { - public void run() - { + Runnable r = new Runnable() { + public void run() { remove(a); } - }); + }; + AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r); } catch(InterruptedException ie) { diff --git a/jdk/src/share/classes/sun/awt/AWTAccessor.java b/jdk/src/share/classes/sun/awt/AWTAccessor.java index 21f426da2f5..633fdcb4c18 100644 --- a/jdk/src/share/classes/sun/awt/AWTAccessor.java +++ b/jdk/src/share/classes/sun/awt/AWTAccessor.java @@ -34,6 +34,8 @@ import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.geom.Point2D; import java.awt.peer.ComponentPeer; + +import java.lang.reflect.InvocationTargetException; import java.security.AccessControlContext; import java.io.File; @@ -476,6 +478,12 @@ public final class AWTAccessor { * appeared. */ void wakeup(EventQueue eventQueue, boolean isShutdown); + + /** + * Static in EventQueue + */ + void invokeAndWait(Object source, Runnable r) + throws InterruptedException, InvocationTargetException; } /* diff --git a/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java b/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java index 6f788c2ac5d..37a257f1130 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java +++ b/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java @@ -488,14 +488,15 @@ public abstract class WComponentPeer extends WObjectPeer try { replaceSurfaceData(); } catch (InvalidPipeException e) { - // REMIND : what do we do if our surface creation failed? + // REMIND : what do we do if our surface creation failed? } } } }; + Component c = (Component)target; // Fix 6255371. - if (!PaintEventDispatcher.getPaintEventDispatcher().queueSurfaceDataReplacing((Component)target, r)) { - postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(), r)); + if (!PaintEventDispatcher.getPaintEventDispatcher().queueSurfaceDataReplacing(c, r)) { + postEvent(new InvocationEvent(c, r)); } } @@ -618,7 +619,7 @@ public abstract class WComponentPeer extends WObjectPeer } public void disposeLater() { - postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(), new Runnable() { + postEvent(new InvocationEvent(target, new Runnable() { public void run() { dispose(); } diff --git a/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java b/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java index b0f9cd3279d..3bc2c3b6b63 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java +++ b/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java @@ -27,6 +27,7 @@ package sun.awt.windows; import sun.awt.*; import java.awt.*; +import java.awt.event.InvocationEvent; import java.awt.peer.ComponentPeer; import java.awt.image.*; import sun.awt.image.ByteInterleavedRaster; @@ -232,11 +233,13 @@ public class WEmbeddedFrame extends EmbeddedFrame { } else { // To avoid focus concurrence b/w IE and EmbeddedFrame // activation is postponed by means of posting it to EDT. - EventQueue.invokeLater(new Runnable() { - public void run() { - ((WEmbeddedFramePeer)getPeer()).synthesizeWmActivate(true); - } - }); + Runnable r = new Runnable() { + public void run() { + ((WEmbeddedFramePeer)getPeer()).synthesizeWmActivate(true); + } + }; + WToolkit.postEvent(WToolkit.targetToAppContext(this), + new InvocationEvent(this, r)); } } From 7749e896e76a27c5872c068bf24f4bd84b294abb Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Fri, 16 Nov 2012 11:05:43 +0400 Subject: [PATCH 027/180] 8001972: Improve image processing Reviewed-by: prr, ahgross --- .../sun/awt/image/ByteComponentRaster.java | 70 ++++++++++----- .../sun/awt/image/ByteInterleavedRaster.java | 29 +----- .../sun/awt/image/ShortComponentRaster.java | 69 +++++++++----- .../sun/awt/image/ShortInterleavedRaster.java | 29 +----- .../native/sun/awt/image/awt_parseImage.c | 90 +++++++++++++++++-- .../native/sun/awt/medialib/safe_alloc.h | 5 ++ 6 files changed, 191 insertions(+), 101 deletions(-) diff --git a/jdk/src/share/classes/sun/awt/image/ByteComponentRaster.java b/jdk/src/share/classes/sun/awt/image/ByteComponentRaster.java index c92f7665904..49c642e37db 100644 --- a/jdk/src/share/classes/sun/awt/image/ByteComponentRaster.java +++ b/jdk/src/share/classes/sun/awt/image/ByteComponentRaster.java @@ -198,7 +198,7 @@ public class ByteComponentRaster extends SunWritableRaster { } this.bandOffset = this.dataOffsets[0]; - verify(false); + verify(); } /** @@ -857,38 +857,68 @@ public class ByteComponentRaster extends SunWritableRaster { } /** - * Verify that the layout parameters are consistent with - * the data. If strictCheck - * is false, this method will check for ArrayIndexOutOfBounds conditions. If - * strictCheck is true, this method will check for additional error - * conditions such as line wraparound (width of a line greater than - * the scanline stride). - * @return String Error string, if the layout is incompatible with - * the data. Otherwise returns null. + * Verify that the layout parameters are consistent with the data. + * + * The method verifies whether scanline stride and pixel stride do not + * cause an integer overflow during calculation of a position of the pixel + * in data buffer. It also verifies whether the data buffer has enough data + * to correspond the raster layout attributes. + * + * @throws RasterFormatException if an integer overflow is detected, + * or if data buffer has not enough capacity. */ - private void verify (boolean strictCheck) { - // Make sure data for Raster is in a legal range - for (int i=0; i < dataOffsets.length; i++) { + protected final void verify() { + for (int i = 0; i < dataOffsets.length; i++) { if (dataOffsets[i] < 0) { - throw new RasterFormatException("Data offsets for band "+i+ - "("+dataOffsets[i]+ - ") must be >= 0"); + throw new RasterFormatException("Data offsets for band " + i + + "(" + dataOffsets[i] + + ") must be >= 0"); } } int maxSize = 0; int size; - for (int i=0; i < numDataElements; i++) { - size = (height-1)*scanlineStride + (width-1)*pixelStride + - dataOffsets[i]; + // we can be sure that width and height are greater than 0 + if (scanlineStride < 0 || + scanlineStride > (Integer.MAX_VALUE / height)) + { + // integer overflow + throw new RasterFormatException("Incorrect scanline stride: " + + scanlineStride); + } + int lastScanOffset = (height - 1) * scanlineStride; + + if (pixelStride < 0 || + pixelStride > (Integer.MAX_VALUE / width)) + { + // integer overflow + throw new RasterFormatException("Incorrect pixel stride: " + + pixelStride); + } + int lastPixelOffset = (width - 1) * pixelStride; + + if (lastPixelOffset > (Integer.MAX_VALUE - lastScanOffset)) { + // integer overflow + throw new RasterFormatException("Incorrect raster attributes"); + } + lastPixelOffset += lastScanOffset; + + for (int i = 0; i < numDataElements; i++) { + size = lastPixelOffset + dataOffsets[i]; + if (dataOffsets[i] > (Integer.MAX_VALUE - lastPixelOffset)) { + throw new RasterFormatException("Incorrect band offset: " + + dataOffsets[i]); + + } + if (size > maxSize) { maxSize = size; } } if (data.length < maxSize) { - throw new RasterFormatException("Data array too small (should be "+ - maxSize+" )"); + throw new RasterFormatException("Data array too small (should be " + + maxSize + " )"); } } diff --git a/jdk/src/share/classes/sun/awt/image/ByteInterleavedRaster.java b/jdk/src/share/classes/sun/awt/image/ByteInterleavedRaster.java index b721d686867..4279ce1f90a 100644 --- a/jdk/src/share/classes/sun/awt/image/ByteInterleavedRaster.java +++ b/jdk/src/share/classes/sun/awt/image/ByteInterleavedRaster.java @@ -250,7 +250,7 @@ public class ByteInterleavedRaster extends ByteComponentRaster { } } - verify(false); + verify(); } /** @@ -1292,33 +1292,6 @@ public class ByteInterleavedRaster extends ByteComponentRaster { return createCompatibleWritableRaster(width,height); } - /** - * Verify that the layout parameters are consistent with - * the data. If strictCheck - * is false, this method will check for ArrayIndexOutOfBounds conditions. If - * strictCheck is true, this method will check for additional error - * conditions such as line wraparound (width of a line greater than - * the scanline stride). - * @return String Error string, if the layout is incompatible with - * the data. Otherwise returns null. - */ - private void verify (boolean strictCheck) { - int maxSize = 0; - int size; - - for (int i=0; i < numDataElements; i++) { - size = (height-1)*scanlineStride + (width-1)*pixelStride + - dataOffsets[i]; - if (size > maxSize) { - maxSize = size; - } - } - if (data.length < maxSize) { - throw new RasterFormatException("Data array too small (should be "+ - maxSize+" )"); - } - } - public String toString() { return new String ("ByteInterleavedRaster: width = "+width+" height = " + height diff --git a/jdk/src/share/classes/sun/awt/image/ShortComponentRaster.java b/jdk/src/share/classes/sun/awt/image/ShortComponentRaster.java index bc39bd2f0c8..df2c0f7d663 100644 --- a/jdk/src/share/classes/sun/awt/image/ShortComponentRaster.java +++ b/jdk/src/share/classes/sun/awt/image/ShortComponentRaster.java @@ -198,7 +198,7 @@ public class ShortComponentRaster extends SunWritableRaster { } this.bandOffset = this.dataOffsets[0]; - verify(false); + verify(); } /** @@ -791,38 +791,67 @@ public class ShortComponentRaster extends SunWritableRaster { } /** - * Verify that the layout parameters are consistent with - * the data. If strictCheck - * is false, this method will check for ArrayIndexOutOfBounds conditions. If - * strictCheck is true, this method will check for additional error - * conditions such as line wraparound (width of a line greater than - * the scanline stride). - * @return String Error string, if the layout is incompatible with - * the data. Otherwise returns null. + * Verify that the layout parameters are consistent with the data. + * + * The method verifies whether scanline stride and pixel stride do not + * cause an integer overflow during calculation of a position of the pixel + * in data buffer. It also verifies whether the data buffer has enough data + * to correspond the raster layout attributes. + * + * @throws RasterFormatException if an integer overflow is detected, + * or if data buffer has not enough capacity. */ - private void verify (boolean strictCheck) { - // Make sure data for Raster is in a legal range - for (int i=0; i < dataOffsets.length; i++) { + protected final void verify() { + for (int i = 0; i < dataOffsets.length; i++) { if (dataOffsets[i] < 0) { - throw new RasterFormatException("Data offsets for band "+i+ - "("+dataOffsets[i]+ - ") must be >= 0"); + throw new RasterFormatException("Data offsets for band " + i + + "(" + dataOffsets[i] + + ") must be >= 0"); } } int maxSize = 0; int size; - for (int i=0; i < numDataElements; i++) { - size = (height-1)*scanlineStride + (width-1)*pixelStride + - dataOffsets[i]; + // we can be sure that width and height are greater than 0 + if (scanlineStride < 0 || + scanlineStride > (Integer.MAX_VALUE / height)) + { + // integer overflow + throw new RasterFormatException("Incorrect scanline stride: " + + scanlineStride); + } + int lastScanOffset = (height - 1) * scanlineStride; + + if (pixelStride < 0 || + pixelStride > (Integer.MAX_VALUE / width)) + { + // integer overflow + throw new RasterFormatException("Incorrect pixel stride: " + + pixelStride); + } + int lastPixelOffset = (width - 1) * pixelStride; + + if (lastPixelOffset > (Integer.MAX_VALUE - lastScanOffset)) { + // integer overflow + throw new RasterFormatException("Incorrect raster attributes"); + } + lastPixelOffset += lastScanOffset; + + for (int i = 0; i < numDataElements; i++) { + size = lastPixelOffset + dataOffsets[i]; + if (dataOffsets[i] > (Integer.MAX_VALUE - lastPixelOffset)) { + throw new RasterFormatException("Incorrect band offset: " + + dataOffsets[i]); + } + if (size > maxSize) { maxSize = size; } } if (data.length < maxSize) { - throw new RasterFormatException("Data array too small (should be "+ - maxSize+" )"); + throw new RasterFormatException("Data array too small (should be " + + maxSize + " )"); } } diff --git a/jdk/src/share/classes/sun/awt/image/ShortInterleavedRaster.java b/jdk/src/share/classes/sun/awt/image/ShortInterleavedRaster.java index ef624f978c2..c55d111d7fd 100644 --- a/jdk/src/share/classes/sun/awt/image/ShortInterleavedRaster.java +++ b/jdk/src/share/classes/sun/awt/image/ShortInterleavedRaster.java @@ -171,7 +171,7 @@ public class ShortInterleavedRaster extends ShortComponentRaster { sampleModel); } this.bandOffset = this.dataOffsets[0]; - verify(false); + verify(); } /** @@ -762,33 +762,6 @@ public class ShortInterleavedRaster extends ShortComponentRaster { return createCompatibleWritableRaster(width,height); } - /** - * Verify that the layout parameters are consistent with - * the data. If strictCheck - * is false, this method will check for ArrayIndexOutOfBounds conditions. If - * strictCheck is true, this method will check for additional error - * conditions such as line wraparound (width of a line greater than - * the scanline stride). - * @return String Error string, if the layout is incompatible with - * the data. Otherwise returns null. - */ - private void verify (boolean strictCheck) { - int maxSize = 0; - int size; - - for (int i=0; i < numDataElements; i++) { - size = (height-1)*scanlineStride + (width-1)*pixelStride + - dataOffsets[i]; - if (size > maxSize) { - maxSize = size; - } - } - if (data.length < maxSize) { - throw new RasterFormatException("Data array too small (should be "+ - maxSize+" )"); - } - } - public String toString() { return new String ("ShortInterleavedRaster: width = "+width +" height = " + height diff --git a/jdk/src/share/native/sun/awt/image/awt_parseImage.c b/jdk/src/share/native/sun/awt/image/awt_parseImage.c index 264a02f1642..cdd22189d78 100644 --- a/jdk/src/share/native/sun/awt/image/awt_parseImage.c +++ b/jdk/src/share/native/sun/awt/image/awt_parseImage.c @@ -114,6 +114,62 @@ int awt_parseImage(JNIEnv *env, jobject jimage, BufImageS_t **imagePP, return status; } +/* Verifies whether the channel offsets are sane and correspond to the type of + * the raster. + * + * Return value: + * 0: Failure: channel offsets are invalid + * 1: Success + */ +static int checkChannelOffsets(RasterS_t *rasterP, int dataArrayLength) { + int i, lastPixelOffset, lastScanOffset; + switch (rasterP->rasterType) { + case COMPONENT_RASTER_TYPE: + if (!SAFE_TO_MULT(rasterP->height, rasterP->scanlineStride)) { + return 0; + } + if (!SAFE_TO_MULT(rasterP->width, rasterP->pixelStride)) { + return 0; + } + + lastScanOffset = (rasterP->height - 1) * rasterP->scanlineStride; + lastPixelOffset = (rasterP->width - 1) * rasterP->pixelStride; + + + if (!SAFE_TO_ADD(lastPixelOffset, lastScanOffset)) { + return 0; + } + + lastPixelOffset += lastScanOffset; + + for (i = 0; i < rasterP->numDataElements; i++) { + int off = rasterP->chanOffsets[i]; + int size = lastPixelOffset + off; + + if (off < 0 || !SAFE_TO_ADD(lastPixelOffset, off)) { + return 0; + } + + if (size < lastPixelOffset || size >= dataArrayLength) { + // an overflow, or insufficient buffer capacity + return 0; + } + } + return 1; + case BANDED_RASTER_TYPE: + // NB:caller does not support the banded rasters yet, + // so this branch of the code must be re-defined in + // order to provide valid criteria for the data offsets + // verification, when/if banded rasters will be supported. + // At the moment, we prohibit banded rasters as well. + return 0; + default: + // PACKED_RASTER_TYPE: does not support channel offsets + // UNKNOWN_RASTER_TYPE: should not be used, likely indicates an error + return 0; + } +} + /* Parse the raster. All of the raster information is returned in the * rasterP structure. * @@ -125,7 +181,6 @@ int awt_parseImage(JNIEnv *env, jobject jimage, BufImageS_t **imagePP, int awt_parseRaster(JNIEnv *env, jobject jraster, RasterS_t *rasterP) { jobject joffs = NULL; /* int status;*/ - int isDiscrete = TRUE; if (JNU_IsNull(env, jraster)) { JNU_ThrowNullPointerException(env, "null Raster object"); @@ -155,6 +210,9 @@ int awt_parseRaster(JNIEnv *env, jobject jraster, RasterS_t *rasterP) { return -1; } + // make sure that the raster type is initialized + rasterP->rasterType = UNKNOWN_RASTER_TYPE; + if (rasterP->numBands <= 0 || rasterP->numBands > MAX_NUMBANDS) { @@ -254,7 +312,6 @@ int awt_parseRaster(JNIEnv *env, jobject jraster, RasterS_t *rasterP) { } rasterP->chanOffsets[0] = (*env)->GetIntField(env, jraster, g_BPRdataBitOffsetID); rasterP->dataType = BYTE_DATA_TYPE; - isDiscrete = FALSE; } else { rasterP->type = sun_awt_image_IntegerComponentRaster_TYPE_CUSTOM; @@ -265,7 +322,19 @@ int awt_parseRaster(JNIEnv *env, jobject jraster, RasterS_t *rasterP) { return 0; } - if (isDiscrete) { + // do basic validation of the raster structure + if (rasterP->width <= 0 || rasterP->height <= 0 || + rasterP->pixelStride <= 0 || rasterP->scanlineStride <= 0) + { + // invalid raster + return -1; + } + + // channel (data) offsets + switch (rasterP->rasterType) { + case COMPONENT_RASTER_TYPE: + case BANDED_RASTER_TYPE: // note that this routine does not support banded rasters at the moment + // get channel (data) offsets rasterP->chanOffsets = NULL; if (SAFE_TO_ALLOC_2(rasterP->numDataElements, sizeof(jint))) { rasterP->chanOffsets = @@ -278,10 +347,21 @@ int awt_parseRaster(JNIEnv *env, jobject jraster, RasterS_t *rasterP) { } (*env)->GetIntArrayRegion(env, joffs, 0, rasterP->numDataElements, rasterP->chanOffsets); + if (rasterP->jdata == NULL) { + // unable to verify the raster + return -1; + } + // verify whether channel offsets look sane + if (!checkChannelOffsets(rasterP, (*env)->GetArrayLength(env, rasterP->jdata))) { + return -1; + } + break; + default: + ; // PACKED_RASTER_TYPE does not use the channel offsets. } - /* additioanl check for sppsm fields validity: make sure that - * size of raster samples doesn't exceed the data type cpacity. + /* additional check for sppsm fields validity: make sure that + * size of raster samples doesn't exceed the data type capacity. */ if (rasterP->dataType > UNKNOWN_DATA_TYPE && /* data type has been recognized */ rasterP->sppsm.maxBitSize > 0 && /* raster has SPP sample model */ diff --git a/jdk/src/share/native/sun/awt/medialib/safe_alloc.h b/jdk/src/share/native/sun/awt/medialib/safe_alloc.h index ce744af2c3b..579d98638dc 100644 --- a/jdk/src/share/native/sun/awt/medialib/safe_alloc.h +++ b/jdk/src/share/native/sun/awt/medialib/safe_alloc.h @@ -41,5 +41,10 @@ (((w) > 0) && ((h) > 0) && ((sz) > 0) && \ (((0xffffffffu / ((juint)(w))) / ((juint)(h))) > ((juint)(sz)))) +#define SAFE_TO_MULT(a, b) \ + (((a) > 0) && ((b) >= 0) && ((0x7fffffff / (a)) > (b))) + +#define SAFE_TO_ADD(a, b) \ + (((a) >= 0) && ((b) >= 0) && ((0x7fffffff - (a)) > (b))) #endif // __SAFE_ALLOC_H__ From 52caa8646b6b5ea2ae4a3b6883c8072f257db2ef Mon Sep 17 00:00:00 2001 From: Darryl Mocek Date: Mon, 19 Nov 2012 13:54:12 -0800 Subject: [PATCH 028/180] 6563318: RMI data sanitization Reviewed-by: ahgross, hawtin, mchung, smarks --- .../sun/rmi/transport/proxy/CGIHandler.java | 6 +-- jdk/test/java/rmi/testlibrary/JavaVM.java | 39 +++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/jdk/src/share/classes/sun/rmi/transport/proxy/CGIHandler.java b/jdk/src/share/classes/sun/rmi/transport/proxy/CGIHandler.java index 918986deec9..460c9f17203 100644 --- a/jdk/src/share/classes/sun/rmi/transport/proxy/CGIHandler.java +++ b/jdk/src/share/classes/sun/rmi/transport/proxy/CGIHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -153,7 +153,7 @@ public final class CGIHandler { returnServerError(e.getMessage()); } else - returnClientError("invalid command: " + command); + returnClientError("invalid command."); } catch (Exception e) { returnServerError("internal error: " + e.getMessage()); } @@ -225,7 +225,7 @@ final class CGIForwardCommand implements CGICommandHandler { try { port = Integer.parseInt(param); } catch (NumberFormatException e) { - throw new CGIClientException("invalid port number: " + param); + throw new CGIClientException("invalid port number."); } if (port <= 0 || port > 0xFFFF) throw new CGIClientException("invalid port: " + port); diff --git a/jdk/test/java/rmi/testlibrary/JavaVM.java b/jdk/test/java/rmi/testlibrary/JavaVM.java index 62be87d8279..d7b94bfe4b1 100644 --- a/jdk/test/java/rmi/testlibrary/JavaVM.java +++ b/jdk/test/java/rmi/testlibrary/JavaVM.java @@ -133,6 +133,14 @@ public class JavaVM { return TestLibrary.getExtraProperty("jcov.options",""); } + public void start(Runnable runnable) throws IOException { + if (runnable == null) { + throw new NullPointerException("Runnable cannot be null."); + } + + start(); + new JavaVMCallbackHandler(runnable).start(); + } /** * Exec the VM as specified in this object's constructor. @@ -235,4 +243,35 @@ public class JavaVM { protected Process getVM() { return vm; } + + /** + * Handles calling the callback. + */ + private class JavaVMCallbackHandler extends Thread { + Runnable runnable; + + JavaVMCallbackHandler(Runnable runnable) { + this.runnable = runnable; + } + + + /** + * Wait for the Process to terminate and notify the callback. + */ + @Override + public void run() { + if (vm != null) { + try { + vm.waitFor(); + } catch(InterruptedException ie) { + // Restore the interrupted status + Thread.currentThread().interrupt(); + } + } + + if (runnable != null) { + runnable.run(); + } + } + } } From 103aa32912bf857ca25737649db2800c4dbb8365 Mon Sep 17 00:00:00 2001 From: Darryl Mocek Date: Mon, 19 Nov 2012 15:38:56 -0800 Subject: [PATCH 029/180] 8001242: Improve RMI HTTP conformance Reviewed-by: ahgross, mchung, smarks --- .../sun/rmi/transport/proxy/CGIHandler.java | 13 ++++++++----- .../sun/rmi/transport/proxy/HttpInputStream.java | 15 +++++++++------ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/jdk/src/share/classes/sun/rmi/transport/proxy/CGIHandler.java b/jdk/src/share/classes/sun/rmi/transport/proxy/CGIHandler.java index 460c9f17203..a60b23864af 100644 --- a/jdk/src/share/classes/sun/rmi/transport/proxy/CGIHandler.java +++ b/jdk/src/share/classes/sun/rmi/transport/proxy/CGIHandler.java @@ -293,11 +293,14 @@ final class CGIForwardCommand implements CGICommandHandler { "unexpected EOF reading server response"); if (line.toLowerCase().startsWith(key)) { - // if contentLengthFound is true - // we should probably do something here - responseContentLength = - Integer.parseInt(line.substring(key.length()).trim()); - contentLengthFound = true; + if (contentLengthFound) { + throw new CGIServerException( + "Multiple Content-length entries found."); + } else { + responseContentLength = + Integer.parseInt(line.substring(key.length()).trim()); + contentLengthFound = true; + } } } while ((line.length() != 0) && (line.charAt(0) != '\r') && (line.charAt(0) != '\n')); diff --git a/jdk/src/share/classes/sun/rmi/transport/proxy/HttpInputStream.java b/jdk/src/share/classes/sun/rmi/transport/proxy/HttpInputStream.java index 773493e48df..3a35bb02b25 100644 --- a/jdk/src/share/classes/sun/rmi/transport/proxy/HttpInputStream.java +++ b/jdk/src/share/classes/sun/rmi/transport/proxy/HttpInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -70,11 +70,14 @@ class HttpInputStream extends FilterInputStream { throw new EOFException(); if (line.toLowerCase().startsWith(key)) { - // if contentLengthFound is true - // we should probably do something here - bytesLeft = - Integer.parseInt(line.substring(key.length()).trim()); - contentLengthFound = true; + if (contentLengthFound) { + throw new IOException( + "Multiple Content-length entries found."); + } else { + bytesLeft = + Integer.parseInt(line.substring(key.length()).trim()); + contentLengthFound = true; + } } // The idea here is to go past the first blank line. From b9b59635225b5db8216c3da0024545ad279f6f53 Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Tue, 20 Nov 2012 11:46:42 +0400 Subject: [PATCH 030/180] 8002325: Improve management of images Reviewed-by: prr, ahgross --- .../native/sun/awt/image/awt_parseImage.c | 20 +++++++++++++++++++ .../native/sun/awt/image/awt_parseImage.h | 1 + 2 files changed, 21 insertions(+) diff --git a/jdk/src/share/native/sun/awt/image/awt_parseImage.c b/jdk/src/share/native/sun/awt/image/awt_parseImage.c index cdd22189d78..4fe4efd2916 100644 --- a/jdk/src/share/native/sun/awt/image/awt_parseImage.c +++ b/jdk/src/share/native/sun/awt/image/awt_parseImage.c @@ -223,9 +223,14 @@ int awt_parseRaster(JNIEnv *env, jobject jraster, RasterS_t *rasterP) { return 0; } + rasterP->sppsm.isUsed = 0; + if ((*env)->IsInstanceOf(env, rasterP->jsampleModel, (*env)->FindClass(env,"java/awt/image/SinglePixelPackedSampleModel"))) { jobject jmask, joffs, jnbits; + + rasterP->sppsm.isUsed = 1; + rasterP->sppsm.maxBitSize = (*env)->GetIntField(env, rasterP->jsampleModel, g_SPPSMmaxBitID); @@ -711,6 +716,21 @@ setHints(JNIEnv *env, BufImageS_t *imageP) { } else if (cmodelP->cmType == DIRECT_CM_TYPE || cmodelP->cmType == PACKED_CM_TYPE) { int i; + + /* do some sanity check first: make sure that + * - sample model is SinglePixelPackedSampleModel + * - number of bands in the raster corresponds to the number + * of color components in the color model + */ + if (!rasterP->sppsm.isUsed || + rasterP->numBands != cmodelP->numComponents) + { + /* given raster is not compatible with the color model, + * so the operation has to be aborted. + */ + return -1; + } + if (cmodelP->maxNbits > 8) { hintP->needToExpand = TRUE; hintP->expandToNbits = cmodelP->maxNbits; diff --git a/jdk/src/share/native/sun/awt/image/awt_parseImage.h b/jdk/src/share/native/sun/awt/image/awt_parseImage.h index f58adabb754..b92bb0c2833 100644 --- a/jdk/src/share/native/sun/awt/image/awt_parseImage.h +++ b/jdk/src/share/native/sun/awt/image/awt_parseImage.h @@ -95,6 +95,7 @@ typedef struct { jint offsets[MAX_NUMBANDS]; jint nBits[MAX_NUMBANDS]; jint maxBitSize; + jint isUsed; // flag to indicate whether the raster sample model is SPPSM } SPPSampleModelS_t; /* Struct that holds information for the Raster object */ From 6ddbe35ee2793eb0ebc52b013e46b65d25c804dc Mon Sep 17 00:00:00 2001 From: Denis Fokin Date: Mon, 26 Nov 2012 20:49:54 +0400 Subject: [PATCH 031/180] 7186952: Improve clipboard access Reviewed-by: serb, ahgross --- .../share/classes/java/awt/TextComponent.java | 25 ++++++------------- .../native/sun/windows/awt_TextComponent.cpp | 22 ++++++++-------- .../native/sun/windows/awt_TextComponent.h | 3 +-- 3 files changed, 18 insertions(+), 32 deletions(-) diff --git a/jdk/src/share/classes/java/awt/TextComponent.java b/jdk/src/share/classes/java/awt/TextComponent.java index c99cae403a4..838c7c9dd3c 100644 --- a/jdk/src/share/classes/java/awt/TextComponent.java +++ b/jdk/src/share/classes/java/awt/TextComponent.java @@ -109,12 +109,6 @@ public class TextComponent extends Component implements Accessible { // the background color of non-editable TextComponents. boolean backgroundSetByClientCode = false; - /** - * True if this TextComponent has access - * to the System clipboard. - */ - transient private boolean canAccessClipboard; - transient protected TextListener textListener; /* @@ -139,7 +133,6 @@ public class TextComponent extends Component implements Accessible { GraphicsEnvironment.checkHeadless(); this.text = (text != null) ? text : ""; setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); - checkSystemClipboardAccess(); } private void enableInputMethodsIfNecessary() { @@ -734,17 +727,14 @@ public class TextComponent extends Component implements Accessible { /** * Assigns a valid value to the canAccessClipboard instance variable. */ - private void checkSystemClipboardAccess() { - canAccessClipboard = true; + private boolean canAccessClipboard() { SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - try { - sm.checkSystemClipboardAccess(); - } - catch (SecurityException e) { - canAccessClipboard = false; - } - } + if (sm == null) return true; + try { + sm.checkSystemClipboardAccess(); + return true; + } catch (SecurityException e) {} + return false; } /* @@ -827,7 +817,6 @@ public class TextComponent extends Component implements Accessible { } } enableInputMethodsIfNecessary(); - checkSystemClipboardAccess(); } diff --git a/jdk/src/windows/native/sun/windows/awt_TextComponent.cpp b/jdk/src/windows/native/sun/windows/awt_TextComponent.cpp index f16ba6c345c..eddcbca4088 100644 --- a/jdk/src/windows/native/sun/windows/awt_TextComponent.cpp +++ b/jdk/src/windows/native/sun/windows/awt_TextComponent.cpp @@ -53,14 +53,12 @@ struct EnableEditingStruct { * AwtTextComponent fields */ -/* java.awt.TextComponent fields */ -jfieldID AwtTextComponent::canAccessClipboardID; - - /************************************************************************ * AwtTextComponent methods */ +jmethodID AwtTextComponent::canAccessClipboardMID; + AwtTextComponent::AwtTextComponent() { m_synthetic = FALSE; m_lStartPos = -1; @@ -367,8 +365,7 @@ AwtTextComponent::WmPaste() } jobject target = GetTarget(env); jboolean canAccessClipboard = - env->GetBooleanField(target, - AwtTextComponent::canAccessClipboardID); + env->CallBooleanMethod (target, AwtTextComponent::canAccessClipboardMID); env->DeleteLocalRef(target); return (canAccessClipboard) ? mrDoDefault : mrConsume; } @@ -854,12 +851,13 @@ Java_sun_awt_windows_WTextComponentPeer_initIDs(JNIEnv *env, jclass cls) { TRY; - cls = env->FindClass("java/awt/TextComponent"); - if (cls != NULL) { - AwtTextComponent::canAccessClipboardID = - env->GetFieldID(cls, "canAccessClipboard", "Z"); - DASSERT(AwtTextComponent::canAccessClipboardID != NULL); - } + jclass textComponentClassID = env->FindClass("java/awt/TextComponent"); + AwtTextComponent::canAccessClipboardMID = + env->GetMethodID(textComponentClassID, + "canAccessClipboard", "()Z"); + env->DeleteLocalRef(textComponentClassID); + + DASSERT(AwtTextComponent::canAccessClipboardMID != NULL); CATCH_BAD_ALLOC; } diff --git a/jdk/src/windows/native/sun/windows/awt_TextComponent.h b/jdk/src/windows/native/sun/windows/awt_TextComponent.h index e50219cd271..cc0fc97f780 100644 --- a/jdk/src/windows/native/sun/windows/awt_TextComponent.h +++ b/jdk/src/windows/native/sun/windows/awt_TextComponent.h @@ -42,8 +42,7 @@ class AwtTextComponent : public AwtComponent { public: - /* java.awt.TextComponent canAccessClipboard field ID */ - static jfieldID canAccessClipboardID; + static jmethodID canAccessClipboardMID; AwtTextComponent(); From 7dde39f4f5a8075a71cd57eee4c5418aaed1aa24 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Mon, 26 Nov 2012 22:49:06 -0800 Subject: [PATCH 032/180] 6664509: Add logging context 6664528: Find log level matching its name or value given at construction time Reviewed-by: alanb, ahgross, jgish, hawtin --- .../classes/java/util/logging/Level.java | 255 +++++++-- .../classes/java/util/logging/LogManager.java | 531 +++++++++++------- .../classes/java/util/logging/Logger.java | 67 ++- .../classes/java/util/logging/Logging.java | 10 +- .../java/util/logging/LoggingProxyImpl.java | 11 +- .../java/util/logging/SimpleFormatter.java | 2 +- jdk/src/share/classes/sun/awt/AppContext.java | 39 +- .../share/classes/sun/misc/JavaAWTAccess.java | 8 + jdk/src/share/lib/security/java.security | 6 + 9 files changed, 678 insertions(+), 251 deletions(-) diff --git a/jdk/src/share/classes/java/util/logging/Level.java b/jdk/src/share/classes/java/util/logging/Level.java index 286ed5e6008..6847518ce02 100644 --- a/jdk/src/share/classes/java/util/logging/Level.java +++ b/jdk/src/share/classes/java/util/logging/Level.java @@ -24,6 +24,10 @@ */ package java.util.logging; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.ResourceBundle; /** @@ -59,7 +63,6 @@ import java.util.ResourceBundle; */ public class Level implements java.io.Serializable { - private static java.util.ArrayList known = new java.util.ArrayList<>(); private static String defaultBundle = "sun.util.logging.resources.logging"; /** @@ -77,6 +80,9 @@ public class Level implements java.io.Serializable { */ private final String resourceBundleName; + // localized level name + private String localizedLevelName; + /** * OFF is a special level that can be used to turn off logging. * This level is initialized to Integer.MAX_VALUE. @@ -202,9 +208,8 @@ public class Level implements java.io.Serializable { this.name = name; this.value = value; this.resourceBundleName = resourceBundleName; - synchronized (Level.class) { - known.add(this); - } + this.localizedLevelName = resourceBundleName == null ? name : null; + KnownLevel.add(this); } /** @@ -236,12 +241,76 @@ public class Level implements java.io.Serializable { * @return localized name */ public String getLocalizedName() { + return getLocalizedLevelName(); + } + + // package-private getLevelName() is used by the implementation + // instead of getName() to avoid calling the subclass's version + final String getLevelName() { + return this.name; + } + + final synchronized String getLocalizedLevelName() { + if (localizedLevelName != null) { + return localizedLevelName; + } + try { ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName); - return rb.getString(name); + localizedLevelName = rb.getString(name); } catch (Exception ex) { - return name; + localizedLevelName = name; } + return localizedLevelName; + } + + // Returns a mirrored Level object that matches the given name as + // specified in the Level.parse method. Returns null if not found. + // + // It returns the same Level object as the one returned by Level.parse + // method if the given name is a non-localized name or integer. + // + // If the name is a localized name, findLevel and parse method may + // return a different level value if there is a custom Level subclass + // that overrides Level.getLocalizedName() to return a different string + // than what's returned by the default implementation. + // + static Level findLevel(String name) { + if (name == null) { + throw new NullPointerException(); + } + + KnownLevel level; + + // Look for a known Level with the given non-localized name. + level = KnownLevel.findByName(name); + if (level != null) { + return level.mirroredLevel; + } + + // Now, check if the given name is an integer. If so, + // first look for a Level with the given value and then + // if necessary create one. + try { + int x = Integer.parseInt(name); + level = KnownLevel.findByValue(x); + if (level == null) { + // add new Level + Level levelObject = new Level(name, x); + level = KnownLevel.findByValue(x); + } + return level.mirroredLevel; + } catch (NumberFormatException ex) { + // Not an integer. + // Drop through. + } + + level = KnownLevel.findByLocalizedLevelName(name); + if (level != null) { + return level.mirroredLevel; + } + + return null; } /** @@ -268,21 +337,15 @@ public class Level implements java.io.Serializable { // Serialization magic to prevent "doppelgangers". // This is a performance optimization. private Object readResolve() { - synchronized (Level.class) { - for (int i = 0; i < known.size(); i++) { - Level other = known.get(i); - if (this.name.equals(other.name) && this.value == other.value - && (this.resourceBundleName == other.resourceBundleName || - (this.resourceBundleName != null && - this.resourceBundleName.equals(other.resourceBundleName)))) { - return other; - } - } - // Woops. Whoever sent us this object knows - // about a new log level. Add it to our list. - known.add(this); - return this; + KnownLevel o = KnownLevel.matches(this); + if (o != null) { + return o.levelObject; } + + // Woops. Whoever sent us this object knows + // about a new log level. Add it to our list. + Level level = new Level(this.name, this.value, this.resourceBundleName); + return level; } /** @@ -296,6 +359,7 @@ public class Level implements java.io.Serializable { *
  • "SEVERE" *
  • "1000" * + * * @param name string to be parsed * @throws NullPointerException if the name is null * @throws IllegalArgumentException if the value is not valid. @@ -315,12 +379,12 @@ public class Level implements java.io.Serializable { // Check that name is not null. name.length(); + KnownLevel level; + // Look for a known Level with the given non-localized name. - for (int i = 0; i < known.size(); i++) { - Level l = known.get(i); - if (name.equals(l.name)) { - return l; - } + level = KnownLevel.findByName(name); + if (level != null) { + return level.levelObject; } // Now, check if the given name is an integer. If so, @@ -328,14 +392,13 @@ public class Level implements java.io.Serializable { // if necessary create one. try { int x = Integer.parseInt(name); - for (int i = 0; i < known.size(); i++) { - Level l = known.get(i); - if (l.value == x) { - return l; - } + level = KnownLevel.findByValue(x); + if (level == null) { + // add new Level + Level levelObject = new Level(name, x); + level = KnownLevel.findByValue(x); } - // Create a new Level. - return new Level(name, x); + return level.levelObject; } catch (NumberFormatException ex) { // Not an integer. // Drop through. @@ -344,11 +407,9 @@ public class Level implements java.io.Serializable { // Finally, look for a known level with the given localized name, // in the current default locale. // This is relatively expensive, but not excessively so. - for (int i = 0; i < known.size(); i++) { - Level l = known.get(i); - if (name.equals(l.getLocalizedName())) { - return l; - } + level = KnownLevel.findByLocalizedName(name); + if (level != null) { + return level.levelObject; } // OK, we've tried everything and failed @@ -375,4 +436,124 @@ public class Level implements java.io.Serializable { public int hashCode() { return this.value; } + + // KnownLevel class maintains the global list of all known levels. + // The API allows multiple custom Level instances of the same name/value + // be created. This class provides convenient methods to find a level + // by a given name, by a given value, or by a given localized name. + // + // KnownLevel wraps the following Level objects: + // 1. levelObject: standard Level object or custom Level object + // 2. mirroredLevel: Level object representing the level specified in the + // logging configuration. + // + // Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods + // are non-final but the name and resource bundle name are parameters to + // the Level constructor. Use the mirroredLevel object instead of the + // levelObject to prevent the logging framework to execute foreign code + // implemented by untrusted Level subclass. + // + // Implementation Notes: + // If Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods + // were final, the following KnownLevel implementation can be removed. + // Future API change should take this into consideration. + static final class KnownLevel { + private static Map> nameToLevels = new HashMap<>(); + private static Map> intToLevels = new HashMap<>(); + final Level levelObject; // instance of Level class or Level subclass + final Level mirroredLevel; // instance of Level class + KnownLevel(Level l) { + this.levelObject = l; + if (l.getClass() == Level.class) { + this.mirroredLevel = l; + } else { + this.mirroredLevel = new Level(l.name, l.value, l.resourceBundleName); + } + } + + static synchronized void add(Level l) { + // the mirroredLevel object is always added to the list + // before the custom Level instance + KnownLevel o = new KnownLevel(l); + List list = nameToLevels.get(l.name); + if (list == null) { + list = new ArrayList<>(); + nameToLevels.put(l.name, list); + } + list.add(o); + + list = intToLevels.get(l.value); + if (list == null) { + list = new ArrayList<>(); + intToLevels.put(l.value, list); + } + list.add(o); + } + + // Returns a KnownLevel with the given non-localized name. + static synchronized KnownLevel findByName(String name) { + List list = nameToLevels.get(name); + if (list != null) { + return list.get(0); + } + return null; + } + + // Returns a KnownLevel with the given value. + static synchronized KnownLevel findByValue(int value) { + List list = intToLevels.get(value); + if (list != null) { + return list.get(0); + } + return null; + } + + // Returns a KnownLevel with the given localized name matching + // by calling the Level.getLocalizedLevelName() method (i.e. found + // from the resourceBundle associated with the Level object). + // This method does not call Level.getLocalizedName() that may + // be overridden in a subclass implementation + static synchronized KnownLevel findByLocalizedLevelName(String name) { + for (List levels : nameToLevels.values()) { + for (KnownLevel l : levels) { + String lname = l.levelObject.getLocalizedLevelName(); + if (name.equals(lname)) { + return l; + } + } + } + return null; + } + + // Returns a KnownLevel with the given localized name matching + // by calling the Level.getLocalizedName() method + static synchronized KnownLevel findByLocalizedName(String name) { + for (List levels : nameToLevels.values()) { + for (KnownLevel l : levels) { + String lname = l.levelObject.getLocalizedName(); + if (name.equals(lname)) { + return l; + } + } + } + return null; + } + + static synchronized KnownLevel matches(Level l) { + List list = nameToLevels.get(l.name); + if (list != null) { + for (KnownLevel level : list) { + Level other = level.mirroredLevel; + if (l.value == other.value && + (l.resourceBundleName == other.resourceBundleName || + (l.resourceBundleName != null && + l.resourceBundleName.equals(other.resourceBundleName)))) { + return level; + } + } + } + return null; + } + } + } diff --git a/jdk/src/share/classes/java/util/logging/LogManager.java b/jdk/src/share/classes/java/util/logging/LogManager.java index bfdf83f93da..78c90acee7d 100644 --- a/jdk/src/share/classes/java/util/logging/LogManager.java +++ b/jdk/src/share/classes/java/util/logging/LogManager.java @@ -34,6 +34,8 @@ import java.lang.ref.WeakReference; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; import java.net.URL; +import sun.misc.JavaAWTAccess; +import sun.misc.SharedSecrets; import sun.security.action.GetPropertyAction; /** @@ -157,10 +159,9 @@ public class LogManager { // count to allow for cases where the same listener is registered many times. private final Map listenerMap = new HashMap<>(); - // Table of named Loggers that maps names to Loggers. - private Hashtable namedLoggers = new Hashtable<>(); - // Tree of named Loggers - private LogNode root = new LogNode(null); + // LoggerContext for system loggers and user loggers + private final LoggerContext systemContext = new SystemLoggerContext(); + private final LoggerContext userContext = new UserLoggerContext(); private Logger rootLogger; // Have we done the primordial reading of the configuration file? @@ -198,12 +199,13 @@ public class LogManager { // Create and retain Logger for the root of the namespace. manager.rootLogger = manager.new RootLogger(); - manager.addLogger(manager.rootLogger); + manager.systemContext.addLogger(manager.rootLogger); + manager.userContext.addLogger(manager.rootLogger); // Adding the global Logger. Doing so in the Logger. // would deadlock with the LogManager.. Logger.getGlobal().setLogManager(manager); - manager.addLogger(Logger.getGlobal()); + manager.systemContext.addLogger(Logger.getGlobal()); // We don't call readConfiguration() here, as we may be running // very early in the JVM startup sequence. Instead readConfiguration @@ -281,14 +283,14 @@ public class LogManager { return; } readPrimordialConfiguration = true; + try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws Exception { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Void run() throws Exception { readConfiguration(); // Platform loggers begin to delegate to java.util.logging.Logger sun.util.logging.PlatformLogger.redirectPlatformLoggers(); - return null; } }); @@ -358,62 +360,290 @@ public class LogManager { } } - // Package-level method. - // Find or create a specified logger instance. If a logger has - // already been created with the given name it is returned. - // Otherwise a new logger instance is created and registered - // in the LogManager global namespace. + // Returns the LoggerContext for the user code (i.e. application or AppContext). + // Loggers are isolated from each AppContext. + LoggerContext getUserContext() { + LoggerContext context = null; - // This method will always return a non-null Logger object. - // Synchronization is not required here. All synchronization for - // adding a new Logger object is handled by addLogger(). - Logger demandLogger(String name) { - Logger result = getLogger(name); - if (result == null) { - // only allocate the new logger once - Logger newLogger = new Logger(name, null); - do { - if (addLogger(newLogger)) { - // We successfully added the new Logger that we - // created above so return it without refetching. - return newLogger; + SecurityManager sm = System.getSecurityManager(); + JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess(); + if (sm != null && javaAwtAccess != null) { + synchronized (javaAwtAccess) { + // AppContext.getAppContext() returns the system AppContext if called + // from a system thread but Logger.getLogger might be called from + // an applet code. Instead, find the AppContext of the applet code + // from the execution stack. + Object ecx = javaAwtAccess.getExecutionContext(); + if (ecx == null) { + // fall back to AppContext.getAppContext() + ecx = javaAwtAccess.getContext(); } - - // We didn't add the new Logger that we created above - // because another thread added a Logger with the same - // name after our null check above and before our call - // to addLogger(). We have to refetch the Logger because - // addLogger() returns a boolean instead of the Logger - // reference itself. However, if the thread that created - // the other Logger is not holding a strong reference to - // the other Logger, then it is possible for the other - // Logger to be GC'ed after we saw it in addLogger() and - // before we can refetch it. If it has been GC'ed then - // we'll just loop around and try again. - result = getLogger(name); - } while (result == null); + context = (LoggerContext)javaAwtAccess.get(ecx, LoggerContext.class); + if (context == null) { + if (javaAwtAccess.isMainAppContext()) { + context = userContext; + } else { + context = new UserLoggerContext(); + context.addLogger(manager.rootLogger); + } + javaAwtAccess.put(ecx, LoggerContext.class, context); + } + } + } else { + context = userContext; } - return result; + return context; } - // If logger.getUseParentHandlers() returns 'true' and any of the logger's - // parents have levels or handlers defined, make sure they are instantiated. - private void processParentHandlers(Logger logger, String name) { - int ix = 1; - for (;;) { - int ix2 = name.indexOf(".", ix); - if (ix2 < 0) { - break; - } - String pname = name.substring(0,ix2); + LoggerContext getSystemContext() { + return systemContext; + } - if (getProperty(pname+".level") != null || - getProperty(pname+".handlers") != null) { - // This pname has a level/handlers definition. - // Make sure it exists. - demandLogger(pname); + private List contexts() { + List cxs = new ArrayList<>(); + cxs.add(systemContext); + cxs.add(getUserContext()); + return cxs; + } + + static class LoggerContext { + // Table of named Loggers that maps names to Loggers. + private final Hashtable namedLoggers = new Hashtable<>(); + // Tree of named Loggers + private final LogNode root; + + private LoggerContext() { + this.root = new LogNode(null, this); + } + + synchronized Logger findLogger(String name) { + LoggerWeakRef ref = namedLoggers.get(name); + if (ref == null) { + return null; } - ix = ix2+1; + Logger logger = ref.get(); + if (logger == null) { + // Hashtable holds stale weak reference + // to a logger which has been GC-ed. + removeLogger(name); + } + return logger; + } + + synchronized boolean addLogger(Logger logger) { + final String name = logger.getName(); + if (name == null) { + throw new NullPointerException(); + } + + // cleanup some Loggers that have been GC'ed + manager.drainLoggerRefQueueBounded(); + + LoggerWeakRef ref = namedLoggers.get(name); + if (ref != null) { + if (ref.get() == null) { + // It's possible that the Logger was GC'ed after the + // drainLoggerRefQueueBounded() call above so allow + // a new one to be registered. + removeLogger(name); + } else { + // We already have a registered logger with the given name. + return false; + } + } + + // We're adding a new logger. + // Note that we are creating a weak reference here. + ref = manager.new LoggerWeakRef(logger); + namedLoggers.put(name, ref); + + // Apply any initial level defined for the new logger. + Level level = manager.getLevelProperty(name + ".level", null); + if (level != null) { + doSetLevel(logger, level); + } + + // Do we have a per logger handler too? + // Note: this will add a 200ms penalty + manager.loadLoggerHandlers(logger, name, name + ".handlers"); + processParentHandlers(logger, name); + + // Find the new node and its parent. + LogNode node = getNode(name); + node.loggerRef = ref; + Logger parent = null; + LogNode nodep = node.parent; + while (nodep != null) { + LoggerWeakRef nodeRef = nodep.loggerRef; + if (nodeRef != null) { + parent = nodeRef.get(); + if (parent != null) { + break; + } + } + nodep = nodep.parent; + } + + if (parent != null) { + doSetParent(logger, parent); + } + // Walk over the children and tell them we are their new parent. + node.walkAndSetParent(logger); + // new LogNode is ready so tell the LoggerWeakRef about it + ref.setNode(node); + return true; + } + + void removeLogger(String name) { + namedLoggers.remove(name); + } + + synchronized Enumeration getLoggerNames() { + return namedLoggers.keys(); + } + + Logger demandLogger(String name) { + return demandLogger(name, null); + } + + // Find or create a specified logger instance. If a logger has + // already been created with the given name it is returned. + // Otherwise a new logger instance is created and registered + // in the LogManager global namespace. + + // This method will always return a non-null Logger object. + // Synchronization is not required here. All synchronization for + // adding a new Logger object is handled by addLogger(). + Logger demandLogger(String name, String resourceBundleName) { + Logger result = findLogger(name); + if (result == null) { + // only allocate the new logger once + Logger newLogger = new Logger(name, resourceBundleName); + do { + if (addLogger(newLogger)) { + // We successfully added the new Logger that we + // created above so return it without refetching. + return newLogger; + } + + // We didn't add the new Logger that we created above + // because another thread added a Logger with the same + // name after our null check above and before our call + // to addLogger(). We have to refetch the Logger because + // addLogger() returns a boolean instead of the Logger + // reference itself. However, if the thread that created + // the other Logger is not holding a strong reference to + // the other Logger, then it is possible for the other + // Logger to be GC'ed after we saw it in addLogger() and + // before we can refetch it. If it has been GC'ed then + // we'll just loop around and try again. + result = findLogger(name); + } while (result == null); + } + return result; + } + + // If logger.getUseParentHandlers() returns 'true' and any of the logger's + // parents have levels or handlers defined, make sure they are instantiated. + private void processParentHandlers(Logger logger, String name) { + int ix = 1; + for (;;) { + int ix2 = name.indexOf(".", ix); + if (ix2 < 0) { + break; + } + String pname = name.substring(0, ix2); + + if (manager.getProperty(pname + ".level") != null || + manager.getProperty(pname + ".handlers") != null) { + // This pname has a level/handlers definition. + // Make sure it exists. + demandLogger(pname); + } + ix = ix2+1; + } + } + + // Gets a node in our tree of logger nodes. + // If necessary, create it. + LogNode getNode(String name) { + if (name == null || name.equals("")) { + return root; + } + LogNode node = root; + while (name.length() > 0) { + int ix = name.indexOf("."); + String head; + if (ix > 0) { + head = name.substring(0, ix); + name = name.substring(ix + 1); + } else { + head = name; + name = ""; + } + if (node.children == null) { + node.children = new HashMap<>(); + } + LogNode child = node.children.get(head); + if (child == null) { + child = new LogNode(node, this); + node.children.put(head, child); + } + node = child; + } + return node; + } + } + + static class SystemLoggerContext extends LoggerContext { + // Default resource bundle for all system loggers + Logger demandLogger(String name) { + // default to use the system logger's resource bundle + return super.demandLogger(name, Logger.SYSTEM_LOGGER_RB_NAME); + } + } + + static class UserLoggerContext extends LoggerContext { + /** + * Returns a Logger of the given name if there is one registered + * in this context. Otherwise, it will return the one registered + * in the system context if there is one. The returned Logger + * instance may be initialized with a different resourceBundleName. + * If no such logger exists, a new Logger instance will be created + * and registered in this context. + */ + Logger demandLogger(String name, String resourceBundleName) { + Logger result = findLogger(name); + if (result == null) { + // use the system logger if exists; or allocate a new logger. + // The system logger is added to the app logger context so that + // any child logger created in the app logger context can have + // a system logger as its parent if already exist. + Logger logger = manager.systemContext.findLogger(name); + Logger newLogger = + logger != null ? logger : new Logger(name, resourceBundleName); + do { + if (addLogger(newLogger)) { + // We successfully added the new Logger that we + // created above so return it without refetching. + return newLogger; + } + + // We didn't add the new Logger that we created above + // because another thread added a Logger with the same + // name after our null check above and before our call + // to addLogger(). We have to refetch the Logger because + // addLogger() returns a boolean instead of the Logger + // reference itself. However, if the thread that created + // the other Logger is not holding a strong reference to + // the other Logger, then it is possible for the other + // Logger to be GC'ed after we saw it in addLogger() and + // before we can refetch it. If it has been GC'ed then + // we'll just loop around and try again. + result = findLogger(name); + } while (result == null); + } + return result; } } @@ -438,16 +668,17 @@ public class LogManager { try { Class clz = ClassLoader.getSystemClassLoader().loadClass(word); Handler hdl = (Handler) clz.newInstance(); - try { - // Check if there is a property defining the - // this handler's level. - String levs = getProperty(word + ".level"); - if (levs != null) { - hdl.setLevel(Level.parse(levs)); + // Check if there is a property defining the + // this handler's level. + String levs = getProperty(word + ".level"); + if (levs != null) { + Level l = Level.findLevel(levs); + if (l != null) { + hdl.setLevel(l); + } else { + // Probably a bad level. Drop through. + System.err.println("Can't set level for " + word); } - } catch (Exception ex) { - System.err.println("Can't set level for " + word); - // Probably a bad level. Drop through. } // Add this Handler to the logger logger.addHandler(hdl); @@ -503,7 +734,7 @@ public class LogManager { if (node != null) { // if we have a LogNode, then we were a named Logger // so clear namedLoggers weak ref to us - manager.namedLoggers.remove(name); + node.context.removeLogger(name); name = null; // clear our ref to the Logger's name node.loggerRef = null; // clear LogNode's weak ref to us @@ -592,70 +823,15 @@ public class LogManager { * false if a logger of that name already exists. * @exception NullPointerException if the logger name is null. */ - public synchronized boolean addLogger(Logger logger) { + public boolean addLogger(Logger logger) { final String name = logger.getName(); if (name == null) { throw new NullPointerException(); } - - // cleanup some Loggers that have been GC'ed - drainLoggerRefQueueBounded(); - - LoggerWeakRef ref = namedLoggers.get(name); - if (ref != null) { - if (ref.get() == null) { - // It's possible that the Logger was GC'ed after the - // drainLoggerRefQueueBounded() call above so allow - // a new one to be registered. - namedLoggers.remove(name); - } else { - // We already have a registered logger with the given name. - return false; - } + if (systemContext.findLogger(name) != null) { + return false; } - - // We're adding a new logger. - // Note that we are creating a weak reference here. - ref = new LoggerWeakRef(logger); - namedLoggers.put(name, ref); - - // Apply any initial level defined for the new logger. - Level level = getLevelProperty(name+".level", null); - if (level != null) { - doSetLevel(logger, level); - } - - // Do we have a per logger handler too? - // Note: this will add a 200ms penalty - loadLoggerHandlers(logger, name, name+".handlers"); - processParentHandlers(logger, name); - - // Find the new node and its parent. - LogNode node = findNode(name); - node.loggerRef = ref; - Logger parent = null; - LogNode nodep = node.parent; - while (nodep != null) { - LoggerWeakRef nodeRef = nodep.loggerRef; - if (nodeRef != null) { - parent = nodeRef.get(); - if (parent != null) { - break; - } - } - nodep = nodep.parent; - } - - if (parent != null) { - doSetParent(logger, parent); - } - // Walk over the children and tell them we are their new parent. - node.walkAndSetParent(logger); - - // new LogNode is ready so tell the LoggerWeakRef about it - ref.setNode(node); - - return true; + return getUserContext().addLogger(logger); } @@ -697,36 +873,6 @@ public class LogManager { }}); } - // Find a node in our tree of logger nodes. - // If necessary, create it. - private LogNode findNode(String name) { - if (name == null || name.equals("")) { - return root; - } - LogNode node = root; - while (name.length() > 0) { - int ix = name.indexOf("."); - String head; - if (ix > 0) { - head = name.substring(0,ix); - name = name.substring(ix+1); - } else { - head = name; - name = ""; - } - if (node.children == null) { - node.children = new HashMap<>(); - } - LogNode child = node.children.get(head); - if (child == null) { - child = new LogNode(node); - node.children.put(head, child); - } - node = child; - } - return node; - } - /** * Method to find a named logger. *

    @@ -742,18 +888,16 @@ public class LogManager { * @param name name of the logger * @return matching logger or null if none is found */ - public synchronized Logger getLogger(String name) { - LoggerWeakRef ref = namedLoggers.get(name); - if (ref == null) { - return null; - } - Logger logger = ref.get(); - if (logger == null) { - // Hashtable holds stale weak reference - // to a logger which has been GC-ed. - namedLoggers.remove(name); - } - return logger; + public Logger getLogger(String name) { + // return the first logger added + // + // once a system logger is added in the system context, no one can + // adds a logger with the same name in the global context + // (see LogManager.addLogger). So if there is a logger in the global + // context with the same name as one in the system context, it must be + // added before the system logger was created. + Logger logger = getUserContext().findLogger(name); + return logger != null ? logger : systemContext.findLogger(name); } /** @@ -772,8 +916,11 @@ public class LogManager { *

    * @return enumeration of logger name strings */ - public synchronized Enumeration getLoggerNames() { - return namedLoggers.keys(); + public Enumeration getLoggerNames() { + // only return unique names + Set names = new HashSet<>(Collections.list(systemContext.getLoggerNames())); + names.addAll(Collections.list(getUserContext().getLoggerNames())); + return Collections.enumeration(names); } /** @@ -858,20 +1005,20 @@ public class LogManager { // the global handlers, if they haven't been initialized yet. initializedGlobalHandlers = true; } - Enumeration enum_ = getLoggerNames(); - while (enum_.hasMoreElements()) { - String name = enum_.nextElement(); - resetLogger(name); + for (LoggerContext cx : contexts()) { + Enumeration enum_ = cx.getLoggerNames(); + while (enum_.hasMoreElements()) { + String name = enum_.nextElement(); + Logger logger = cx.findLogger(name); + if (logger != null) { + resetLogger(logger); + } + } } } - // Private method to reset an individual target logger. - private void resetLogger(String name) { - Logger logger = getLogger(name); - if (logger == null) { - return; - } + private void resetLogger(Logger logger) { // Close all the Logger's handlers. Handler[] targets = logger.getHandlers(); for (int i = 0; i < targets.length; i++) { @@ -883,6 +1030,7 @@ public class LogManager { // Problems closing a handler? Keep going... } } + String name = logger.getName(); if (name != null && name.equals("")) { // This is the root logger. logger.setLevel(defaultLevel); @@ -1046,11 +1194,8 @@ public class LogManager { if (val == null) { return defaultValue; } - try { - return Level.parse(val.trim()); - } catch (Exception ex) { - return defaultValue; - } + Level l = Level.findLevel(val.trim()); + return l != null ? l : defaultValue; } // Package private method to get a filter property. @@ -1140,9 +1285,11 @@ public class LogManager { HashMap children; LoggerWeakRef loggerRef; LogNode parent; + final LoggerContext context; - LogNode(LogNode parent) { + LogNode(LogNode parent, LoggerContext context) { this.parent = parent; + this.context = context; } // Recursive method to walk the tree below a node and set @@ -1215,11 +1362,13 @@ public class LogManager { System.err.println("Bad level value for property: " + key); continue; } - Logger l = getLogger(name); - if (l == null) { - continue; + for (LoggerContext cx : contexts()) { + Logger l = cx.findLogger(name); + if (l == null) { + continue; + } + l.setLevel(level); } - l.setLevel(level); } } diff --git a/jdk/src/share/classes/java/util/logging/Logger.java b/jdk/src/share/classes/java/util/logging/Logger.java index f1d6f729b91..fec3d5c9a64 100644 --- a/jdk/src/share/classes/java/util/logging/Logger.java +++ b/jdk/src/share/classes/java/util/logging/Logger.java @@ -30,6 +30,7 @@ import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import java.security.*; import java.lang.ref.WeakReference; +import java.util.logging.LogManager.LoggerContext; /** * A Logger object is used to log messages for a specific @@ -286,6 +287,26 @@ public class Logger { } } + // Until all JDK code converted to call sun.util.logging.PlatformLogger + // (see 7054233), we need to determine if Logger.getLogger is to add + // a system logger or user logger. + // + // As an interim solution, if the immediate caller whose caller loader is + // null, we assume it's a system logger and add it to the system context. + private static LoggerContext getLoggerContext() { + LogManager manager = LogManager.getLogManager(); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + // 0: Reflection 1: Logger.getLoggerContext 2: Logger.getLogger 3: caller + final int SKIP_FRAMES = 3; + Class caller = sun.reflect.Reflection.getCallerClass(SKIP_FRAMES); + if (caller.getClassLoader() == null) { + return manager.getSystemContext(); + } + } + return manager.getUserContext(); + } + /** * Find or create a logger for a named subsystem. If a logger has * already been created with the given name it is returned. Otherwise @@ -327,8 +348,8 @@ public class Logger { // would throw an IllegalArgumentException in the second call // because the wrapper would result in an attempt to replace // the existing "resourceBundleForFoo" with null. - LogManager manager = LogManager.getLogManager(); - return manager.demandLogger(name); + LoggerContext context = getLoggerContext(); + return context.demandLogger(name); } /** @@ -375,8 +396,8 @@ public class Logger { // Synchronization is not required here. All synchronization for // adding a new Logger object is handled by LogManager.addLogger(). public static Logger getLogger(String name, String resourceBundleName) { - LogManager manager = LogManager.getLogManager(); - Logger result = manager.demandLogger(name); + LoggerContext context = getLoggerContext(); + Logger result = context.demandLogger(name, resourceBundleName); // MissingResourceException or IllegalArgumentException can be // thrown by setupResourceInfo(). @@ -384,6 +405,18 @@ public class Logger { return result; } + // package-private + // Add a platform logger to the system context. + // i.e. caller of sun.util.logging.PlatformLogger.getLogger + static Logger getPlatformLogger(String name) { + LogManager manager = LogManager.getLogManager(); + LoggerContext context = manager.getSystemContext(); + + // all loggers in the system context will default to + // the system logger's resource bundle + Logger result = context.demandLogger(name); + return result; + } /** * Create an anonymous Logger. The newly created Logger is not @@ -536,7 +569,7 @@ public class Logger { private void doLog(LogRecord lr) { lr.setLoggerName(name); String ebname = getEffectiveResourceBundleName(); - if (ebname != null) { + if (ebname != null && !ebname.equals(SYSTEM_LOGGER_RB_NAME)) { lr.setResourceBundleName(ebname); lr.setResourceBundle(findResourceBundle(ebname)); } @@ -1285,6 +1318,22 @@ public class Logger { // May also return null if we can't find the resource bundle and // there is no suitable previous cached value. + static final String SYSTEM_LOGGER_RB_NAME = "sun.util.logging.resources.logging"; + + private static ResourceBundle findSystemResourceBundle(final Locale locale) { + // the resource bundle is in a restricted package + return AccessController.doPrivileged(new PrivilegedAction() { + public ResourceBundle run() { + try { + return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME, + locale); + } catch (MissingResourceException e) { + throw new InternalError(e.toString()); + } + } + }); + } + private synchronized ResourceBundle findResourceBundle(String name) { // Return a null bundle for a null name. if (name == null) { @@ -1299,6 +1348,13 @@ public class Logger { return catalog; } + if (name.equals(SYSTEM_LOGGER_RB_NAME)) { + catalog = findSystemResourceBundle(currentLocale); + catalogName = name; + catalogLocale = currentLocale; + return catalog; + } + // Use the thread's context ClassLoader. If there isn't one, // use the SystemClassloader. ClassLoader cl = Thread.currentThread().getContextClassLoader(); @@ -1315,7 +1371,6 @@ public class Logger { // ClassLoader. Drop through. } - // Fall back to searching up the call stack and trying each // calling ClassLoader. for (int ix = 0; ; ix++) { diff --git a/jdk/src/share/classes/java/util/logging/Logging.java b/jdk/src/share/classes/java/util/logging/Logging.java index 2492349188e..bf34046826d 100644 --- a/jdk/src/share/classes/java/util/logging/Logging.java +++ b/jdk/src/share/classes/java/util/logging/Logging.java @@ -34,7 +34,7 @@ import java.util.ArrayList; * * The LoggingMXBean interface provides a standard * method for management access to the individual - * java.util.Logger objects available at runtime. + * {@code Logger} objects available at runtime. * * @author Ron Mann * @author Mandy Chung @@ -75,7 +75,7 @@ class Logging implements LoggingMXBean { if (level == null) { return EMPTY_STRING; } else { - return level.getName(); + return level.getLevelName(); } } @@ -85,7 +85,6 @@ class Logging implements LoggingMXBean { } Logger logger = logManager.getLogger(loggerName); - if (logger == null) { throw new IllegalArgumentException("Logger " + loggerName + "does not exist"); @@ -94,7 +93,10 @@ class Logging implements LoggingMXBean { Level level = null; if (levelName != null) { // parse will throw IAE if logLevel is invalid - level = Level.parse(levelName); + level = Level.findLevel(levelName); + if (level == null) { + throw new IllegalArgumentException("Unknown level \"" + levelName + "\""); + } } logger.setLevel(level); diff --git a/jdk/src/share/classes/java/util/logging/LoggingProxyImpl.java b/jdk/src/share/classes/java/util/logging/LoggingProxyImpl.java index 8e027d66a47..dbb62a144e3 100644 --- a/jdk/src/share/classes/java/util/logging/LoggingProxyImpl.java +++ b/jdk/src/share/classes/java/util/logging/LoggingProxyImpl.java @@ -37,7 +37,8 @@ class LoggingProxyImpl implements LoggingProxy { @Override public Object getLogger(String name) { - return Logger.getLogger(name); + // always create a platform logger with the resource bundle name + return Logger.getPlatformLogger(name); } @Override @@ -92,12 +93,16 @@ class LoggingProxyImpl implements LoggingProxy { @Override public Object parseLevel(String levelName) { - return Level.parse(levelName); + Level level = Level.findLevel(levelName); + if (level == null) { + throw new IllegalArgumentException("Unknown level \"" + levelName + "\""); + } + return level; } @Override public String getLevelName(Object level) { - return ((Level) level).getName(); + return ((Level) level).getLevelName(); } @Override diff --git a/jdk/src/share/classes/java/util/logging/SimpleFormatter.java b/jdk/src/share/classes/java/util/logging/SimpleFormatter.java index 87f2c7eeba6..af2b1dcb5f2 100644 --- a/jdk/src/share/classes/java/util/logging/SimpleFormatter.java +++ b/jdk/src/share/classes/java/util/logging/SimpleFormatter.java @@ -162,7 +162,7 @@ public class SimpleFormatter extends Formatter { dat, source, record.getLoggerName(), - record.getLevel().getLocalizedName(), + record.getLevel().getLocalizedLevelName(), message, throwable); } diff --git a/jdk/src/share/classes/sun/awt/AppContext.java b/jdk/src/share/classes/sun/awt/AppContext.java index 0756b6c82bd..47f472737ea 100644 --- a/jdk/src/share/classes/sun/awt/AppContext.java +++ b/jdk/src/share/classes/sun/awt/AppContext.java @@ -327,21 +327,27 @@ public final class AppContext { // Before we return the main "system" AppContext, check to // see if there's an AWTSecurityManager installed. If so, // allow it to choose the AppContext to return. - SecurityManager securityManager = System.getSecurityManager(); - if ((securityManager != null) && - (securityManager instanceof AWTSecurityManager)) - { - AWTSecurityManager awtSecMgr = (AWTSecurityManager)securityManager; - AppContext secAppContext = awtSecMgr.getAppContext(); - if (secAppContext != null) { - appContext = secAppContext; // Return what we're told - } + AppContext secAppContext = getExecutionAppContext(); + if (secAppContext != null) { + appContext = secAppContext; // Return what we're told } } return appContext; } + private final static AppContext getExecutionAppContext() { + SecurityManager securityManager = System.getSecurityManager(); + if ((securityManager != null) && + (securityManager instanceof AWTSecurityManager)) + { + AWTSecurityManager awtSecMgr = (AWTSecurityManager) securityManager; + AppContext secAppContext = awtSecMgr.getAppContext(); + return secAppContext; // Return what we're told + } + return null; + } + /** * Returns the main ("system") AppContext. * @@ -806,6 +812,21 @@ public final class AppContext { public boolean isMainAppContext() { return (numAppContexts.get() == 1); } + public Object getContext() { + return getAppContext(); + } + public Object getExecutionContext() { + return getExecutionAppContext(); + } + public Object get(Object context, Object key) { + return ((AppContext)context).get(key); + } + public void put(Object context, Object key, Object value) { + ((AppContext)context).put(key, value); + } + public void remove(Object context, Object key) { + ((AppContext)context).remove(key); + } }); } } diff --git a/jdk/src/share/classes/sun/misc/JavaAWTAccess.java b/jdk/src/share/classes/sun/misc/JavaAWTAccess.java index 6e3712592ce..e64a38b22c9 100644 --- a/jdk/src/share/classes/sun/misc/JavaAWTAccess.java +++ b/jdk/src/share/classes/sun/misc/JavaAWTAccess.java @@ -26,6 +26,14 @@ package sun.misc; public interface JavaAWTAccess { + public Object getContext(); + public Object getExecutionContext(); + + public Object get(Object context, Object key); + public void put(Object context, Object key, Object value); + public void remove(Object context, Object key); + + // convenience methods whose context is the object returned by getContext() public Object get(Object key); public void put(Object key, Object value); public void remove(Object key); diff --git a/jdk/src/share/lib/security/java.security b/jdk/src/share/lib/security/java.security index d0dc3c5b423..741f0c2f64d 100644 --- a/jdk/src/share/lib/security/java.security +++ b/jdk/src/share/lib/security/java.security @@ -148,6 +148,9 @@ keystore.type=jks package.access=sun.,\ com.sun.xml.internal.,\ com.sun.imageio.,\ + com.sun.istack.internal.,\ + com.sun.jmx.default.,\ + com.sun.jmx.remote.util.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ @@ -166,6 +169,9 @@ package.access=sun.,\ package.definition=sun.,\ com.sun.xml.internal.,\ com.sun.imageio.,\ + com.sun.istack.internal.,\ + com.sun.jmx.default.,\ + com.sun.jmx.remote.util.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ From eb67f3f1da2cbf1eeb42f01d9cc778dbbd0820c9 Mon Sep 17 00:00:00 2001 From: Denis Fokin Date: Fri, 30 Nov 2012 15:51:44 +0400 Subject: [PATCH 033/180] 7201064: Better dialogue checking Reviewed-by: serb, skoivu --- jdk/src/share/classes/java/awt/Dialog.java | 55 ++++++++++++++++++---- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/jdk/src/share/classes/java/awt/Dialog.java b/jdk/src/share/classes/java/awt/Dialog.java index 800d19c0200..33ae6dde3b9 100644 --- a/jdk/src/share/classes/java/awt/Dialog.java +++ b/jdk/src/share/classes/java/awt/Dialog.java @@ -39,6 +39,7 @@ import sun.awt.PeerEvent; import sun.awt.util.IdentityArrayList; import sun.awt.util.IdentityLinkedList; import sun.security.util.SecurityConstants; +import java.security.AccessControlException; /** * A Dialog is a top-level window with a title and a border @@ -128,6 +129,8 @@ public class Dialog extends Window { */ boolean undecorated = false; + private transient boolean initialized = false; + /** * Modal dialogs block all input to some top-level windows. * Whether a particular window is blocked depends on dialog's type @@ -671,6 +674,7 @@ public class Dialog extends Window { this.title = title; setModalityType(modalityType); SunToolkit.checkAndSetPolicy(this); + initialized = true; } /** @@ -722,6 +726,7 @@ public class Dialog extends Window { this.title = title; setModalityType(modalityType); SunToolkit.checkAndSetPolicy(this); + initialized = true; } /** @@ -851,12 +856,9 @@ public class Dialog extends Window { if (modalityType == type) { return; } - if (type == ModalityType.TOOLKIT_MODAL) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(SecurityConstants.AWT.TOOLKIT_MODALITY_PERMISSION); - } - } + + checkModalityPermission(type); + modalityType = type; modal = (modalityType != ModalityType.MODELESS); } @@ -1025,6 +1027,11 @@ public class Dialog extends Window { */ @Deprecated public void show() { + if (!initialized) { + throw new IllegalStateException("The dialog component " + + "has not been initialized properly"); + } + beforeFirstShow = false; if (!isModal()) { conditionalShow(null, null); @@ -1600,18 +1607,50 @@ public class Dialog extends Window { } } + private void checkModalityPermission(ModalityType mt) { + if (mt == ModalityType.TOOLKIT_MODAL) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission( + SecurityConstants.AWT.TOOLKIT_MODALITY_PERMISSION + ); + } + } + } + private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException, HeadlessException { GraphicsEnvironment.checkHeadless(); - s.defaultReadObject(); + + java.io.ObjectInputStream.GetField fields = + s.readFields(); + + ModalityType localModalityType = (ModalityType)fields.get("modalityType", null); + + try { + checkModalityPermission(localModalityType); + } catch (AccessControlException ace) { + localModalityType = DEFAULT_MODALITY_TYPE; + } // in 1.5 or earlier modalityType was absent, so use "modal" instead - if (modalityType == null) { + if (localModalityType == null) { + this.modal = fields.get("modal", false); setModal(modal); } + this.resizable = fields.get("resizable", true); + this.undecorated = fields.get("undecorated", false); + this.title = (String)fields.get("title", ""); + this.modalityType = localModalityType; + blockedWindows = new IdentityArrayList(); + + SunToolkit.checkAndSetPolicy(this); + + initialized = true; + } /* From d093c6fbb64b8f9294756755e5e5349f2a616c83 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Wed, 5 Dec 2012 14:02:58 -0800 Subject: [PATCH 034/180] 8004175: Restricted packages added in java.security are missing in java.security-{macosx, solaris, windows} Reviewed-by: alanb, ahgross, mullan --- jdk/src/share/lib/security/java.security-macosx | 6 ++++++ jdk/src/share/lib/security/java.security-solaris | 6 ++++++ jdk/src/share/lib/security/java.security-windows | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/jdk/src/share/lib/security/java.security-macosx b/jdk/src/share/lib/security/java.security-macosx index 9a4f2964e79..5f4d82974ac 100644 --- a/jdk/src/share/lib/security/java.security-macosx +++ b/jdk/src/share/lib/security/java.security-macosx @@ -149,6 +149,9 @@ keystore.type=jks package.access=sun.,\ com.sun.xml.internal.,\ com.sun.imageio.,\ + com.sun.istack.internal.,\ + com.sun.jmx.defaults.,\ + com.sun.jmx.remote.util.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ @@ -168,6 +171,9 @@ package.access=sun.,\ package.definition=sun.,\ com.sun.xml.internal.,\ com.sun.imageio.,\ + com.sun.istack.internal.,\ + com.sun.jmx.defaults.,\ + com.sun.jmx.remote.util.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ diff --git a/jdk/src/share/lib/security/java.security-solaris b/jdk/src/share/lib/security/java.security-solaris index a5b1d577d2e..f8e6774e3a1 100644 --- a/jdk/src/share/lib/security/java.security-solaris +++ b/jdk/src/share/lib/security/java.security-solaris @@ -150,6 +150,9 @@ keystore.type=jks package.access=sun.,\ com.sun.xml.internal.,\ com.sun.imageio.,\ + com.sun.istack.internal.,\ + com.sun.jmx.defaults.,\ + com.sun.jmx.remote.util.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ @@ -168,6 +171,9 @@ package.access=sun.,\ package.definition=sun.,\ com.sun.xml.internal.,\ com.sun.imageio.,\ + com.sun.istack.internal.,\ + com.sun.jmx.defaults.,\ + com.sun.jmx.remote.util.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows index c2f0ebf8f21..d539f90be63 100644 --- a/jdk/src/share/lib/security/java.security-windows +++ b/jdk/src/share/lib/security/java.security-windows @@ -149,6 +149,9 @@ keystore.type=jks package.access=sun.,\ com.sun.xml.internal.,\ com.sun.imageio.,\ + com.sun.istack.internal.,\ + com.sun.jmx.defaults.,\ + com.sun.jmx.remote.util.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ @@ -167,6 +170,9 @@ package.access=sun.,\ package.definition=sun.,\ com.sun.xml.internal.,\ com.sun.imageio.,\ + com.sun.istack.internal.,\ + com.sun.jmx.defaults.,\ + com.sun.jmx.remote.util.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ From 07d6fc6bd103f05febb52e76796b6b08790c31d1 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Fri, 7 Dec 2012 22:49:08 +0400 Subject: [PATCH 035/180] 8000537: Contextualize RequiredModelMBean class Contextualize RequiredModelMBean class Reviewed-by: asaha --- .../modelmbean/RequiredModelMBean.java | 225 +++++++++++++----- 1 file changed, 172 insertions(+), 53 deletions(-) diff --git a/jdk/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java b/jdk/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java index c1600a94317..6d28adaf0f7 100644 --- a/jdk/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java +++ b/jdk/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -39,11 +39,13 @@ import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Date; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.logging.Level; import java.util.Map; import java.util.Set; @@ -78,6 +80,8 @@ import javax.management.RuntimeErrorException; import javax.management.RuntimeOperationsException; import javax.management.ServiceNotFoundException; import javax.management.loading.ClassLoaderRepository; +import sun.misc.JavaSecurityAccess; +import sun.misc.SharedSecrets; import sun.reflect.misc.MethodUtil; import sun.reflect.misc.ReflectUtil; @@ -138,6 +142,9 @@ public class RequiredModelMBean private boolean registered = false; private transient MBeanServer server = null; + private final static JavaSecurityAccess javaSecurityAccess = SharedSecrets.getJavaSecurityAccess(); + final private AccessControlContext acc = AccessController.getContext(); + /*************************************/ /* constructors */ /*************************************/ @@ -1025,10 +1032,31 @@ public class RequiredModelMBean if (opClassName != null) { try { - final ClassLoader targetClassLoader = - targetObject.getClass().getClassLoader(); - targetClass = Class.forName(opClassName, false, - targetClassLoader); + AccessControlContext stack = AccessController.getContext(); + final Object obj = targetObject; + final String className = opClassName; + final ClassNotFoundException[] caughtException = new ClassNotFoundException[1]; + + targetClass = javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction>() { + + @Override + public Class run() { + try { + ReflectUtil.checkPackageAccess(className); + final ClassLoader targetClassLoader = + obj.getClass().getClassLoader(); + return Class.forName(className, false, + targetClassLoader); + } catch (ClassNotFoundException e) { + caughtException[0] = e; + } + return null; + } + }, stack, acc); + + if (caughtException[0] != null) { + throw caughtException[0]; + } } catch (ClassNotFoundException e) { final String msg = "class for invoke " + opName + " not found"; @@ -1061,9 +1089,9 @@ public class RequiredModelMBean return result; } - private static Method resolveMethod(Class targetClass, + private Method resolveMethod(Class targetClass, String opMethodName, - String[] sig) + final String[] sig) throws ReflectionException { final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER); @@ -1078,30 +1106,45 @@ public class RequiredModelMBean if (sig == null) argClasses = null; else { + final AccessControlContext stack = AccessController.getContext(); + final ReflectionException[] caughtException = new ReflectionException[1]; final ClassLoader targetClassLoader = targetClass.getClassLoader(); argClasses = new Class[sig.length]; - for (int i = 0; i < sig.length; i++) { - if (tracing) { - MODELMBEAN_LOGGER.logp(Level.FINER, - RequiredModelMBean.class.getName(),"resolveMethod", - "resolve type " + sig[i]); - } - argClasses[i] = (Class) primitiveClassMap.get(sig[i]); - if (argClasses[i] == null) { - try { - argClasses[i] = - Class.forName(sig[i], false, targetClassLoader); - } catch (ClassNotFoundException e) { + + javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction() { + + @Override + public Void run() { + for (int i = 0; i < sig.length; i++) { if (tracing) { MODELMBEAN_LOGGER.logp(Level.FINER, - RequiredModelMBean.class.getName(), - "resolveMethod", - "class not found"); + RequiredModelMBean.class.getName(),"resolveMethod", + "resolve type " + sig[i]); + } + argClasses[i] = (Class) primitiveClassMap.get(sig[i]); + if (argClasses[i] == null) { + try { + ReflectUtil.checkPackageAccess(sig[i]); + argClasses[i] = + Class.forName(sig[i], false, targetClassLoader); + } catch (ClassNotFoundException e) { + if (tracing) { + MODELMBEAN_LOGGER.logp(Level.FINER, + RequiredModelMBean.class.getName(), + "resolveMethod", + "class not found"); + } + final String msg = "Parameter class not found"; + caughtException[0] = new ReflectionException(e, msg); + } } - final String msg = "Parameter class not found"; - throw new ReflectionException(e, msg); } + return null; } + }, stack, acc); + + if (caughtException[0] != null) { + throw caughtException[0]; } } @@ -1133,7 +1176,7 @@ public class RequiredModelMBean /* Find a method in RequiredModelMBean as determined by the given parameters. Return null if there is none, or if the parameters exclude using it. Called from invoke. */ - private static Method findRMMBMethod(String opMethodName, + private Method findRMMBMethod(String opMethodName, Object targetObjectField, String opClassName, String[] sig) { @@ -1155,19 +1198,29 @@ public class RequiredModelMBean if (opClassName == null) targetClass = rmmbClass; else { - try { - final ClassLoader targetClassLoader = - rmmbClass.getClassLoader(); - targetClass = Class.forName(opClassName, false, - targetClassLoader); - if (!rmmbClass.isAssignableFrom(targetClass)) - return null; - } catch (ClassNotFoundException e) { - return null; - } + AccessControlContext stack = AccessController.getContext(); + final String className = opClassName; + targetClass = javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction>() { + + @Override + public Class run() { + try { + ReflectUtil.checkPackageAccess(className); + final ClassLoader targetClassLoader = + rmmbClass.getClassLoader(); + Class clz = Class.forName(className, false, + targetClassLoader); + if (!rmmbClass.isAssignableFrom(clz)) + return null; + return clz; + } catch (ClassNotFoundException e) { + return null; + } + } + }, stack, acc); } try { - return resolveMethod(targetClass, opMethodName, sig); + return targetClass != null ? resolveMethod(targetClass, opMethodName, sig) : null; } catch (ReflectionException e) { return null; } @@ -1177,12 +1230,35 @@ public class RequiredModelMBean * Invoke the given method, and throw the somewhat unpredictable * appropriate exception if the method itself gets an exception. */ - private Object invokeMethod(String opName, Method method, - Object targetObject, Object[] opArgs) + private Object invokeMethod(String opName, final Method method, + final Object targetObject, final Object[] opArgs) throws MBeanException, ReflectionException { try { - ReflectUtil.checkPackageAccess(method.getDeclaringClass()); - return MethodUtil.invoke(method, targetObject, opArgs); + final Throwable[] caughtException = new Throwable[1]; + AccessControlContext stack = AccessController.getContext(); + Object rslt = javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction() { + + @Override + public Object run() { + try { + ReflectUtil.checkPackageAccess(method.getDeclaringClass()); + return MethodUtil.invoke(method, targetObject, opArgs); + } catch (InvocationTargetException e) { + caughtException[0] = e; + } catch (IllegalAccessException e) { + caughtException[0] = e; + } + return null; + } + }, stack, acc); + if (caughtException[0] != null) { + if (caughtException[0] instanceof Exception) { + throw (Exception)caughtException[0]; + } else if(caughtException[0] instanceof Error) { + throw (Error)caughtException[0]; + } + } + return rslt; } catch (RuntimeErrorException ree) { throw new RuntimeOperationsException(ree, "RuntimeException occurred in RequiredModelMBean "+ @@ -1567,7 +1643,7 @@ public class RequiredModelMBean } // make sure response class matches type field - String respType = attrInfo.getType(); + final String respType = attrInfo.getType(); if (response != null) { String responseClass = response.getClass().getName(); if (!respType.equals(responseClass)) { @@ -1590,9 +1666,31 @@ public class RequiredModelMBean // inequality may come from type subclassing boolean subtype; try { - ClassLoader cl = - response.getClass().getClassLoader(); - Class c = Class.forName(respType, true, cl); + final Class respClass = response.getClass(); + final Exception[] caughException = new Exception[1]; + + AccessControlContext stack = AccessController.getContext(); + + Class c = javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction>() { + + @Override + public Class run() { + try { + ReflectUtil.checkPackageAccess(respType); + ClassLoader cl = + respClass.getClassLoader(); + return Class.forName(respType, true, cl); + } catch (Exception e) { + caughException[0] = e; + } + return null; + } + }, stack, acc); + + if (caughException[0] != null) { + throw caughException[0]; + } + subtype = c.isInstance(response); } catch (Exception e) { subtype = false; @@ -2745,16 +2843,37 @@ public class RequiredModelMBean return MBeanServerFactory.getClassLoaderRepository(server); } - private Class loadClass(String className) + private Class loadClass(final String className) throws ClassNotFoundException { - try { - return Class.forName(className); - } catch (ClassNotFoundException e) { - final ClassLoaderRepository clr = - getClassLoaderRepository(); - if (clr == null) throw new ClassNotFoundException(className); - return clr.loadClass(className); + AccessControlContext stack = AccessController.getContext(); + final ClassNotFoundException[] caughtException = new ClassNotFoundException[1]; + + Class c = javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction>() { + + @Override + public Class run() { + try { + ReflectUtil.checkPackageAccess(className); + return Class.forName(className); + } catch (ClassNotFoundException e) { + final ClassLoaderRepository clr = + getClassLoaderRepository(); + try { + if (clr == null) throw new ClassNotFoundException(className); + return clr.loadClass(className); + } catch (ClassNotFoundException ex) { + caughtException[0] = ex; + } + } + return null; + } + }, stack, acc); + + if (caughtException[0] != null) { + throw caughtException[0]; } + + return c; } From 3780f56b0f987516d3a8d029ded0c11f62f32716 Mon Sep 17 00:00:00 2001 From: Denis Fokin Date: Wed, 12 Dec 2012 21:08:19 +0400 Subject: [PATCH 036/180] 8004341: Two JCK tests fails with 7u11 b06 Reviewed-by: serb, skoivu --- jdk/src/share/classes/java/awt/Dialog.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/java/awt/Dialog.java b/jdk/src/share/classes/java/awt/Dialog.java index d24944f2995..d27041fd322 100644 --- a/jdk/src/share/classes/java/awt/Dialog.java +++ b/jdk/src/share/classes/java/awt/Dialog.java @@ -1638,12 +1638,13 @@ public class Dialog extends Window { if (localModalityType == null) { this.modal = fields.get("modal", false); setModal(modal); + } else { + this.modalityType = localModalityType; } this.resizable = fields.get("resizable", true); this.undecorated = fields.get("undecorated", false); this.title = (String)fields.get("title", ""); - this.modalityType = localModalityType; blockedWindows = new IdentityArrayList<>(); From be64e9b087b120e3864b89dca2e5adb61661f777 Mon Sep 17 00:00:00 2001 From: Sean Mullan Date: Tue, 18 Dec 2012 13:48:48 -0500 Subject: [PATCH 037/180] 8004302: javax/xml/soap/Test7013971.java fails since jdk6u39b01 Reviewed-by: vinnie, skoivu, mgrebac, ohair, tbell --- jdk/src/share/lib/security/java.security-macosx | 8 ++++++-- jdk/src/share/lib/security/java.security-solaris | 8 ++++++-- jdk/src/share/lib/security/java.security-windows | 8 ++++++-- jdk/test/Makefile | 1 + 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/jdk/src/share/lib/security/java.security-macosx b/jdk/src/share/lib/security/java.security-macosx index 5f4d82974ac..707f1cf21a7 100644 --- a/jdk/src/share/lib/security/java.security-macosx +++ b/jdk/src/share/lib/security/java.security-macosx @@ -147,7 +147,9 @@ keystore.type=jks # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. package.access=sun.,\ - com.sun.xml.internal.,\ + com.sun.xml.internal.bind.,\ + com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.defaults.,\ @@ -169,7 +171,9 @@ package.access=sun.,\ # checkPackageDefinition. # package.definition=sun.,\ - com.sun.xml.internal.,\ + com.sun.xml.internal.bind.,\ + com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.defaults.,\ diff --git a/jdk/src/share/lib/security/java.security-solaris b/jdk/src/share/lib/security/java.security-solaris index f8e6774e3a1..5f905227d5f 100644 --- a/jdk/src/share/lib/security/java.security-solaris +++ b/jdk/src/share/lib/security/java.security-solaris @@ -148,7 +148,9 @@ keystore.type=jks # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. package.access=sun.,\ - com.sun.xml.internal.,\ + com.sun.xml.internal.bind.,\ + com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.defaults.,\ @@ -169,7 +171,9 @@ package.access=sun.,\ # checkPackageDefinition. # package.definition=sun.,\ - com.sun.xml.internal.,\ + com.sun.xml.internal.bind.,\ + com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.defaults.,\ diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows index d539f90be63..fceb1021d6d 100644 --- a/jdk/src/share/lib/security/java.security-windows +++ b/jdk/src/share/lib/security/java.security-windows @@ -147,7 +147,9 @@ keystore.type=jks # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. package.access=sun.,\ - com.sun.xml.internal.,\ + com.sun.xml.internal.bind.,\ + com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.defaults.,\ @@ -168,7 +170,9 @@ package.access=sun.,\ # checkPackageDefinition. # package.definition=sun.,\ - com.sun.xml.internal.,\ + com.sun.xml.internal.bind.,\ + com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.defaults.,\ diff --git a/jdk/test/Makefile b/jdk/test/Makefile index 408aaaeed25..cac80e27c9f 100644 --- a/jdk/test/Makefile +++ b/jdk/test/Makefile @@ -512,6 +512,7 @@ jdk_other: $(call TestDirs, \ javax/script \ java/sql javax/sql \ javax/smartcardio \ + javax/xml/soap \ javax/xml/ws com/sun/internal/ws \ jdk/asm \ com/sun/org/apache/xerces \ From 3243aaf47a448a5e99cdb09a010fd86aec3d740a Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Thu, 10 Jan 2013 19:43:36 -0800 Subject: [PATCH 038/180] 8005615: Java Logger fails to load tomcat logger implementation (JULI) Reviewed-by: alanb, ahgross --- .../classes/java/util/logging/LogManager.java | 263 +++++++++--------- .../classes/java/util/logging/Logger.java | 37 ++- .../java/util/logging/CustomLogManager.java | 177 ++++++++++++ .../util/logging/CustomLogManagerTest.java | 63 +++++ .../java/util/logging/SimpleLogManager.java | 113 ++++++++ 5 files changed, 513 insertions(+), 140 deletions(-) create mode 100644 jdk/test/java/util/logging/CustomLogManager.java create mode 100644 jdk/test/java/util/logging/CustomLogManagerTest.java create mode 100644 jdk/test/java/util/logging/SimpleLogManager.java diff --git a/jdk/src/share/classes/java/util/logging/LogManager.java b/jdk/src/share/classes/java/util/logging/LogManager.java index 3526c77ac01..58bd1ba7ead 100644 --- a/jdk/src/share/classes/java/util/logging/LogManager.java +++ b/jdk/src/share/classes/java/util/logging/LogManager.java @@ -158,7 +158,7 @@ public class LogManager { // LoggerContext for system loggers and user loggers private final LoggerContext systemContext = new SystemLoggerContext(); - private final LoggerContext userContext = new UserLoggerContext(); + private final LoggerContext userContext = new LoggerContext(); private Logger rootLogger; // Have we done the primordial reading of the configuration file? @@ -196,13 +196,13 @@ public class LogManager { // Create and retain Logger for the root of the namespace. manager.rootLogger = manager.new RootLogger(); - manager.systemContext.addLogger(manager.rootLogger); - manager.userContext.addLogger(manager.rootLogger); + manager.addLogger(manager.rootLogger); + manager.systemContext.addLocalLogger(manager.rootLogger); // Adding the global Logger. Doing so in the Logger. // would deadlock with the LogManager.. - Logger.getGlobal().setLogManager(manager); - manager.systemContext.addLogger(Logger.getGlobal()); + Logger.global.setLogManager(manager); + manager.addLogger(Logger.global); // We don't call readConfiguration() here, as we may be running // very early in the JVM startup sequence. Instead readConfiguration @@ -373,7 +373,7 @@ public class LogManager { // Returns the LoggerContext for the user code (i.e. application or AppContext). // Loggers are isolated from each AppContext. - LoggerContext getUserContext() { + private LoggerContext getUserContext() { LoggerContext context = null; SecurityManager sm = System.getSecurityManager(); @@ -394,8 +394,8 @@ public class LogManager { if (javaAwtAccess.isMainAppContext()) { context = userContext; } else { - context = new UserLoggerContext(); - context.addLogger(manager.rootLogger); + context = new LoggerContext(); + context.addLocalLogger(manager.rootLogger); } javaAwtAccess.put(ecx, LoggerContext.class, context); } @@ -406,10 +406,6 @@ public class LogManager { return context; } - LoggerContext getSystemContext() { - return systemContext; - } - private List contexts() { List cxs = new ArrayList<>(); cxs.add(systemContext); @@ -417,6 +413,58 @@ public class LogManager { return cxs; } + // Find or create a specified logger instance. If a logger has + // already been created with the given name it is returned. + // Otherwise a new logger instance is created and registered + // in the LogManager global namespace. + // This method will always return a non-null Logger object. + // Synchronization is not required here. All synchronization for + // adding a new Logger object is handled by addLogger(). + // + // This method must delegate to the LogManager implementation to + // add a new Logger or return the one that has been added previously + // as a LogManager subclass may override the addLogger, getLogger, + // readConfiguration, and other methods. + Logger demandLogger(String name, String resourceBundleName) { + Logger result = getLogger(name); + if (result == null) { + // only allocate the new logger once + Logger newLogger = new Logger(name, resourceBundleName); + do { + if (addLogger(newLogger)) { + // We successfully added the new Logger that we + // created above so return it without refetching. + return newLogger; + } + + // We didn't add the new Logger that we created above + // because another thread added a Logger with the same + // name after our null check above and before our call + // to addLogger(). We have to refetch the Logger because + // addLogger() returns a boolean instead of the Logger + // reference itself. However, if the thread that created + // the other Logger is not holding a strong reference to + // the other Logger, then it is possible for the other + // Logger to be GC'ed after we saw it in addLogger() and + // before we can refetch it. If it has been GC'ed then + // we'll just loop around and try again. + result = getLogger(name); + } while (result == null); + } + return result; + } + + Logger demandSystemLogger(String name, String resourceBundleName) { + return systemContext.demandLogger(name, resourceBundleName); + } + + // LoggerContext maintains the logger namespace per context. + // The default LogManager implementation has one system context and user + // context. The system context is used to maintain the namespace for + // all system loggers and is queried by the system code. If a system logger + // doesn't exist in the user context, it'll also be added to the user context. + // The user context is queried by the user code and all other loggers are + // added in the user context. static class LoggerContext { // Table of named Loggers that maps names to Loggers. private final Hashtable namedLoggers = new Hashtable<>(); @@ -427,6 +475,12 @@ public class LogManager { this.root = new LogNode(null, this); } + Logger demandLogger(String name, String resourceBundleName) { + // a LogManager subclass may have its own implementation to add and + // get a Logger. So delegate to the LogManager to do the work. + return manager.demandLogger(name, resourceBundleName); + } + synchronized Logger findLogger(String name) { LoggerWeakRef ref = namedLoggers.get(name); if (ref == null) { @@ -441,7 +495,9 @@ public class LogManager { return logger; } - synchronized boolean addLogger(Logger logger) { + // Add a logger to this context. This method will only set its level + // and process parent loggers. It doesn't set its handlers. + synchronized boolean addLocalLogger(Logger logger) { final String name = logger.getName(); if (name == null) { throw new NullPointerException(); @@ -474,9 +530,9 @@ public class LogManager { doSetLevel(logger, level); } - // Do we have a per logger handler too? - // Note: this will add a 200ms penalty - manager.loadLoggerHandlers(logger, name, name + ".handlers"); + // instantiation of the handler is done in the LogManager.addLogger + // implementation as a handler class may be only visible to LogManager + // subclass for the custom log manager case processParentHandlers(logger, name); // Find the new node and its parent. @@ -513,50 +569,21 @@ public class LogManager { return namedLoggers.keys(); } - Logger demandLogger(String name) { - return demandLogger(name, null); - } - - // Find or create a specified logger instance. If a logger has - // already been created with the given name it is returned. - // Otherwise a new logger instance is created and registered - // in the LogManager global namespace. - - // This method will always return a non-null Logger object. - // Synchronization is not required here. All synchronization for - // adding a new Logger object is handled by addLogger(). - Logger demandLogger(String name, String resourceBundleName) { - Logger result = findLogger(name); - if (result == null) { - // only allocate the new logger once - Logger newLogger = new Logger(name, resourceBundleName); - do { - if (addLogger(newLogger)) { - // We successfully added the new Logger that we - // created above so return it without refetching. - return newLogger; - } - - // We didn't add the new Logger that we created above - // because another thread added a Logger with the same - // name after our null check above and before our call - // to addLogger(). We have to refetch the Logger because - // addLogger() returns a boolean instead of the Logger - // reference itself. However, if the thread that created - // the other Logger is not holding a strong reference to - // the other Logger, then it is possible for the other - // Logger to be GC'ed after we saw it in addLogger() and - // before we can refetch it. If it has been GC'ed then - // we'll just loop around and try again. - result = findLogger(name); - } while (result == null); - } - return result; - } - // If logger.getUseParentHandlers() returns 'true' and any of the logger's // parents have levels or handlers defined, make sure they are instantiated. - private void processParentHandlers(Logger logger, String name) { + private void processParentHandlers(final Logger logger, final String name) { + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + if (logger != manager.rootLogger) { + boolean useParent = manager.getBooleanProperty(name + ".useParentHandlers", true); + if (!useParent) { + logger.setUseParentHandlers(false); + } + } + return null; + } + }); + int ix = 1; for (;;) { int ix2 = name.indexOf(".", ix); @@ -564,12 +591,11 @@ public class LogManager { break; } String pname = name.substring(0, ix2); - if (manager.getProperty(pname + ".level") != null || manager.getProperty(pname + ".handlers") != null) { // This pname has a level/handlers definition. // Make sure it exists. - demandLogger(pname); + demandLogger(pname, null); } ix = ix2+1; } @@ -607,53 +633,51 @@ public class LogManager { } static class SystemLoggerContext extends LoggerContext { - // Default resource bundle for all system loggers - Logger demandLogger(String name) { - // default to use the system logger's resource bundle - return super.demandLogger(name, Logger.SYSTEM_LOGGER_RB_NAME); - } - } - - static class UserLoggerContext extends LoggerContext { - /** - * Returns a Logger of the given name if there is one registered - * in this context. Otherwise, it will return the one registered - * in the system context if there is one. The returned Logger - * instance may be initialized with a different resourceBundleName. - * If no such logger exists, a new Logger instance will be created - * and registered in this context. - */ + // Add a system logger in the system context's namespace as well as + // in the LogManager's namespace if not exist so that there is only + // one single logger of the given name. System loggers are visible + // to applications unless a logger of the same name has been added. Logger demandLogger(String name, String resourceBundleName) { Logger result = findLogger(name); if (result == null) { - // use the system logger if exists; or allocate a new logger. - // The system logger is added to the app logger context so that - // any child logger created in the app logger context can have - // a system logger as its parent if already exist. - Logger logger = manager.systemContext.findLogger(name); - Logger newLogger = - logger != null ? logger : new Logger(name, resourceBundleName); + // only allocate the new system logger once + Logger newLogger = new Logger(name, resourceBundleName); do { - if (addLogger(newLogger)) { + if (addLocalLogger(newLogger)) { // We successfully added the new Logger that we // created above so return it without refetching. - return newLogger; + result = newLogger; + } else { + // We didn't add the new Logger that we created above + // because another thread added a Logger with the same + // name after our null check above and before our call + // to addLogger(). We have to refetch the Logger because + // addLogger() returns a boolean instead of the Logger + // reference itself. However, if the thread that created + // the other Logger is not holding a strong reference to + // the other Logger, then it is possible for the other + // Logger to be GC'ed after we saw it in addLogger() and + // before we can refetch it. If it has been GC'ed then + // we'll just loop around and try again. + result = findLogger(name); } - - // We didn't add the new Logger that we created above - // because another thread added a Logger with the same - // name after our null check above and before our call - // to addLogger(). We have to refetch the Logger because - // addLogger() returns a boolean instead of the Logger - // reference itself. However, if the thread that created - // the other Logger is not holding a strong reference to - // the other Logger, then it is possible for the other - // Logger to be GC'ed after we saw it in addLogger() and - // before we can refetch it. If it has been GC'ed then - // we'll just loop around and try again. - result = findLogger(name); } while (result == null); } + // Add the system logger to the LogManager's namespace if not exists + // The LogManager will set its handlers via the LogManager.addLogger method. + if (!manager.addLogger(result) && result.getHandlers().length == 0) { + // if logger already exists but handlers not set + final Logger l = manager.getLogger(name); + final Logger logger = result; + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + for (Handler hdl : l.getHandlers()) { + logger.addHandler(hdl); + } + return null; + } + }); + } return result; } } @@ -663,22 +687,16 @@ public class LogManager { // be made based on the logging configuration, which can // only be modified by trusted code. private void loadLoggerHandlers(final Logger logger, final String name, - final String handlersPropertyName) { + final String handlersPropertyName) + { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { - if (logger != rootLogger) { - boolean useParent = getBooleanProperty(name + ".useParentHandlers", true); - if (!useParent) { - logger.setUseParentHandlers(false); - } - } - String names[] = parseClassNames(handlersPropertyName); for (int i = 0; i < names.length; i++) { String word = names[i]; try { Class clz = ClassLoader.getSystemClassLoader().loadClass(word); - Handler hdl = (Handler) clz.newInstance(); + Handler hdl = (Handler) clz.newInstance(); // Check if there is a property defining the // this handler's level. String levs = getProperty(word + ".level"); @@ -700,7 +718,8 @@ public class LogManager { } } return null; - }}); + } + }); } @@ -839,13 +858,17 @@ public class LogManager { if (name == null) { throw new NullPointerException(); } - if (systemContext.findLogger(name) != null) { + LoggerContext cx = getUserContext(); + if (cx.addLocalLogger(logger)) { + // Do we have a per logger handler too? + // Note: this will add a 200ms penalty + loadLoggerHandlers(logger, name, name + ".handlers"); + return true; + } else { return false; } - return getUserContext().addLogger(logger); } - // Private method to set a level on a logger. // If necessary, we raise privilege before doing the call. private static void doSetLevel(final Logger logger, final Level level) { @@ -864,8 +887,6 @@ public class LogManager { }}); } - - // Private method to set a parent on a logger. // If necessary, we raise privilege before doing the setParent call. private static void doSetParent(final Logger logger, final Logger parent) { @@ -900,15 +921,7 @@ public class LogManager { * @return matching logger or null if none is found */ public Logger getLogger(String name) { - // return the first logger added - // - // once a system logger is added in the system context, no one can - // adds a logger with the same name in the global context - // (see LogManager.addLogger). So if there is a logger in the global - // context with the same name as one in the system context, it must be - // added before the system logger was created. - Logger logger = getUserContext().findLogger(name); - return logger != null ? logger : systemContext.findLogger(name); + return getUserContext().findLogger(name); } /** @@ -928,10 +941,7 @@ public class LogManager { * @return enumeration of logger name strings */ public Enumeration getLoggerNames() { - // only return unique names - Set names = new HashSet<>(Collections.list(systemContext.getLoggerNames())); - names.addAll(Collections.list(getUserContext().getLoggerNames())); - return Collections.enumeration(names); + return getUserContext().getLoggerNames(); } /** @@ -1329,7 +1339,6 @@ public class LogManager { // that we only instantiate the global handlers when they // are first needed. private class RootLogger extends Logger { - private RootLogger() { super("", null); setLevel(defaultLevel); diff --git a/jdk/src/share/classes/java/util/logging/Logger.java b/jdk/src/share/classes/java/util/logging/Logger.java index 34f96be2112..5d060059e60 100644 --- a/jdk/src/share/classes/java/util/logging/Logger.java +++ b/jdk/src/share/classes/java/util/logging/Logger.java @@ -31,7 +31,6 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.security.*; import java.lang.ref.WeakReference; import java.util.function.Supplier; -import java.util.logging.LogManager.LoggerContext; /** * A Logger object is used to log messages for a specific @@ -321,18 +320,32 @@ public class Logger { // // As an interim solution, if the immediate caller whose caller loader is // null, we assume it's a system logger and add it to the system context. - private static LoggerContext getLoggerContext() { + // These system loggers only set the resource bundle to the given + // resource bundle name (rather than the default system resource bundle). + private static class SystemLoggerHelper { + static boolean disableCallerCheck = getBooleanProperty("sun.util.logging.disableCallerCheck"); + private static boolean getBooleanProperty(final String key) { + String s = AccessController.doPrivileged(new PrivilegedAction() { + public String run() { + return System.getProperty(key); + } + }); + return Boolean.valueOf(s); + } + } + + private static Logger demandLogger(String name, String resourceBundleName) { LogManager manager = LogManager.getLogManager(); SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - // 0: Reflection 1: Logger.getLoggerContext 2: Logger.getLogger 3: caller + if (sm != null && !SystemLoggerHelper.disableCallerCheck) { + // 0: Reflection 1: Logger.demandLogger 2: Logger.getLogger 3: caller final int SKIP_FRAMES = 3; Class caller = sun.reflect.Reflection.getCallerClass(SKIP_FRAMES); if (caller.getClassLoader() == null) { - return manager.getSystemContext(); + return manager.demandSystemLogger(name, resourceBundleName); } } - return manager.getUserContext(); + return manager.demandLogger(name, resourceBundleName); } /** @@ -376,8 +389,7 @@ public class Logger { // would throw an IllegalArgumentException in the second call // because the wrapper would result in an attempt to replace // the existing "resourceBundleForFoo" with null. - LoggerContext context = getLoggerContext(); - return context.demandLogger(name); + return demandLogger(name, null); } /** @@ -424,8 +436,7 @@ public class Logger { // Synchronization is not required here. All synchronization for // adding a new Logger object is handled by LogManager.addLogger(). public static Logger getLogger(String name, String resourceBundleName) { - LoggerContext context = getLoggerContext(); - Logger result = context.demandLogger(name, resourceBundleName); + Logger result = demandLogger(name, resourceBundleName); // MissingResourceException or IllegalArgumentException can be // thrown by setupResourceInfo(). @@ -438,11 +449,10 @@ public class Logger { // i.e. caller of sun.util.logging.PlatformLogger.getLogger static Logger getPlatformLogger(String name) { LogManager manager = LogManager.getLogManager(); - LoggerContext context = manager.getSystemContext(); // all loggers in the system context will default to // the system logger's resource bundle - Logger result = context.demandLogger(name); + Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME); return result; } @@ -1588,7 +1598,8 @@ public class Logger { public ResourceBundle run() { try { return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME, - locale); + locale, + ClassLoader.getSystemClassLoader()); } catch (MissingResourceException e) { throw new InternalError(e.toString()); } diff --git a/jdk/test/java/util/logging/CustomLogManager.java b/jdk/test/java/util/logging/CustomLogManager.java new file mode 100644 index 00000000000..9542e54ec02 --- /dev/null +++ b/jdk/test/java/util/logging/CustomLogManager.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2013, 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. + */ + +import java.io.*; +import java.util.*; +import java.util.logging.*; + +/* + * Custom LogManager implementation to verify that the implementation delegates + * to the LogManager subclass to register both system logger and user logger. + * + * The LogManager implementation is the one configuring the logger's property + * such as level, handler, etc. + */ +public class CustomLogManager extends LogManager { + static LogManager INSTANCE; + Map namedLoggers = new HashMap<>(); + Properties props = initConfig(); + public CustomLogManager() { + if (INSTANCE != null) { + throw new RuntimeException("CustomLogManager already created"); + } + INSTANCE = this; + } + + public synchronized boolean addLogger(Logger logger) { + String name = logger.getName(); + if (namedLoggers.containsKey(name)) { + return false; + } + namedLoggers.put(name, logger); + // set level + if (props.get(name + ".level") != null) { + logger.setLevel(Level.parse(props.getProperty(name + ".level"))); + } + // add handlers + if (props.get(name + ".handlers") != null && logger.getHandlers().length == 0) { + logger.addHandler(new CustomHandler()); + } + // add parent loggers + int ix = 1; + for (;;) { + int ix2 = name.indexOf(".", ix); + if (ix2 < 0) { + break; + } + String pname = name.substring(0, ix2); + if (props.get(pname + ".level") != null || + props.get(pname + ".handlers") != null) { + // This pname has a level/handlers definition. + // Make sure it exists. + // + // The test doesn't set the parent for simplicity. + if (!namedLoggers.containsKey(pname)) { + Logger.getLogger(pname); + } + } + ix = ix2 + 1; + } + return true; + } + + public synchronized Logger getLogger(String name) { + return namedLoggers.get(name); + } + + public synchronized Enumeration getLoggerNames() { + return Collections.enumeration(namedLoggers.keySet()); + } + + public String getProperty(String name) { + return props.getProperty(name); + } + + public void readConfiguration() { + // do nothing + } + + public void readConfiguration(InputStream ins) { + // do nothing + } + + private Properties initConfig() { + Properties props = new Properties(); + props.put(".level", "CONFIG"); + props.put("CustomLogManagerTest.level", "WARNING"); + props.put("CustomLogManagerTest.handlers", "CustomLogManager$CustomHandler"); + props.put("SimpleLogManager.level", "INFO"); + props.put("SimpleLogManager.handlers", "CustomLogManager$CustomHandler"); + props.put("CustomLogManager$CustomHandler.level", "WARNING"); + props.put(".handlers", "CustomLogManager$CustomHandler"); + props.put("org.foo.bar.level", "SEVERE"); + props.put("org.foo.handlers", "CustomLogManager$CustomHandler"); + props.put("org.openjdk.level", "SEVERE"); + props.put("org.openjdk.handlers", "CustomLogManager$CustomHandler"); + props.put("org.openjdk.core.level", "INFO"); + + return props; + } + + public static void checkLogger(String name) { + checkLogger(name, null); + } + + public static void checkLogger(String name, String resourceBundleName) { + Logger logger = INSTANCE.getLogger(name); + if (logger == null) { + throw new RuntimeException("Logger \"" + name + "\" not exist"); + } + System.out.format("Logger \"%s\" level=%s handlers=%s resourcebundle=%s%n", + name, logger.getLevel(), + Arrays.toString(logger.getHandlers()), + logger.getResourceBundleName()); + String rb = logger.getResourceBundleName(); + if (rb != resourceBundleName && (rb == null || rb.equals(resourceBundleName))) { + throw new RuntimeException("Logger \"" + name + + "\" unexpected resource bundle: " + rb); + } + + String value = INSTANCE.getProperty(name + ".level"); + String level = logger.getLevel() != null ? logger.getLevel().getName() : null; + if (level != value && (level == null || level.equals(value))) { + throw new RuntimeException("Logger \"" + name + "\" unexpected level: " + level); + } + + Handler[] handlers = logger.getHandlers(); + String hdl = INSTANCE.getProperty(name + ".handlers"); + if ((hdl == null && handlers.length != 0) || + (hdl != null && handlers.length != 1)) { + throw new RuntimeException("Logger \"" + name + "\" unexpected handler: " + + Arrays.toString(handlers)); + } + checkParents(name); + } + + private static void checkParents(String name) { + int ix = 1; + for (;;) { + int ix2 = name.indexOf(".", ix); + if (ix2 < 0) { + break; + } + String pname = name.substring(0, ix2); + if (INSTANCE.getProperty(pname + ".level") != null || + INSTANCE.getProperty(pname + ".handlers") != null) { + // This pname has a level/handlers definition. + // Make sure it exists. + checkLogger(pname); + } + ix = ix2 + 1; + } + } + + // only CustomLogManager can create an instance of CustomHandler + private class CustomHandler extends StreamHandler { + } +} diff --git a/jdk/test/java/util/logging/CustomLogManagerTest.java b/jdk/test/java/util/logging/CustomLogManagerTest.java new file mode 100644 index 00000000000..2fa89a9a47b --- /dev/null +++ b/jdk/test/java/util/logging/CustomLogManagerTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013, 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. + */ + +import java.io.*; +import java.util.*; + +import java.util.logging.*; +import sun.util.logging.PlatformLogger; + +/* + * @test + * @bug 8005615 + * @summary Add loggers to custom log manager + * + * @compile -XDignore.symbol.file CustomLogManagerTest.java CustomLogManager.java + * @run main/othervm -Djava.util.logging.manager=CustomLogManager CustomLogManagerTest + */ +public class CustomLogManagerTest { + private static final String RESOURCE_BUNDLE = "sun.util.logging.resources.logging"; + public static void main(String[] args) { + String mgr = System.getProperty("java.util.logging.manager"); + if (!mgr.equals("CustomLogManager")) { + throw new RuntimeException("java.util.logging.manager not set"); + } + + Logger.getLogger(CustomLogManagerTest.class.getName()); + Logger.getLogger("org.foo.Foo"); + Logger.getLogger("org.foo.bar.Foo", RESOURCE_BUNDLE); + // platform logger will be set with the default system resource bundle + PlatformLogger.getLogger("org.openjdk.core.logger"); + + if (LogManager.getLogManager() != CustomLogManager.INSTANCE) { + throw new RuntimeException(LogManager.getLogManager() + " not CustomLogManager"); + } + + CustomLogManager.checkLogger(CustomLogManagerTest.class.getName()); + CustomLogManager.checkLogger("org.foo.Foo"); + CustomLogManager.checkLogger("org.foo.bar.Foo", RESOURCE_BUNDLE); + CustomLogManager.checkLogger(Logger.GLOBAL_LOGGER_NAME); + CustomLogManager.checkLogger(""); + CustomLogManager.checkLogger("org.openjdk.core.logger", RESOURCE_BUNDLE); + } +} diff --git a/jdk/test/java/util/logging/SimpleLogManager.java b/jdk/test/java/util/logging/SimpleLogManager.java new file mode 100644 index 00000000000..f469727654f --- /dev/null +++ b/jdk/test/java/util/logging/SimpleLogManager.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2013, 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. + */ + +import java.util.*; +import java.util.logging.*; +import sun.util.logging.PlatformLogger; + +/* + * @test + * @bug 8005615 + * @summary A LogManager subclass overrides its own implementation of named + * logger (see the subclassing information in the Logger class specification) + * + * @compile -XDignore.symbol.file CustomLogManager.java SimpleLogManager.java + * @run main/othervm -Djava.util.logging.manager=SimpleLogManager SimpleLogManager + */ +public class SimpleLogManager extends CustomLogManager { + public static void main(String[] args) { + String classname = System.getProperty("java.util.logging.manager"); + if (!classname.equals("SimpleLogManager")) { + throw new RuntimeException("java.util.logging.manager not set"); + } + + Logger logger = Logger.getLogger(SimpleLogManager.class.getName()); + Logger.getLogger("org.foo.bar.Foo"); + + // a platform logger used by the system code is just a Logger instance. + PlatformLogger.getLogger("org.openjdk.core.logger"); + + LogManager mgr = LogManager.getLogManager(); + if (mgr != CustomLogManager.INSTANCE || !(mgr instanceof SimpleLogManager)) { + throw new RuntimeException(LogManager.getLogManager() + " not SimpleLogManager"); + } + + checkCustomLogger(SimpleLogManager.class.getName(), null); + checkCustomLogger("org.foo.bar.Foo", null); + checkCustomLogger("org.openjdk.core.logger", "sun.util.logging.resources.logging"); + + // ## The LogManager.demandLogger method does not handle custom log manager + // ## that overrides the getLogger method to return a custom logger + // ## (see the test case in 8005640). Logger.getLogger may return + // ## a Logger instance but LogManager overrides it with a custom Logger + // ## instance like this case. + // + // However, the specification of LogManager and Logger subclassing is + // not clear whether this is supported or not. The following check + // just captures the current behavior. + if (logger instanceof CustomLogger) { + throw new RuntimeException(logger + " not CustomLogger"); + } + } + + private static void checkCustomLogger(String name, String resourceBundleName) { + CustomLogManager.checkLogger(name, resourceBundleName); + Logger logger1 = Logger.getLogger(name); + Logger logger2 = LogManager.getLogManager().getLogger(name); + if (logger1 != logger2) { + throw new RuntimeException(logger1 + " != " + logger2); + } + if (!(logger1 instanceof CustomLogger)) { + throw new RuntimeException(logger1 + " not CustomLogger"); + } + } + + /* + * This SimpleLogManager overrides the addLogger method to replace + * the given logger with a custom logger. + * + * It's unclear what the recommended way to use custom logger is. + * A LogManager subclass might override the getLogger method to return + * a custom Logger and create a new custom logger if not exist so that + * Logger.getLogger() can return a custom Logger instance but that violates + * the LogManager.getLogger() spec which should return null if not found. + */ + public synchronized boolean addLogger(Logger logger) { + String name = logger.getName(); + if (namedLoggers.containsKey(name)) { + return false; + } + CustomLogger newLogger = new CustomLogger(logger); + super.addLogger(newLogger); + return true; + } + + public class CustomLogger extends Logger { + CustomLogger(Logger logger) { + super(logger.getName(), logger.getResourceBundleName()); + } + CustomLogger(String name) { + super(name, null); + } + } +} From fe173efccd4edeb1330746ec05618fef4516a8a5 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Tue, 22 Jan 2013 13:53:53 +0100 Subject: [PATCH 039/180] 8006506: Add test for redefining methods in backtraces to java/lang/instrument tests Reviewed-by: sspitsyn, coleenp --- .../instrument/RedefineMethodInBacktrace.sh | 87 ++++++++++++++ .../RedefineMethodInBacktraceAgent.java | 42 +++++++ .../RedefineMethodInBacktraceApp.java | 111 ++++++++++++++++++ .../RedefineMethodInBacktraceTarget.java | 32 +++++ .../RedefineMethodInBacktraceTarget_2.java | 32 +++++ 5 files changed, 304 insertions(+) create mode 100644 jdk/test/java/lang/instrument/RedefineMethodInBacktrace.sh create mode 100644 jdk/test/java/lang/instrument/RedefineMethodInBacktraceAgent.java create mode 100644 jdk/test/java/lang/instrument/RedefineMethodInBacktraceApp.java create mode 100644 jdk/test/java/lang/instrument/RedefineMethodInBacktraceTarget.java create mode 100644 jdk/test/java/lang/instrument/RedefineMethodInBacktraceTarget_2.java diff --git a/jdk/test/java/lang/instrument/RedefineMethodInBacktrace.sh b/jdk/test/java/lang/instrument/RedefineMethodInBacktrace.sh new file mode 100644 index 00000000000..20167bf8330 --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineMethodInBacktrace.sh @@ -0,0 +1,87 @@ +# +# Copyright (c) 2013, 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 7174978 +# @summary Redefine a class with a method stored in a backtrace. +# @author Stefan Karlsson +# +# @run shell MakeJAR3.sh RedefineMethodInBacktraceAgent 'Can-Redefine-Classes: true' +# @run build RedefineMethodInBacktraceTarget RedefineMethodInBacktraceApp +# @run shell RedefineMethodInBacktrace.sh +# + +if [ "${TESTJAVA}" = "" ] +then + echo "TESTJAVA not set. Test cannot execute. Failed." + exit 1 +fi + +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" + +if [ "${TESTSRC}" = "" ] +then + echo "TESTSRC not set. Test cannot execute. Failed." + exit 1 +fi + +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi + +JAVAC="${COMPILEJAVA}"/bin/javac +JAVA="${TESTJAVA}"/bin/java + +cp "${TESTSRC}"/RedefineMethodInBacktraceTarget_2.java \ + RedefineMethodInBacktraceTarget.java +"${JAVAC}" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . RedefineMethodInBacktraceTarget.java + +"${JAVA}" ${TESTVMOPTS} -javaagent:RedefineMethodInBacktraceAgent.jar \ + -classpath "${TESTCLASSES}" RedefineMethodInBacktraceApp > output.log 2>&1 +RUN_RESULT=$? + +if [ $RUN_RESULT != 0 ]; then + echo "FAIL: the run failed with exit code '$RUN_RESULT'" + exit $RUN_RESULT +fi + +cat output.log + +MESG="Exception" +grep "$MESG" output.log +result=$? +if [ "$result" = 0 ]; then + echo "FAIL: found '$MESG' in the test output" + result=1 +else + echo "PASS: did NOT find '$MESG' in the test output" + result=0 +fi + +exit $result diff --git a/jdk/test/java/lang/instrument/RedefineMethodInBacktraceAgent.java b/jdk/test/java/lang/instrument/RedefineMethodInBacktraceAgent.java new file mode 100644 index 00000000000..a4cc182bf23 --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineMethodInBacktraceAgent.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2013, 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. + */ + +import java.lang.instrument.Instrumentation; + +public class RedefineMethodInBacktraceAgent { + private static Instrumentation instrumentation; + + private RedefineMethodInBacktraceAgent() {} + + public static void premain(String agentArgs, Instrumentation inst) { + System.out.println("Hello from RedefineMethodInBacktraceAgent!"); + System.out.println("isRedefineClassesSupported()=" + + inst.isRedefineClassesSupported()); + + instrumentation = inst; + } + + public static Instrumentation getInstrumentation() { + return instrumentation; + } +} diff --git a/jdk/test/java/lang/instrument/RedefineMethodInBacktraceApp.java b/jdk/test/java/lang/instrument/RedefineMethodInBacktraceApp.java new file mode 100644 index 00000000000..a4ad0884661 --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineMethodInBacktraceApp.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2013, 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. + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.lang.instrument.ClassDefinition; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * When an exception is thrown, the JVM collects just enough information + * about the stack trace to be able to create a full fledged stack trace + * (StackTraceElement[]). The backtrace contains this information and the + * JVM must make sure that the data in the backtrace is still usable after + * a class redefinition. + * + * After the PermGen removal there was a bug when the last reference to a Method + * was in the backtrace. The class of the method was kept alive, because of the + * mirror stored in the backtrace, but the old versions of the redefined method + * could be freed, since class redefinition didn't know about the backtraces. + */ +public class RedefineMethodInBacktraceApp { + public static void main(String args[]) throws Exception { + System.out.println("Hello from RedefineMethodInBacktraceApp!"); + + new RedefineMethodInBacktraceApp().doTest(); + + System.exit(0); + } + + private void doTest() throws Exception { + doMethodInBacktraceTest(); + } + + private void doMethodInBacktraceTest() throws Exception { + Throwable t = getThrowableFromMethodToRedefine(); + + doRedefine(RedefineMethodInBacktraceTarget.class); + + doClassUnloading(); + + touchRedefinedMethodInBacktrace(t); + } + + private static Throwable getThrowableFromMethodToRedefine() throws Exception { + Class c = + RedefineMethodInBacktraceTarget.class; + Method method = c.getMethod("methodToRedefine"); + + Throwable thrownFromMethodToRedefine = null; + try { + method.invoke(null); + } catch (InvocationTargetException e) { + thrownFromMethodToRedefine = e.getCause(); + if (!(thrownFromMethodToRedefine instanceof RuntimeException)) { + throw e; + } + } + method = null; + c = null; + + return thrownFromMethodToRedefine; + } + + private static void doClassUnloading() { + // This will clean out old, unused redefined methods. + System.gc(); + } + + private static void touchRedefinedMethodInBacktrace(Throwable throwable) { + // Make sure that we can convert the backtrace, which is referring to + // the redefined method, to a StrackTraceElement[] without crashing. + throwable.getStackTrace(); + } + + private static void doRedefine(Class clazz) throws Exception { + // Load the second version of this class. + File f = new File(clazz.getName() + ".class"); + System.out.println("Reading test class from " + f.getAbsolutePath()); + InputStream redefineStream = new FileInputStream(f); + + byte[] redefineBuffer = NamedBuffer.loadBufferFromStream(redefineStream); + + ClassDefinition redefineParamBlock = new ClassDefinition( + clazz, redefineBuffer); + + RedefineMethodInBacktraceAgent.getInstrumentation().redefineClasses( + new ClassDefinition[] {redefineParamBlock}); + } +} diff --git a/jdk/test/java/lang/instrument/RedefineMethodInBacktraceTarget.java b/jdk/test/java/lang/instrument/RedefineMethodInBacktraceTarget.java new file mode 100644 index 00000000000..fad881137c8 --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineMethodInBacktraceTarget.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013, 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. + */ + +/** + * The first version of this class. The second version is in + * RedefineMethodInBacktraceTarget_2.java. + */ +public class RedefineMethodInBacktraceTarget { + public static void methodToRedefine() { + throw new RuntimeException("Test exception"); + } +} diff --git a/jdk/test/java/lang/instrument/RedefineMethodInBacktraceTarget_2.java b/jdk/test/java/lang/instrument/RedefineMethodInBacktraceTarget_2.java new file mode 100644 index 00000000000..d2ba2259932 --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineMethodInBacktraceTarget_2.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013, 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. + */ + +/** + * This is the second version of this class. The first version is in + * RedefineMethodInBacktraceTarget.java. + */ +public class RedefineMethodInBacktraceTarget { + public static void methodToRedefine() { + throw new RuntimeException("Test exception 2"); + } +} From 15d98b74e99745f352e40dc07ef2903d683f16cf Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Tue, 22 Jan 2013 15:25:37 +0100 Subject: [PATCH 040/180] 7140852: Add test for 7022100 Reviewed-by: sspitsyn, coleenp --- .../RedefineMethodWithAnnotations.sh | 85 ++++++++++++++ .../RedefineMethodWithAnnotationsAgent.java | 42 +++++++ ...efineMethodWithAnnotationsAnnotations.java | 38 ++++++ .../RedefineMethodWithAnnotationsApp.java | 108 ++++++++++++++++++ .../RedefineMethodWithAnnotationsTarget.java | 33 ++++++ ...RedefineMethodWithAnnotationsTarget_2.java | 35 ++++++ 6 files changed, 341 insertions(+) create mode 100644 jdk/test/java/lang/instrument/RedefineMethodWithAnnotations.sh create mode 100644 jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsAgent.java create mode 100644 jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsAnnotations.java create mode 100644 jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsApp.java create mode 100644 jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsTarget.java create mode 100644 jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsTarget_2.java diff --git a/jdk/test/java/lang/instrument/RedefineMethodWithAnnotations.sh b/jdk/test/java/lang/instrument/RedefineMethodWithAnnotations.sh new file mode 100644 index 00000000000..9bde206f17a --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineMethodWithAnnotations.sh @@ -0,0 +1,85 @@ +# +# Copyright (c) 2013, 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 7022100 +# @summary Method annotations are incorrectly set when redefining classes. +# @author Stefan Karlsson +# +# @run shell MakeJAR3.sh RedefineMethodWithAnnotationsAgent 'Can-Redefine-Classes: true' +# @run build RedefineMethodWithAnnotationsTarget RedefineMethodWithAnnotationsApp RedefineMethodWithAnnotationsAnnotations +# @run shell RedefineMethodWithAnnotations.sh +# + +if [ "${TESTJAVA}" = "" ] +then + echo "TESTJAVA not set. Test cannot execute. Failed." + exit 1 +fi + +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" + +if [ "${TESTSRC}" = "" ] +then + echo "TESTSRC not set. Test cannot execute. Failed." + exit 1 +fi + +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi + +JAVAC="${COMPILEJAVA}"/bin/javac +JAVA="${TESTJAVA}"/bin/java + +cp "${TESTSRC}"/RedefineMethodWithAnnotationsTarget_2.java \ + RedefineMethodWithAnnotationsTarget.java +cp "${TESTSRC}"/RedefineMethodWithAnnotationsAnnotations.java \ + RedefineMethodWithAnnotationsAnnotations.java + +"${JAVAC}" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ + RedefineMethodWithAnnotationsTarget.java \ + RedefineMethodWithAnnotationsAnnotations.java + +"${JAVA}" ${TESTVMOPTS} -javaagent:RedefineMethodWithAnnotationsAgent.jar \ + -cp "${TESTCLASSES}" RedefineMethodWithAnnotationsApp > output.log 2>&1 +cat output.log + +MESG="Exception" +grep "$MESG" output.log +result=$? +if [ "$result" = 0 ]; then + echo "FAIL: found '$MESG' in the test output" + result=1 +else + echo "PASS: did NOT find '$MESG' in the test output" + result=0 +fi + +exit $result diff --git a/jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsAgent.java b/jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsAgent.java new file mode 100644 index 00000000000..c160be8756b --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsAgent.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2013, 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. + */ + +import java.lang.instrument.Instrumentation; + +public class RedefineMethodWithAnnotationsAgent { + private static Instrumentation instrumentation; + + private RedefineMethodWithAnnotationsAgent() {} + + public static void premain(String agentArgs, Instrumentation inst) { + System.out.println("Hello from RedefineMethodWithAnnotationsAgent!"); + System.out.println("isRedefineClassesSupported()=" + + inst.isRedefineClassesSupported()); + + instrumentation = inst; + } + + public static Instrumentation getInstrumentation() { + return instrumentation; + } +} diff --git a/jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsAnnotations.java b/jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsAnnotations.java new file mode 100644 index 00000000000..a215e96b8b9 --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsAnnotations.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013, 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. + */ + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +@interface ParameterAnnotation { + // Values used for the annotations in the first version of the target class. + static final String STRING_VALUE_1 = "String1"; + static final String INT_VALUE_1 = "Int1"; + + // Values used for the annotations in the second version of the target class. + static final String STRING_VALUE_2 = "String2"; + static final String INT_VALUE_2 = "Int2"; + + String value(); +} diff --git a/jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsApp.java b/jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsApp.java new file mode 100644 index 00000000000..ebc6ac503b8 --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsApp.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2013, 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. + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.lang.instrument.ClassDefinition; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Method; + +public class RedefineMethodWithAnnotationsApp { + public static void main(String args[]) throws Exception { + System.out.println("Hello from RedefineMethodWithAnnotationsApp!"); + + new RedefineMethodWithAnnotationsApp().doTest(); + + System.exit(0); + } + + private void doTest() throws Exception { + doMethodParameterAnnotationsTest(); + } + + private void doMethodParameterAnnotationsTest() throws Exception { + verifyMethodParameterAnnotationsValue( + ParameterAnnotation.STRING_VALUE_1); + + doRedefine(RedefineMethodWithAnnotationsTarget.class); + + verifyMethodParameterAnnotationsValue( + ParameterAnnotation.STRING_VALUE_2); + } + + private static void verifyMethodParameterAnnotationsValue( + String expectedValue) throws Exception { + Class c = + RedefineMethodWithAnnotationsTarget.class; + Method method = c.getMethod("annotatedMethod", String.class); + + Annotation [][] parametersAnnotations = + method.getParameterAnnotations(); + if (parametersAnnotations.length != 1) { + throw new Exception("Incorrect number of parameters to method: " + + method.getName() + "." + + " Expected: 1," + + " got: " + parametersAnnotations.length); + } + + Annotation[] parameterAnnotations = parametersAnnotations[0]; + if (parameterAnnotations.length != 1) { + throw new Exception("Incorrect number of annotations." + + " Expected: 1" + + ", got " + parameterAnnotations.length); + } + + Annotation parameterAnnotation = parameterAnnotations[0]; + if (!(parameterAnnotation instanceof ParameterAnnotation)) { + throw new Exception("Incorrect Annotation class." + + " Expected: " + ParameterAnnotation.class.getName() + + ", got: " + parameterAnnotation.getClass().getName()); + } + + ParameterAnnotation pa = (ParameterAnnotation)parameterAnnotation; + String annotationValue = pa.value(); + if (!expectedValue.equals(annotationValue)) { + throw new Exception("Incorrect parameter annotation value." + + " Expected: " + expectedValue + + ", got: " + annotationValue); + } + } + + private static void doRedefine(Class clazz) throws Exception { + // Load the second version of this class. + File f = new File(clazz.getName() + ".class"); + System.out.println("Reading test class from " + f); + InputStream redefineStream = new FileInputStream(f); + + byte[] redefineBuffer = NamedBuffer.loadBufferFromStream(redefineStream); + + ClassDefinition redefineParamBlock = new ClassDefinition( + clazz, redefineBuffer); + + RedefineMethodWithAnnotationsAgent.getInstrumentation().redefineClasses( + new ClassDefinition[] {redefineParamBlock}); + } +} diff --git a/jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsTarget.java b/jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsTarget.java new file mode 100644 index 00000000000..6cfbe21eb89 --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsTarget.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013, 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. + */ + +/** + * The first version of this class. The second version is in + * RedefineMethodWithAnnotationsTarget_2.java. + */ +public class RedefineMethodWithAnnotationsTarget { + public void annotatedMethod(@ParameterAnnotation( + value = ParameterAnnotation.STRING_VALUE_1) String parameter) { } + public void annotatedMethod(@ParameterAnnotation( + value = ParameterAnnotation.INT_VALUE_1) int parameter) { } +} diff --git a/jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsTarget_2.java b/jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsTarget_2.java new file mode 100644 index 00000000000..85c43047231 --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineMethodWithAnnotationsTarget_2.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013, 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. + */ + +/** + * This is the second version of this class. The first version is in + * RedefineMethodWithAnnotationsTarget.java. + *

    + * It has the same methods but with different annotations and order. + */ +public class RedefineMethodWithAnnotationsTarget { + public void annotatedMethod(@ParameterAnnotation( + value = ParameterAnnotation.INT_VALUE_2) int parameter) { } + public void annotatedMethod(@ParameterAnnotation( + value = ParameterAnnotation.STRING_VALUE_2) String parameter) { } +} From 7cb8f824d3f46cf6d3dd1066d7ceb4a0747cde8d Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Mon, 28 Jan 2013 15:53:29 -0800 Subject: [PATCH 041/180] 8006882: Proxy generated classes in sun.proxy package breaks JMockit Reviewed-by: alanb, ahgross --- jdk/src/share/classes/java/lang/reflect/Proxy.java | 2 +- jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java | 4 +++- jdk/src/share/lib/security/java.security-linux | 2 ++ jdk/src/share/lib/security/java.security-macosx | 2 ++ jdk/src/share/lib/security/java.security-solaris | 2 ++ jdk/src/share/lib/security/java.security-windows | 2 ++ 6 files changed, 12 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/java/lang/reflect/Proxy.java b/jdk/src/share/classes/java/lang/reflect/Proxy.java index 5e0c31f2de0..e946ba3226d 100644 --- a/jdk/src/share/classes/java/lang/reflect/Proxy.java +++ b/jdk/src/share/classes/java/lang/reflect/Proxy.java @@ -609,7 +609,7 @@ public class Proxy implements java.io.Serializable { } if (proxyPkg == null) { - // if no non-public proxy interfaces, use sun.proxy package + // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } diff --git a/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java b/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java index 84ab06b080a..0640d92e5d0 100644 --- a/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java +++ b/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java @@ -202,5 +202,7 @@ public final class ReflectUtil { } } - public static final String PROXY_PACKAGE = "sun.proxy"; + // Note that bytecode instrumentation tools may exclude 'sun.*' + // classes but not generated proxy classes and so keep it in com.sun.* + public static final String PROXY_PACKAGE = "com.sun.proxy"; } diff --git a/jdk/src/share/lib/security/java.security-linux b/jdk/src/share/lib/security/java.security-linux index cdda1b47699..c37bb480eb6 100644 --- a/jdk/src/share/lib/security/java.security-linux +++ b/jdk/src/share/lib/security/java.security-linux @@ -153,6 +153,7 @@ package.access=sun.,\ com.sun.istack.internal.,\ com.sun.jmx.defaults.,\ com.sun.jmx.remote.util.,\ + com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ @@ -177,6 +178,7 @@ package.definition=sun.,\ com.sun.istack.internal.,\ com.sun.jmx.defaults.,\ com.sun.jmx.remote.util.,\ + com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ diff --git a/jdk/src/share/lib/security/java.security-macosx b/jdk/src/share/lib/security/java.security-macosx index 515141de81b..ffb99c06936 100644 --- a/jdk/src/share/lib/security/java.security-macosx +++ b/jdk/src/share/lib/security/java.security-macosx @@ -154,6 +154,7 @@ package.access=sun.,\ com.sun.istack.internal.,\ com.sun.jmx.defaults.,\ com.sun.jmx.remote.util.,\ + com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ @@ -179,6 +180,7 @@ package.definition=sun.,\ com.sun.istack.internal.,\ com.sun.jmx.defaults.,\ com.sun.jmx.remote.util.,\ + com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ diff --git a/jdk/src/share/lib/security/java.security-solaris b/jdk/src/share/lib/security/java.security-solaris index 2cccc0d455b..4236643f55e 100644 --- a/jdk/src/share/lib/security/java.security-solaris +++ b/jdk/src/share/lib/security/java.security-solaris @@ -155,6 +155,7 @@ package.access=sun.,\ com.sun.istack.internal.,\ com.sun.jmx.defaults.,\ com.sun.jmx.remote.util.,\ + com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ @@ -179,6 +180,7 @@ package.definition=sun.,\ com.sun.istack.internal.,\ com.sun.jmx.defaults.,\ com.sun.jmx.remote.util.,\ + com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows index b6281f741a1..89ec5678646 100644 --- a/jdk/src/share/lib/security/java.security-windows +++ b/jdk/src/share/lib/security/java.security-windows @@ -154,6 +154,7 @@ package.access=sun.,\ com.sun.istack.internal.,\ com.sun.jmx.defaults.,\ com.sun.jmx.remote.util.,\ + com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ @@ -178,6 +179,7 @@ package.definition=sun.,\ com.sun.istack.internal.,\ com.sun.jmx.defaults.,\ com.sun.jmx.remote.util.,\ + com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ From 7303280ef5e99aff51f0e1bdcbdbcb66bb7f226e Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 30 Jan 2013 11:33:51 +0100 Subject: [PATCH 042/180] 8006446: Restrict MBeanServer access Reviewed-by: alanb, mchung, darcy, jrose, ahgross, skoivu --- .../ClassLoaderRepositorySupport.java | 2 ++ .../sun/jmx/mbeanserver/JmxMBeanServer.java | 10 ++++++ .../jmx/mbeanserver/MBeanInstantiator.java | 34 ++++++++++++++++--- .../com/sun/jmx/mbeanserver/MBeanSupport.java | 2 ++ .../lang/management/ManagementFactory.java | 18 +++++----- .../share/lib/security/java.security-linux | 6 ++-- .../share/lib/security/java.security-macosx | 6 ++-- .../share/lib/security/java.security-solaris | 6 ++-- .../share/lib/security/java.security-windows | 6 ++-- .../SubjectDelegation2Test.java | 6 ++-- .../SubjectDelegation3Test.java | 6 ++-- 11 files changed, 67 insertions(+), 35 deletions(-) diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/ClassLoaderRepositorySupport.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/ClassLoaderRepositorySupport.java index 728fb12a7e8..9fc0e7dbe9e 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/ClassLoaderRepositorySupport.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/ClassLoaderRepositorySupport.java @@ -36,6 +36,7 @@ import java.util.logging.Level; import javax.management.ObjectName; import javax.management.loading.PrivateClassLoader; +import sun.reflect.misc.ReflectUtil; /** * This class keeps the list of Class Loaders registered in the MBean Server. @@ -192,6 +193,7 @@ final class ClassLoaderRepositorySupport final ClassLoader without, final ClassLoader stop) throws ClassNotFoundException { + ReflectUtil.checkPackageAccess(className); final int size = list.length; for(int i=0; i theClass) throws ReflectionException, MBeanException { + + checkMBeanPermission(theClass, null, null, "instantiate"); + Object moi; @@ -260,6 +266,9 @@ public class MBeanInstantiator { public Object instantiate(Class theClass, Object params[], String signature[], ClassLoader loader) throws ReflectionException, MBeanException { + + checkMBeanPermission(theClass, null, null, "instantiate"); + // Instantiate the new object // ------------------------------ @@ -407,6 +416,8 @@ public class MBeanInstantiator { throw new RuntimeOperationsException(new IllegalArgumentException(), "Null className passed in parameter"); } + + ReflectUtil.checkPackageAccess(className); Class theClass; if (loaderName == null) { // Load the class using the agent class loader @@ -619,13 +630,13 @@ public class MBeanInstantiator { **/ static Class loadClass(String className, ClassLoader loader) throws ReflectionException { - Class theClass; if (className == null) { throw new RuntimeOperationsException(new IllegalArgumentException("The class name cannot be null"), "Exception occurred during object instantiation"); } + ReflectUtil.checkPackageAccess(className); try { if (loader == null) loader = MBeanInstantiator.class.getClassLoader(); @@ -676,6 +687,7 @@ public class MBeanInstantiator { // We need to load the class through the class // loader of the target object. // + ReflectUtil.checkPackageAccess(signature[i]); tab[i] = Class.forName(signature[i], false, aLoader); } } catch (ClassNotFoundException e) { @@ -701,7 +713,7 @@ public class MBeanInstantiator { private Constructor findConstructor(Class c, Class[] params) { try { - return c.getConstructor(params); + return ConstructorUtil.getConstructor(c, params); } catch (Exception e) { return null; } @@ -715,4 +727,18 @@ public class MBeanInstantiator { char.class, boolean.class}) primitiveClasses.put(c.getName(), c); } + + private static void checkMBeanPermission(Class clazz, + String member, + ObjectName objectName, + String actions) { + SecurityManager sm = System.getSecurityManager(); + if (clazz != null && sm != null) { + Permission perm = new MBeanPermission(clazz.getName(), + member, + objectName, + actions); + sm.checkPermission(perm); + } + } } diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java index 8109365e8d4..3af4b8b86d7 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java @@ -38,6 +38,7 @@ import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; import javax.management.ReflectionException; import com.sun.jmx.mbeanserver.MXBeanMappingFactory; +import sun.reflect.misc.ReflectUtil; /** * Base class for MBeans. There is one instance of this class for @@ -131,6 +132,7 @@ public abstract class MBeanSupport " is not an instance of " + mbeanInterfaceType.getName(); throw new NotCompliantMBeanException(msg); } + ReflectUtil.checkPackageAccess(mbeanInterfaceType); this.resource = resource; MBeanIntrospector introspector = getMBeanIntrospector(); this.perInterface = introspector.getPerInterface(mbeanInterfaceType); diff --git a/jdk/src/share/classes/java/lang/management/ManagementFactory.java b/jdk/src/share/classes/java/lang/management/ManagementFactory.java index d99333c9e11..278ace1d7d1 100644 --- a/jdk/src/share/classes/java/lang/management/ManagementFactory.java +++ b/jdk/src/share/classes/java/lang/management/ManagementFactory.java @@ -802,20 +802,20 @@ public class ManagementFactory { */ private static void addMXBean(final MBeanServer mbs, final PlatformManagedObject pmo) { // Make DynamicMBean out of MXBean by wrapping it with a StandardMBean - final DynamicMBean dmbean; - if (pmo instanceof DynamicMBean) { - dmbean = DynamicMBean.class.cast(pmo); - } else if (pmo instanceof NotificationEmitter) { - dmbean = new StandardEmitterMBean(pmo, null, true, (NotificationEmitter) pmo); - } else { - dmbean = new StandardMBean(pmo, null, true); - } - try { AccessController.doPrivileged(new PrivilegedExceptionAction() { public Void run() throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { + final DynamicMBean dmbean; + if (pmo instanceof DynamicMBean) { + dmbean = DynamicMBean.class.cast(pmo); + } else if (pmo instanceof NotificationEmitter) { + dmbean = new StandardEmitterMBean(pmo, null, true, (NotificationEmitter) pmo); + } else { + dmbean = new StandardMBean(pmo, null, true); + } + mbs.registerMBean(dmbean, pmo.getObjectName()); return null; } diff --git a/jdk/src/share/lib/security/java.security-linux b/jdk/src/share/lib/security/java.security-linux index c37bb480eb6..8fc53d73677 100644 --- a/jdk/src/share/lib/security/java.security-linux +++ b/jdk/src/share/lib/security/java.security-linux @@ -151,8 +151,7 @@ package.access=sun.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ - com.sun.jmx.defaults.,\ - com.sun.jmx.remote.util.,\ + com.sun.jmx.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ @@ -176,8 +175,7 @@ package.definition=sun.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ - com.sun.jmx.defaults.,\ - com.sun.jmx.remote.util.,\ + com.sun.jmx.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ diff --git a/jdk/src/share/lib/security/java.security-macosx b/jdk/src/share/lib/security/java.security-macosx index ffb99c06936..5a319fa5445 100644 --- a/jdk/src/share/lib/security/java.security-macosx +++ b/jdk/src/share/lib/security/java.security-macosx @@ -152,8 +152,7 @@ package.access=sun.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ - com.sun.jmx.defaults.,\ - com.sun.jmx.remote.util.,\ + com.sun.jmx.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ @@ -178,8 +177,7 @@ package.definition=sun.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ - com.sun.jmx.defaults.,\ - com.sun.jmx.remote.util.,\ + com.sun.jmx.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ diff --git a/jdk/src/share/lib/security/java.security-solaris b/jdk/src/share/lib/security/java.security-solaris index 4236643f55e..2a781cff75d 100644 --- a/jdk/src/share/lib/security/java.security-solaris +++ b/jdk/src/share/lib/security/java.security-solaris @@ -153,8 +153,7 @@ package.access=sun.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ - com.sun.jmx.defaults.,\ - com.sun.jmx.remote.util.,\ + com.sun.jmx.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ @@ -178,8 +177,7 @@ package.definition=sun.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ - com.sun.jmx.defaults.,\ - com.sun.jmx.remote.util.,\ + com.sun.jmx.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows index 89ec5678646..a00f4628dd6 100644 --- a/jdk/src/share/lib/security/java.security-windows +++ b/jdk/src/share/lib/security/java.security-windows @@ -152,8 +152,7 @@ package.access=sun.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ - com.sun.jmx.defaults.,\ - com.sun.jmx.remote.util.,\ + com.sun.jmx.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ @@ -177,8 +176,7 @@ package.definition=sun.,\ com.sun.xml.internal.ws.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ - com.sun.jmx.defaults.,\ - com.sun.jmx.remote.util.,\ + com.sun.jmx.,\ com.sun.proxy.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ diff --git a/jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation2Test.java b/jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation2Test.java index ff56c46fbd2..d91ae14ba57 100644 --- a/jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation2Test.java +++ b/jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation2Test.java @@ -119,9 +119,6 @@ public class SubjectDelegation2Test { System.out.println("Create SimpleStandard MBean"); SimpleStandard s = new SimpleStandard("monitorRole"); mbs.registerMBean(s, new ObjectName("MBeans:type=SimpleStandard")); - // Set Security Manager - // - System.setSecurityManager(new SecurityManager()); // Create Properties containing the username/password entries // Properties props = new Properties(); @@ -132,6 +129,9 @@ public class SubjectDelegation2Test { HashMap env = new HashMap(); env.put("jmx.remote.authenticator", new JMXPluggableAuthenticator(props)); + // Set Security Manager + // + System.setSecurityManager(new SecurityManager()); // Create an RMI connector server // System.out.println("Create an RMI connector server"); diff --git a/jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation3Test.java b/jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation3Test.java index b3a004e0467..de169987796 100644 --- a/jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation3Test.java +++ b/jdk/test/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation3Test.java @@ -120,9 +120,6 @@ public class SubjectDelegation3Test { System.out.println("Create SimpleStandard MBean"); SimpleStandard s = new SimpleStandard("delegate"); mbs.registerMBean(s, new ObjectName("MBeans:type=SimpleStandard")); - // Set Security Manager - // - System.setSecurityManager(new SecurityManager()); // Create Properties containing the username/password entries // Properties props = new Properties(); @@ -133,6 +130,9 @@ public class SubjectDelegation3Test { HashMap env = new HashMap(); env.put("jmx.remote.authenticator", new JMXPluggableAuthenticator(props)); + // Set Security Manager + // + System.setSecurityManager(new SecurityManager()); // Create an RMI connector server // System.out.println("Create an RMI connector server"); From fad9c0e89cf9e887aa6f04e1055a8b6c3248e5ad Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Thu, 24 Jan 2013 16:45:38 -0800 Subject: [PATCH 043/180] 8004937: Improve proxy construction Reviewed-by: jrose, ahgross --- .../java/lang/invoke/MethodHandleNatives.java | 2 ++ .../java/lang/invoke/MethodHandleProxies.java | 25 ++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java index fcc928a327d..8f1d0c3164e 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java @@ -476,6 +476,8 @@ class MethodHandleNatives { case "getProxyClass": case "newProxyInstance": return defc == java.lang.reflect.Proxy.class; + case "asInterfaceInstance": + return defc == java.lang.invoke.MethodHandleProxies.class; case "getBundle": case "clearCache": return defc == java.util.ResourceBundle.class; diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java index b000116d875..ade1630dcfb 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java @@ -141,12 +141,15 @@ public class MethodHandleProxies { T asInterfaceInstance(final Class intfc, final MethodHandle target) { if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers())) throw new IllegalArgumentException("not a public interface: "+intfc.getName()); - SecurityManager smgr = System.getSecurityManager(); - if (smgr != null) { + final MethodHandle mh; + if (System.getSecurityManager() != null) { final int CALLER_FRAME = 2; // 0: Reflection, 1: asInterfaceInstance, 2: caller final Class caller = Reflection.getCallerClass(CALLER_FRAME); - final ClassLoader ccl = caller.getClassLoader(); + final ClassLoader ccl = caller != null ? caller.getClassLoader() : null; ReflectUtil.checkProxyPackageAccess(ccl, intfc); + mh = ccl != null ? bindCaller(target, caller) : target; + } else { + mh = target; } ClassLoader proxyLoader = intfc.getClassLoader(); if (proxyLoader == null) { @@ -160,7 +163,7 @@ public class MethodHandleProxies { for (int i = 0; i < methods.length; i++) { Method sm = methods[i]; MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes()); - MethodHandle checkTarget = target.asType(smMT); // make throw WMT + MethodHandle checkTarget = mh.asType(smMT); // make throw WMT checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class)); vaTargets[i] = checkTarget.asSpreader(Object[].class, smMT.parameterCount()); } @@ -183,8 +186,8 @@ public class MethodHandleProxies { } }; - Object proxy; - if (smgr != null) { + final Object proxy; + if (System.getSecurityManager() != null) { // sun.invoke.WrapperInstance is a restricted interface not accessible // by any non-null class loader. final ClassLoader loader = proxyLoader; @@ -204,6 +207,16 @@ public class MethodHandleProxies { return intfc.cast(proxy); } + private static MethodHandle bindCaller(MethodHandle target, Class hostClass) { + MethodHandle cbmh = MethodHandleImpl.bindCaller(target, hostClass); + if (target.isVarargsCollector()) { + MethodType type = cbmh.type(); + int arity = type.parameterCount(); + return cbmh.asVarargsCollector(type.parameterType(arity-1)); + } + return cbmh; + } + /** * Determines if the given object was produced by a call to {@link #asInterfaceInstance asInterfaceInstance}. * @param x any reference From a320378fac78141df43a719d067b135d9c10fca3 Mon Sep 17 00:00:00 2001 From: Edvard Wendelin Date: Mon, 28 Jan 2013 11:07:07 +0100 Subject: [PATCH 044/180] 8006864: Update java.security-linux to include changes in java.security Reviewed-by: mchung, mullan --- .../share/lib/security/java.security-linux | 28 +++++++++++++++++-- .../share/lib/security/java.security-macosx | 2 ++ .../share/lib/security/java.security-solaris | 6 ++-- .../share/lib/security/java.security-windows | 6 ++-- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/jdk/src/share/lib/security/java.security-linux b/jdk/src/share/lib/security/java.security-linux index dd63fd4d1e2..cdda1b47699 100644 --- a/jdk/src/share/lib/security/java.security-linux +++ b/jdk/src/share/lib/security/java.security-linux @@ -145,7 +145,19 @@ keystore.type=jks # passed to checkPackageAccess unless the # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. -package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal.,jdk.internal. +package.access=sun.,\ + com.sun.xml.internal.bind.,\ + com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.ws.,\ + com.sun.imageio.,\ + com.sun.istack.internal.,\ + com.sun.jmx.defaults.,\ + com.sun.jmx.remote.util.,\ + com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.glassfish.external.,\ + com.sun.org.glassfish.gmbal.,\ + jdk.internal. # # List of comma-separated packages that start with or equal this string @@ -157,7 +169,19 @@ package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun. # by default, none of the class loaders supplied with the JDK call # checkPackageDefinition. # -package.definition=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal.,jdk.internal. +package.definition=sun.,\ + com.sun.xml.internal.bind.,\ + com.sun.xml.internal.org.jvnet.staxex.,\ + com.sun.xml.internal.ws.,\ + com.sun.imageio.,\ + com.sun.istack.internal.,\ + com.sun.jmx.defaults.,\ + com.sun.jmx.remote.util.,\ + com.sun.org.apache.xerces.internal.utils.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.glassfish.external.,\ + com.sun.org.glassfish.gmbal.,\ + jdk.internal. # # Determines whether this properties file can be appended to diff --git a/jdk/src/share/lib/security/java.security-macosx b/jdk/src/share/lib/security/java.security-macosx index 707f1cf21a7..515141de81b 100644 --- a/jdk/src/share/lib/security/java.security-macosx +++ b/jdk/src/share/lib/security/java.security-macosx @@ -158,6 +158,7 @@ package.access=sun.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ com.sun.org.glassfish.gmbal.,\ + jdk.internal.,\ apple. # @@ -182,6 +183,7 @@ package.definition=sun.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ com.sun.org.glassfish.gmbal.,\ + jdk.internal.,\ apple. # diff --git a/jdk/src/share/lib/security/java.security-solaris b/jdk/src/share/lib/security/java.security-solaris index 5f905227d5f..2cccc0d455b 100644 --- a/jdk/src/share/lib/security/java.security-solaris +++ b/jdk/src/share/lib/security/java.security-solaris @@ -158,7 +158,8 @@ package.access=sun.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal. + com.sun.org.glassfish.gmbal.,\ + jdk.internal. # # List of comma-separated packages that start with or equal this string @@ -181,7 +182,8 @@ package.definition=sun.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal. + com.sun.org.glassfish.gmbal.,\ + jdk.internal. # # Determines whether this properties file can be appended to diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows index fceb1021d6d..b6281f741a1 100644 --- a/jdk/src/share/lib/security/java.security-windows +++ b/jdk/src/share/lib/security/java.security-windows @@ -157,7 +157,8 @@ package.access=sun.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal. + com.sun.org.glassfish.gmbal.,\ + jdk.internal. # # List of comma-separated packages that start with or equal this string @@ -180,7 +181,8 @@ package.definition=sun.,\ com.sun.org.apache.xerces.internal.utils.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.glassfish.external.,\ - com.sun.org.glassfish.gmbal. + com.sun.org.glassfish.gmbal.,\ + jdk.internal. # # Determines whether this properties file can be appended to From e84e88f4c9b8375be1764a2d59e2cf2556b3c0a2 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Tue, 5 Feb 2013 22:56:47 -0800 Subject: [PATCH 045/180] 8007393: Possible race condition after JDK-6664509 Reviewed-by: alanb, jgish --- .../classes/java/util/logging/LogManager.java | 50 +++++++++++++------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/jdk/src/share/classes/java/util/logging/LogManager.java b/jdk/src/share/classes/java/util/logging/LogManager.java index 58bd1ba7ead..55b2f206e76 100644 --- a/jdk/src/share/classes/java/util/logging/LogManager.java +++ b/jdk/src/share/classes/java/util/logging/LogManager.java @@ -455,7 +455,40 @@ public class LogManager { } Logger demandSystemLogger(String name, String resourceBundleName) { - return systemContext.demandLogger(name, resourceBundleName); + // Add a system logger in the system context's namespace + final Logger sysLogger = systemContext.demandLogger(name, resourceBundleName); + + // Add the system logger to the LogManager's namespace if not exist + // so that there is only one single logger of the given name. + // System loggers are visible to applications unless a logger of + // the same name has been added. + Logger logger; + do { + // First attempt to call addLogger instead of getLogger + // This would avoid potential bug in custom LogManager.getLogger + // implementation that adds a logger if does not exist + if (addLogger(sysLogger)) { + // successfully added the new system logger + logger = sysLogger; + } else { + logger = getLogger(name); + } + } while (logger == null); + + // LogManager will set the sysLogger's handlers via LogManager.addLogger method. + if (logger != sysLogger && sysLogger.getHandlers().length == 0) { + // if logger already exists but handlers not set + final Logger l = logger; + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + for (Handler hdl : l.getHandlers()) { + sysLogger.addHandler(hdl); + } + return null; + } + }); + } + return sysLogger; } // LoggerContext maintains the logger namespace per context. @@ -663,21 +696,6 @@ public class LogManager { } } while (result == null); } - // Add the system logger to the LogManager's namespace if not exists - // The LogManager will set its handlers via the LogManager.addLogger method. - if (!manager.addLogger(result) && result.getHandlers().length == 0) { - // if logger already exists but handlers not set - final Logger l = manager.getLogger(name); - final Logger logger = result; - AccessController.doPrivileged(new PrivilegedAction() { - public Void run() { - for (Handler hdl : l.getHandlers()) { - logger.addHandler(hdl); - } - return null; - } - }); - } return result; } } From 3479e4412ab65b5c582060e502348c7d81a69b0a Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Thu, 7 Feb 2013 09:41:47 -0800 Subject: [PATCH 046/180] 8007611: logging behavior in applet changed Reviewed-by: alanb, jgish --- jdk/src/share/classes/java/util/logging/LogManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/java/util/logging/LogManager.java b/jdk/src/share/classes/java/util/logging/LogManager.java index 55b2f206e76..40537d2e46e 100644 --- a/jdk/src/share/classes/java/util/logging/LogManager.java +++ b/jdk/src/share/classes/java/util/logging/LogManager.java @@ -395,7 +395,10 @@ public class LogManager { context = userContext; } else { context = new LoggerContext(); - context.addLocalLogger(manager.rootLogger); + // during initialization, rootLogger is null when + // instantiating itself RootLogger + if (manager.rootLogger != null) + context.addLocalLogger(manager.rootLogger); } javaAwtAccess.put(ecx, LoggerContext.class, context); } From e1d6f09bba5aa4bffb1ce6d2ca0b0ebc39166ed9 Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Thu, 7 Feb 2013 16:05:55 -0800 Subject: [PATCH 047/180] 8006777: Improve TLS handling of invalid messages Reviewed-by: wetmore, ahgross --- .../classes/sun/security/ssl/CipherBox.java | 202 ++++++++++++---- .../classes/sun/security/ssl/CipherSuite.java | 23 +- .../sun/security/ssl/EngineInputRecord.java | 220 ++++++++++++------ .../sun/security/ssl/EngineOutputRecord.java | 4 +- .../classes/sun/security/ssl/InputRecord.java | 184 ++++++++++++--- .../share/classes/sun/security/ssl/MAC.java | 51 ++-- .../sun/security/ssl/OutputRecord.java | 4 +- .../sun/security/ssl/SSLEngineImpl.java | 26 +-- .../sun/security/ssl/SSLSocketImpl.java | 22 +- 9 files changed, 527 insertions(+), 209 deletions(-) diff --git a/jdk/src/share/classes/sun/security/ssl/CipherBox.java b/jdk/src/share/classes/sun/security/ssl/CipherBox.java index 362f9b5d904..52bb7d95863 100644 --- a/jdk/src/share/classes/sun/security/ssl/CipherBox.java +++ b/jdk/src/share/classes/sun/security/ssl/CipherBox.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, 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 @@ -392,7 +392,8 @@ final class CipherBox { * uniformly use the bad_record_mac alert to hide the specific type of * the error. */ - int decrypt(byte[] buf, int offset, int len) throws BadPaddingException { + int decrypt(byte[] buf, int offset, int len, + int tagLen) throws BadPaddingException { if (cipher == null) { return len; } @@ -416,9 +417,10 @@ final class CipherBox { System.out); } catch (IOException e) { } } + if (blockSize != 0) { - newLen = removePadding(buf, offset, newLen, - blockSize, protocolVersion); + newLen = removePadding( + buf, offset, newLen, tagLen, blockSize, protocolVersion); if (protocolVersion.v >= ProtocolVersion.TLS11.v) { if (newLen < blockSize) { @@ -448,7 +450,7 @@ final class CipherBox { * * @see decrypt(byte[], int, int) */ - int decrypt(ByteBuffer bb) throws BadPaddingException { + int decrypt(ByteBuffer bb, int tagLen) throws BadPaddingException { int len = bb.remaining(); @@ -471,7 +473,6 @@ final class CipherBox { } if (debug != null && Debug.isOn("plaintext")) { - bb.position(pos); try { HexDumpEncoder hd = new HexDumpEncoder(); @@ -479,7 +480,8 @@ final class CipherBox { "Padded plaintext after DECRYPTION: len = " + newLen); - hd.encodeBuffer(bb, System.out); + hd.encodeBuffer( + (ByteBuffer)bb.duplicate().position(pos), System.out); } catch (IOException e) { } } @@ -488,7 +490,8 @@ final class CipherBox { */ if (blockSize != 0) { bb.position(pos); - newLen = removePadding(bb, blockSize, protocolVersion); + newLen = removePadding( + bb, tagLen, blockSize, protocolVersion); if (protocolVersion.v >= ProtocolVersion.TLS11.v) { if (newLen < blockSize) { @@ -590,6 +593,65 @@ final class CipherBox { return newlen; } + /* + * A constant-time check of the padding. + * + * NOTE that we are checking both the padding and the padLen bytes here. + * + * The caller MUST ensure that the len parameter is a positive number. + */ + private static int[] checkPadding( + byte[] buf, int offset, int len, byte pad) { + + if (len <= 0) { + throw new RuntimeException("padding len must be positive"); + } + + // An array of hits is used to prevent Hotspot optimization for + // the purpose of a constant-time check. + int[] results = {0, 0}; // {missed #, matched #} + for (int i = 0; i <= 256;) { + for (int j = 0; j < len && i <= 256; j++, i++) { // j <= i + if (buf[offset + j] != pad) { + results[0]++; // mismatched padding data + } else { + results[1]++; // matched padding data + } + } + } + + return results; + } + + /* + * A constant-time check of the padding. + * + * NOTE that we are checking both the padding and the padLen bytes here. + * + * The caller MUST ensure that the bb parameter has remaining. + */ + private static int[] checkPadding(ByteBuffer bb, byte pad) { + + if (!bb.hasRemaining()) { + throw new RuntimeException("hasRemaining() must be positive"); + } + + // An array of hits is used to prevent Hotspot optimization for + // the purpose of a constant-time check. + int[] results = {0, 0}; // {missed #, matched #} + bb.mark(); + for (int i = 0; i <= 256; bb.reset()) { + for (; bb.hasRemaining() && i <= 256; i++) { + if (bb.get() != pad) { + results[0]++; // mismatched padding data + } else { + results[1]++; // matched padding data + } + } + } + + return results; + } /* * Typical TLS padding format for a 64 bit block cipher is as follows: @@ -602,86 +664,95 @@ final class CipherBox { * as it makes the data a multiple of the block size */ private static int removePadding(byte[] buf, int offset, int len, - int blockSize, ProtocolVersion protocolVersion) - throws BadPaddingException { + int tagLen, int blockSize, + ProtocolVersion protocolVersion) throws BadPaddingException { + // last byte is length byte (i.e. actual padding length - 1) int padOffset = offset + len - 1; - int pad = buf[padOffset] & 0x0ff; + int padLen = buf[padOffset] & 0xFF; - int newlen = len - (pad + 1); - if (newlen < 0) { - throw new BadPaddingException("Padding length invalid: " + pad); + int newLen = len - (padLen + 1); + if ((newLen - tagLen) < 0) { + // If the buffer is not long enough to contain the padding plus + // a MAC tag, do a dummy constant-time padding check. + // + // Note that it is a dummy check, so we won't care about what is + // the actual padding data. + checkPadding(buf, offset, len, (byte)(padLen & 0xFF)); + + throw new BadPaddingException("Invalid Padding length: " + padLen); } + // The padding data should be filled with the padding length value. + int[] results = checkPadding(buf, offset + newLen, + padLen + 1, (byte)(padLen & 0xFF)); if (protocolVersion.v >= ProtocolVersion.TLS10.v) { - for (int i = 1; i <= pad; i++) { - int val = buf[padOffset - i] & 0xff; - if (val != pad) { - throw new BadPaddingException - ("Invalid TLS padding: " + val); - } + if (results[0] != 0) { // padding data has invalid bytes + throw new BadPaddingException("Invalid TLS padding data"); } } else { // SSLv3 // SSLv3 requires 0 <= length byte < block size // some implementations do 1 <= length byte <= block size, // so accept that as well // v3 does not require any particular value for the other bytes - if (pad > blockSize) { - throw new BadPaddingException("Invalid SSLv3 padding: " + pad); + if (padLen > blockSize) { + throw new BadPaddingException("Invalid SSLv3 padding"); } } - return newlen; + return newLen; } /* * Position/limit is equal the removed padding. */ private static int removePadding(ByteBuffer bb, - int blockSize, ProtocolVersion protocolVersion) - throws BadPaddingException { + int tagLen, int blockSize, + ProtocolVersion protocolVersion) throws BadPaddingException { int len = bb.remaining(); int offset = bb.position(); // last byte is length byte (i.e. actual padding length - 1) int padOffset = offset + len - 1; - int pad = bb.get(padOffset) & 0x0ff; + int padLen = bb.get(padOffset) & 0xFF; - int newlen = len - (pad + 1); - if (newlen < 0) { - throw new BadPaddingException("Padding length invalid: " + pad); + int newLen = len - (padLen + 1); + if ((newLen - tagLen) < 0) { + // If the buffer is not long enough to contain the padding plus + // a MAC tag, do a dummy constant-time padding check. + // + // Note that it is a dummy check, so we won't care about what is + // the actual padding data. + checkPadding(bb.duplicate(), (byte)(padLen & 0xFF)); + + throw new BadPaddingException("Invalid Padding length: " + padLen); } - /* - * We could zero the padding area, but not much useful - * information there. - */ + // The padding data should be filled with the padding length value. + int[] results = checkPadding( + (ByteBuffer)bb.duplicate().position(offset + newLen), + (byte)(padLen & 0xFF)); if (protocolVersion.v >= ProtocolVersion.TLS10.v) { - bb.put(padOffset, (byte)0); // zero the padding. - for (int i = 1; i <= pad; i++) { - int val = bb.get(padOffset - i) & 0xff; - if (val != pad) { - throw new BadPaddingException - ("Invalid TLS padding: " + val); - } + if (results[0] != 0) { // padding data has invalid bytes + throw new BadPaddingException("Invalid TLS padding data"); } } else { // SSLv3 // SSLv3 requires 0 <= length byte < block size // some implementations do 1 <= length byte <= block size, // so accept that as well // v3 does not require any particular value for the other bytes - if (pad > blockSize) { - throw new BadPaddingException("Invalid SSLv3 padding: " + pad); + if (padLen > blockSize) { + throw new BadPaddingException("Invalid SSLv3 padding"); } } /* * Reset buffer limit to remove padding. */ - bb.position(offset + newlen); - bb.limit(offset + newlen); + bb.position(offset + newLen); + bb.limit(offset + newLen); - return newlen; + return newLen; } /* @@ -708,4 +779,45 @@ final class CipherBox { boolean isCBCMode() { return isCBCMode; } + + /** + * Is the cipher null? + * + * @return true if the cipher is null, false otherwise. + */ + boolean isNullCipher() { + return cipher == null; + } + + /** + * Sanity check the length of a fragment before decryption. + * + * In CBC mode, check that the fragment length is one or multiple times + * of the block size of the cipher suite, and is at least one (one is the + * smallest size of padding in CBC mode) bigger than the tag size of the + * MAC algorithm except the explicit IV size for TLS 1.1 or later. + * + * In non-CBC mode, check that the fragment length is not less than the + * tag size of the MAC algorithm. + * + * @return true if the length of a fragment matches above requirements + */ + boolean sanityCheck(int tagLen, int fragmentLen) { + if (!isCBCMode) { + return fragmentLen >= tagLen; + } + + if ((fragmentLen % blockSize) == 0) { + int minimal = tagLen + 1; + minimal = (minimal >= blockSize) ? minimal : blockSize; + if (protocolVersion.v >= ProtocolVersion.TLS11.v) { + minimal += blockSize; // plus the size of the explicit IV + } + + return (fragmentLen >= minimal); + } + + return false; + } + } diff --git a/jdk/src/share/classes/sun/security/ssl/CipherSuite.java b/jdk/src/share/classes/sun/security/ssl/CipherSuite.java index 555304880b7..e0a081ad85d 100644 --- a/jdk/src/share/classes/sun/security/ssl/CipherSuite.java +++ b/jdk/src/share/classes/sun/security/ssl/CipherSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, 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 @@ -549,9 +549,18 @@ final class CipherSuite implements Comparable { // size of the MAC value (and MAC key) in bytes final int size; - MacAlg(String name, int size) { + // block size of the underlying hash algorithm + final int hashBlockSize; + + // minimal padding size of the underlying hash algorithm + final int minimalPaddingSize; + + MacAlg(String name, int size, + int hashBlockSize, int minimalPaddingSize) { this.name = name; this.size = size; + this.hashBlockSize = hashBlockSize; + this.minimalPaddingSize = minimalPaddingSize; } /** @@ -596,11 +605,11 @@ final class CipherSuite implements Comparable { new BulkCipher(CIPHER_AES, 32, 16, true); // MACs - final static MacAlg M_NULL = new MacAlg("NULL", 0); - final static MacAlg M_MD5 = new MacAlg("MD5", 16); - final static MacAlg M_SHA = new MacAlg("SHA", 20); - final static MacAlg M_SHA256 = new MacAlg("SHA256", 32); - final static MacAlg M_SHA384 = new MacAlg("SHA384", 48); + final static MacAlg M_NULL = new MacAlg("NULL", 0, 0, 0); + final static MacAlg M_MD5 = new MacAlg("MD5", 16, 64, 9); + final static MacAlg M_SHA = new MacAlg("SHA", 20, 64, 9); + final static MacAlg M_SHA256 = new MacAlg("SHA256", 32, 64, 9); + final static MacAlg M_SHA384 = new MacAlg("SHA384", 48, 128, 17); /** * PRFs (PseudoRandom Function) from TLS specifications. diff --git a/jdk/src/share/classes/sun/security/ssl/EngineInputRecord.java b/jdk/src/share/classes/sun/security/ssl/EngineInputRecord.java index 6b064385203..9161d6de8ef 100644 --- a/jdk/src/share/classes/sun/security/ssl/EngineInputRecord.java +++ b/jdk/src/share/classes/sun/security/ssl/EngineInputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -177,71 +177,6 @@ final class EngineInputRecord extends InputRecord { return len; } - /* - * Verifies and removes the MAC value. Returns true if - * the MAC checks out OK. - * - * On entry: - * position = beginning of app/MAC data - * limit = end of MAC data. - * - * On return: - * position = beginning of app data - * limit = end of app data - */ - boolean checkMAC(MAC signer, ByteBuffer bb) { - if (internalData) { - return checkMAC(signer); - } - - int len = signer.MAClen(); - if (len == 0) { // no mac - return true; - } - - /* - * Grab the original limit - */ - int lim = bb.limit(); - - /* - * Delineate the area to apply a MAC on. - */ - int macData = lim - len; - bb.limit(macData); - - byte[] mac = signer.compute(contentType(), bb); - - if (len != mac.length) { - throw new RuntimeException("Internal MAC error"); - } - - /* - * Delineate the MAC values, position was already set - * by doing the compute above. - * - * We could zero the MAC area, but not much useful information - * there anyway. - */ - bb.position(macData); - bb.limit(lim); - - try { - for (int i = 0; i < len; i++) { - if (bb.get() != mac[i]) { // No BB.equals(byte []); ! - return false; - } - } - return true; - } finally { - /* - * Position to the data. - */ - bb.rewind(); - bb.limit(macData); - } - } - /* * Pass the data down if it's internally cached, otherwise * do it here. @@ -251,20 +186,163 @@ final class EngineInputRecord extends InputRecord { * If external data(app), return a new ByteBuffer with data to * process. */ - ByteBuffer decrypt(CipherBox box, ByteBuffer bb) - throws BadPaddingException { + ByteBuffer decrypt(MAC signer, + CipherBox box, ByteBuffer bb) throws BadPaddingException { if (internalData) { - decrypt(box); + decrypt(signer, box); // MAC is checked during decryption return tmpBB; } - box.decrypt(bb); - bb.rewind(); + BadPaddingException reservedBPE = null; + int tagLen = signer.MAClen(); + int cipheredLength = bb.remaining(); + + if (!box.isNullCipher()) { + // sanity check length of the ciphertext + if (!box.sanityCheck(tagLen, cipheredLength)) { + throw new BadPaddingException( + "ciphertext sanity check failed"); + } + + try { + // Note that the CipherBox.decrypt() does not change + // the capacity of the buffer. + box.decrypt(bb, tagLen); + } catch (BadPaddingException bpe) { + // RFC 2246 states that decryption_failed should be used + // for this purpose. However, that allows certain attacks, + // so we just send bad record MAC. We also need to make + // sure to always check the MAC to avoid a timing attack + // for the same issue. See paper by Vaudenay et al and the + // update in RFC 4346/5246. + // + // Failover to message authentication code checking. + reservedBPE = bpe; + } finally { + bb.rewind(); + } + } + + if (tagLen != 0) { + int macOffset = bb.limit() - tagLen; + + // Note that although it is not necessary, we run the same MAC + // computation and comparison on the payload for both stream + // cipher and CBC block cipher. + if (bb.remaining() < tagLen) { + // negative data length, something is wrong + if (reservedBPE == null) { + reservedBPE = new BadPaddingException("bad record"); + } + + // set offset of the dummy MAC + macOffset = cipheredLength - tagLen; + bb.limit(cipheredLength); + } + + // Run MAC computation and comparison on the payload. + if (checkMacTags(contentType(), bb, signer, false)) { + if (reservedBPE == null) { + reservedBPE = new BadPaddingException("bad record MAC"); + } + } + + // Run MAC computation and comparison on the remainder. + // + // It is only necessary for CBC block cipher. It is used to get a + // constant time of MAC computation and comparison on each record. + if (box.isCBCMode()) { + int remainingLen = calculateRemainingLen( + signer, cipheredLength, macOffset); + + // NOTE: here we use the InputRecord.buf because I did not find + // an effective way to work on ByteBuffer when its capacity is + // less than remainingLen. + + // NOTE: remainingLen may be bigger (less than 1 block of the + // hash algorithm of the MAC) than the cipheredLength. However, + // We won't need to worry about it because we always use a + // maximum buffer for every record. We need a change here if + // we use small buffer size in the future. + if (remainingLen > buf.length) { + // unlikely to happen, just a placehold + throw new RuntimeException( + "Internal buffer capacity error"); + } + + // Won't need to worry about the result on the remainder. And + // then we won't need to worry about what's actual data to + // check MAC tag on. We start the check from the header of the + // buffer so that we don't need to construct a new byte buffer. + checkMacTags(contentType(), buf, 0, remainingLen, signer, true); + } + + bb.limit(macOffset); + } + + // Is it a failover? + if (reservedBPE != null) { + throw reservedBPE; + } return bb.slice(); } + /* + * Run MAC computation and comparison + * + * Please DON'T change the content of the ByteBuffer parameter! + */ + private static boolean checkMacTags(byte contentType, ByteBuffer bb, + MAC signer, boolean isSimulated) { + + int tagLen = signer.MAClen(); + int lim = bb.limit(); + int macData = lim - tagLen; + + bb.limit(macData); + byte[] hash = signer.compute(contentType, bb, isSimulated); + if (hash == null || tagLen != hash.length) { + // Something is wrong with MAC implementation. + throw new RuntimeException("Internal MAC error"); + } + + bb.position(macData); + bb.limit(lim); + try { + int[] results = compareMacTags(bb, hash); + return (results[0] != 0); + } finally { + bb.rewind(); + bb.limit(macData); + } + } + + /* + * A constant-time comparison of the MAC tags. + * + * Please DON'T change the content of the ByteBuffer parameter! + */ + private static int[] compareMacTags(ByteBuffer bb, byte[] tag) { + + // An array of hits is used to prevent Hotspot optimization for + // the purpose of a constant-time check. + int[] results = {0, 0}; // {missed #, matched #} + + // The caller ensures there are enough bytes available in the buffer. + // So we won't need to check the remaining of the buffer. + for (int i = 0; i < tag.length; i++) { + if (bb.get() != tag[i]) { + results[0]++; // mismatched bytes + } else { + results[1]++; // matched bytes + } + } + + return results; + } + /* * Override the actual write below. We do things this way to be * consistent with InputRecord. InputRecord may try to write out diff --git a/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java b/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java index e9d39805b36..ae414c115f2 100644 --- a/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java +++ b/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -118,7 +118,7 @@ final class EngineOutputRecord extends OutputRecord { throws IOException { if (signer.MAClen() != 0) { - byte[] hash = signer.compute(contentType(), bb); + byte[] hash = signer.compute(contentType(), bb, false); /* * position was advanced to limit in compute above. diff --git a/jdk/src/share/classes/sun/security/ssl/InputRecord.java b/jdk/src/share/classes/sun/security/ssl/InputRecord.java index 78e866a07ca..45fdc62dd21 100644 --- a/jdk/src/share/classes/sun/security/ssl/InputRecord.java +++ b/jdk/src/share/classes/sun/security/ssl/InputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, 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 @@ -133,43 +133,173 @@ class InputRecord extends ByteArrayInputStream implements Record { return handshakeHash; } + void decrypt(MAC signer, CipherBox box) throws BadPaddingException { + + BadPaddingException reservedBPE = null; + int tagLen = signer.MAClen(); + int cipheredLength = count - headerSize; + + if (!box.isNullCipher()) { + // sanity check length of the ciphertext + if (!box.sanityCheck(tagLen, cipheredLength)) { + throw new BadPaddingException( + "ciphertext sanity check failed"); + } + + try { + // Note that the CipherBox.decrypt() does not change + // the capacity of the buffer. + count = headerSize + + box.decrypt(buf, headerSize, cipheredLength, tagLen); + } catch (BadPaddingException bpe) { + // RFC 2246 states that decryption_failed should be used + // for this purpose. However, that allows certain attacks, + // so we just send bad record MAC. We also need to make + // sure to always check the MAC to avoid a timing attack + // for the same issue. See paper by Vaudenay et al and the + // update in RFC 4346/5246. + // + // Failover to message authentication code checking. + reservedBPE = bpe; + } + } + + if (tagLen != 0) { + int macOffset = count - tagLen; + int contentLen = macOffset - headerSize; + + // Note that although it is not necessary, we run the same MAC + // computation and comparison on the payload for both stream + // cipher and CBC block cipher. + if (contentLen < 0) { + // negative data length, something is wrong + if (reservedBPE == null) { + reservedBPE = new BadPaddingException("bad record"); + } + + // set offset of the dummy MAC + macOffset = headerSize + cipheredLength - tagLen; + contentLen = macOffset - headerSize; + } + + count -= tagLen; // Set the count before any MAC checking + // exception occurs, so that the following + // process can read the actual decrypted + // content (minus the MAC) in the fragment + // if necessary. + + // Run MAC computation and comparison on the payload. + if (checkMacTags(contentType(), + buf, headerSize, contentLen, signer, false)) { + if (reservedBPE == null) { + reservedBPE = new BadPaddingException("bad record MAC"); + } + } + + // Run MAC computation and comparison on the remainder. + // + // It is only necessary for CBC block cipher. It is used to get a + // constant time of MAC computation and comparison on each record. + if (box.isCBCMode()) { + int remainingLen = calculateRemainingLen( + signer, cipheredLength, contentLen); + + // NOTE: remainingLen may be bigger (less than 1 block of the + // hash algorithm of the MAC) than the cipheredLength. However, + // We won't need to worry about it because we always use a + // maximum buffer for every record. We need a change here if + // we use small buffer size in the future. + if (remainingLen > buf.length) { + // unlikely to happen, just a placehold + throw new RuntimeException( + "Internal buffer capacity error"); + } + + // Won't need to worry about the result on the remainder. And + // then we won't need to worry about what's actual data to + // check MAC tag on. We start the check from the header of the + // buffer so that we don't need to construct a new byte buffer. + checkMacTags(contentType(), buf, 0, remainingLen, signer, true); + } + } + + // Is it a failover? + if (reservedBPE != null) { + throw reservedBPE; + } + } + /* - * Verify and remove the MAC ... used for all records. + * Run MAC computation and comparison + * + * Please DON'T change the content of the byte buffer parameter! */ - boolean checkMAC(MAC signer) { - int len = signer.MAClen(); - if (len == 0) { // no mac - return true; - } + static boolean checkMacTags(byte contentType, byte[] buffer, + int offset, int contentLen, MAC signer, boolean isSimulated) { - int offset = count - len; - - if (offset < headerSize) { - // data length would be negative, something is wrong - return false; - } - - byte[] mac = signer.compute(contentType(), buf, - headerSize, offset - headerSize); - - if (len != mac.length) { + int tagLen = signer.MAClen(); + byte[] hash = signer.compute( + contentType, buffer, offset, contentLen, isSimulated); + if (hash == null || tagLen != hash.length) { + // Something is wrong with MAC implementation. throw new RuntimeException("Internal MAC error"); } - for (int i = 0; i < len; i++) { - if (buf[offset + i] != mac[i]) { - return false; + int[] results = compareMacTags(buffer, offset + contentLen, hash); + return (results[0] != 0); + } + + /* + * A constant-time comparison of the MAC tags. + * + * Please DON'T change the content of the byte buffer parameter! + */ + private static int[] compareMacTags( + byte[] buffer, int offset, byte[] tag) { + + // An array of hits is used to prevent Hotspot optimization for + // the purpose of a constant-time check. + int[] results = {0, 0}; // {missed #, matched #} + + // The caller ensures there are enough bytes available in the buffer. + // So we won't need to check the length of the buffer. + for (int i = 0; i < tag.length; i++) { + if (buffer[offset + i] != tag[i]) { + results[0]++; // mismatched bytes + } else { + results[1]++; // matched bytes } } - count -= len; - return true; + + return results; } - void decrypt(CipherBox box) throws BadPaddingException { - int len = count - headerSize; - count = headerSize + box.decrypt(buf, headerSize, len); - } + /* + * Calculate the length of a dummy buffer to run MAC computation + * and comparison on the remainder. + * + * The caller MUST ensure that the fullLen is not less than usedLen. + */ + static int calculateRemainingLen( + MAC signer, int fullLen, int usedLen) { + int blockLen = signer.hashBlockLen(); + int minimalPaddingLen = signer.minimalPaddingLen(); + + // (blockLen - minimalPaddingLen) is the maximum message size of + // the last block of hash function operation. See FIPS 180-4, or + // MD5 specification. + fullLen += 13 - (blockLen - minimalPaddingLen); + usedLen += 13 - (blockLen - minimalPaddingLen); + + // Note: fullLen is always not less than usedLen, and blockLen + // is always bigger than minimalPaddingLen, so we don't worry + // about negative values. 0x01 is added to the result to ensure + // that the return value is positive. The extra one byte does + // not impact the overall MAC compression function evaluations. + return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) - + Math.ceil(usedLen/(1.0d * blockLen))) * signer.hashBlockLen(); + } /* * Well ... hello_request messages are _never_ hashed since we can't diff --git a/jdk/src/share/classes/sun/security/ssl/MAC.java b/jdk/src/share/classes/sun/security/ssl/MAC.java index 753a8c57ac4..e491cc301da 100644 --- a/jdk/src/share/classes/sun/security/ssl/MAC.java +++ b/jdk/src/share/classes/sun/security/ssl/MAC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, 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 @@ -43,8 +43,8 @@ import static sun.security.ssl.CipherSuite.*; * provide integrity protection for SSL messages. The MAC is actually * one of several keyed hashes, as associated with the cipher suite and * protocol version. (SSL v3.0 uses one construct, TLS uses another.) - * - *

    NOTE: MAC computation is the only place in the SSL protocol that the + *

    + * NOTE: MAC computation is the only place in the SSL protocol that the * sequence number is used. It's also reset to zero with each change of * a cipher spec, so this is the only place this state is needed. * @@ -58,6 +58,9 @@ final class MAC { // Value of the null MAC is fixed private static final byte nullMAC[] = new byte[0]; + // internal identifier for the MAC algorithm + private final MacAlg macAlg; + // stuff defined by the kind of MAC algorithm private final int macSize; @@ -82,6 +85,7 @@ final class MAC { private MAC() { macSize = 0; + macAlg = M_NULL; mac = null; block = null; } @@ -91,6 +95,7 @@ final class MAC { */ MAC(MacAlg macAlg, ProtocolVersion protocolVersion, SecretKey key) throws NoSuchAlgorithmException, InvalidKeyException { + this.macAlg = macAlg; this.macSize = macAlg.size; String algorithm; @@ -127,6 +132,20 @@ final class MAC { return macSize; } + /** + * Returns the hash function block length of the MAC alorithm. + */ + int hashBlockLen() { + return macAlg.hashBlockSize; + } + + /** + * Returns the hash function minimal padding length of the MAC alorithm. + */ + int minimalPaddingLen() { + return macAlg.minimalPaddingSize; + } + /** * Computes and returns the MAC for the data in this byte array. * @@ -134,9 +153,11 @@ final class MAC { * @param buf compressed record on which the MAC is computed * @param offset start of compressed record data * @param len the size of the compressed record + * @param isSimulated if true, simulate the the MAC computation */ - final byte[] compute(byte type, byte buf[], int offset, int len) { - return compute(type, null, buf, offset, len); + final byte[] compute(byte type, byte buf[], + int offset, int len, boolean isSimulated) { + return compute(type, null, buf, offset, len, isSimulated); } /** @@ -149,9 +170,10 @@ final class MAC { * @param type record type * @param bb a ByteBuffer in which the position and limit * demarcate the data to be MAC'd. + * @param isSimulated if true, simulate the the MAC computation */ - final byte[] compute(byte type, ByteBuffer bb) { - return compute(type, bb, null, 0, bb.remaining()); + final byte[] compute(byte type, ByteBuffer bb, boolean isSimulated) { + return compute(type, bb, null, 0, bb.remaining(), isSimulated); } /** @@ -204,18 +226,21 @@ final class MAC { * or buf/offset/len. */ private byte[] compute(byte type, ByteBuffer bb, byte[] buf, - int offset, int len) { + int offset, int len, boolean isSimulated) { if (macSize == 0) { return nullMAC; } - block[BLOCK_OFFSET_TYPE] = type; - block[block.length - 2] = (byte)(len >> 8); - block[block.length - 1] = (byte)(len ); + // MUST NOT increase the sequence number for a simulated computation. + if (!isSimulated) { + block[BLOCK_OFFSET_TYPE] = type; + block[block.length - 2] = (byte)(len >> 8); + block[block.length - 1] = (byte)(len ); - mac.update(block); - incrementSequenceNumber(); + mac.update(block); + incrementSequenceNumber(); + } // content if (bb != null) { diff --git a/jdk/src/share/classes/sun/security/ssl/OutputRecord.java b/jdk/src/share/classes/sun/security/ssl/OutputRecord.java index 900003dfd0f..0ff27be460d 100644 --- a/jdk/src/share/classes/sun/security/ssl/OutputRecord.java +++ b/jdk/src/share/classes/sun/security/ssl/OutputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, 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 @@ -205,7 +205,7 @@ class OutputRecord extends ByteArrayOutputStream implements Record { } if (signer.MAClen() != 0) { byte[] hash = signer.compute(contentType, buf, - headerSize, count - headerSize); + headerSize, count - headerSize, false); write(hash); } } diff --git a/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java index 41415337ca1..5534cab0384 100644 --- a/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -958,35 +958,15 @@ final public class SSLEngineImpl extends SSLEngine { * throw a fatal alert if the integrity check fails. */ try { - decryptedBB = inputRecord.decrypt(readCipher, readBB); + decryptedBB = inputRecord.decrypt(readMAC, readCipher, readBB); } catch (BadPaddingException e) { - // RFC 2246 states that decryption_failed should be used - // for this purpose. However, that allows certain attacks, - // so we just send bad record MAC. We also need to make - // sure to always check the MAC to avoid a timing attack - // for the same issue. See paper by Vaudenay et al. - // - // rewind the BB if necessary. - readBB.rewind(); - - inputRecord.checkMAC(readMAC, readBB); - - // use the same alert types as for MAC failure below byte alertType = (inputRecord.contentType() == Record.ct_handshake) ? Alerts.alert_handshake_failure : Alerts.alert_bad_record_mac; - fatal(alertType, "Invalid padding", e); + fatal(alertType, e.getMessage(), e); } - if (!inputRecord.checkMAC(readMAC, decryptedBB)) { - if (inputRecord.contentType() == Record.ct_handshake) { - fatal(Alerts.alert_handshake_failure, - "bad handshake record MAC"); - } else { - fatal(Alerts.alert_bad_record_mac, "bad record MAC"); - } - } // if (!inputRecord.decompress(c)) // fatal(Alerts.alert_decompression_failure, diff --git a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java index f807c4c58ce..cbc3db69b96 100644 --- a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, 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 @@ -986,29 +986,13 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * throw a fatal alert if the integrity check fails. */ try { - r.decrypt(readCipher); + r.decrypt(readMAC, readCipher); } catch (BadPaddingException e) { - // RFC 2246 states that decryption_failed should be used - // for this purpose. However, that allows certain attacks, - // so we just send bad record MAC. We also need to make - // sure to always check the MAC to avoid a timing attack - // for the same issue. See paper by Vaudenay et al. - r.checkMAC(readMAC); - // use the same alert types as for MAC failure below byte alertType = (r.contentType() == Record.ct_handshake) ? Alerts.alert_handshake_failure : Alerts.alert_bad_record_mac; - fatal(alertType, "Invalid padding", e); + fatal(alertType, e.getMessage(), e); } - if (!r.checkMAC(readMAC)) { - if (r.contentType() == Record.ct_handshake) { - fatal(Alerts.alert_handshake_failure, - "bad handshake record MAC"); - } else { - fatal(Alerts.alert_bad_record_mac, "bad record MAC"); - } - } - // if (!r.decompress(c)) // fatal(Alerts.alert_decompression_failure, From 3ae3ac4f875af338d660b8d9f5998e5c327827b9 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Thu, 7 Feb 2013 16:03:43 -0800 Subject: [PATCH 048/180] 8007688: Blacklist known bad certificate Added two known bad certs to the blacklist certs. Reviewed-by: mullan --- .../security/util/UntrustedCertificates.java | 108 +++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/sun/security/util/UntrustedCertificates.java b/jdk/src/share/classes/sun/security/util/UntrustedCertificates.java index 6aad34a73a4..03fdbc78332 100644 --- a/jdk/src/share/classes/sun/security/util/UntrustedCertificates.java +++ b/jdk/src/share/classes/sun/security/util/UntrustedCertificates.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -737,5 +737,111 @@ public final class UntrustedCertificates { "B8WfedLHjFW/TMcnXlEWKz4=\n" + "-----END CERTIFICATE-----"); + // + // Revoked DigiCert code signing certificates used to sign malware + // + + // Subject: CN=Buster Paper Comercial Ltda, + // O=Buster Paper Comercial Ltda, + // L=S?o Jos? Dos Campos, + // ST=S?o Paulo, + // C=BR + // Issuer: CN=DigiCert Assured ID Code Signing CA-1, + // OU=www.digicert.com, + // O=DigiCert Inc, + // C=US + // Serial: 07:b4:4c:db:ff:fb:78:de:05:f4:26:16:72:a6:73:12 + add("buster-paper-comercial-ltda-72A67312", + "-----BEGIN CERTIFICATE-----\n" + + "MIIGwzCCBaugAwIBAgIQB7RM2//7eN4F9CYWcqZzEjANBgkqhkiG9w0BAQUFADBv\n" + + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" + + "d3cuZGlnaWNlcnQuY29tMS4wLAYDVQQDEyVEaWdpQ2VydCBBc3N1cmVkIElEIENv\n" + + "ZGUgU2lnbmluZyBDQS0xMB4XDTEzMDExNzAwMDAwMFoXDTE0MDEyMjEyMDAwMFow\n" + + "gY4xCzAJBgNVBAYTAkJSMRMwEQYDVQQIDApTw6NvIFBhdWxvMR4wHAYDVQQHDBVT\n" + + "w6NvIEpvc8OpIERvcyBDYW1wb3MxJDAiBgNVBAoTG0J1c3RlciBQYXBlciBDb21l\n" + + "cmNpYWwgTHRkYTEkMCIGA1UEAxMbQnVzdGVyIFBhcGVyIENvbWVyY2lhbCBMdGRh\n" + + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzO0l6jWIpEfO2oUpVHpL\n" + + "HETj5lzivNb0S9jKHgGJax917czh81PnGTxwxFXd6gLJuy/XFHvmiSi8g8jzlymn\n" + + "2Ji5zQ3CPaz7nomJokSUDlMVJ2qYWtctw4jrdjuI4qtn+koXXUFkWjkf8h8251I4\n" + + "tUs7S49HE2Go5owCYP3byajj7fsFAYR/Xb7TdVtndkZsUB/YgOjHovyACjouaNCi\n" + + "mDiRyQ6zLLjZGiyeD65Yiseuhp5b8/BL5h1p7w76QYMYMVQNAdtDKut2R8MBpuWf\n" + + "Ny7Eoi0x/gm1p9X5Rcl5aN7K0G4UtTAJKbkuUfXddsyFoM0Nx8uo8SgNQ8Y/X5Jx\n" + + "BwIDAQABo4IDOTCCAzUwHwYDVR0jBBgwFoAUe2jOKarAF75JeuHlP9an90WPNTIw\n" + + "HQYDVR0OBBYEFFLZ3n5nt/Eer7n1bvtOqMb1qKO5MA4GA1UdDwEB/wQEAwIHgDAT\n" + + "BgNVHSUEDDAKBggrBgEFBQcDAzBzBgNVHR8EbDBqMDOgMaAvhi1odHRwOi8vY3Js\n" + + "My5kaWdpY2VydC5jb20vYXNzdXJlZC1jcy0yMDExYS5jcmwwM6AxoC+GLWh0dHA6\n" + + "Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9hc3N1cmVkLWNzLTIwMTFhLmNybDCCAcQGA1Ud\n" + + "IASCAbswggG3MIIBswYJYIZIAYb9bAMBMIIBpDA6BggrBgEFBQcCARYuaHR0cDov\n" + + "L3d3dy5kaWdpY2VydC5jb20vc3NsLWNwcy1yZXBvc2l0b3J5Lmh0bTCCAWQGCCsG\n" + + "AQUFBwICMIIBVh6CAVIAQQBuAHkAIAB1AHMAZQAgAG8AZgAgAHQAaABpAHMAIABD\n" + + "AGUAcgB0AGkAZgBpAGMAYQB0AGUAIABjAG8AbgBzAHQAaQB0AHUAdABlAHMAIABh\n" + + "AGMAYwBlAHAAdABhAG4AYwBlACAAbwBmACAAdABoAGUAIABEAGkAZwBpAEMAZQBy\n" + + "AHQAIABDAFAALwBDAFAAUwAgAGEAbgBkACAAdABoAGUAIABSAGUAbAB5AGkAbgBn\n" + + "ACAAUABhAHIAdAB5ACAAQQBnAHIAZQBlAG0AZQBuAHQAIAB3AGgAaQBjAGgAIABs\n" + + "AGkAbQBpAHQAIABsAGkAYQBiAGkAbABpAHQAeQAgAGEAbgBkACAAYQByAGUAIABp\n" + + "AG4AYwBvAHIAcABvAHIAYQB0AGUAZAAgAGgAZQByAGUAaQBuACAAYgB5ACAAcgBl\n" + + "AGYAZQByAGUAbgBjAGUALjCBggYIKwYBBQUHAQEEdjB0MCQGCCsGAQUFBzABhhho\n" + + "dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTAYIKwYBBQUHMAKGQGh0dHA6Ly9jYWNl\n" + + "cnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRENvZGVTaWduaW5nQ0Et\n" + + "MS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQUFAAOCAQEAPTTQvpOIikXI\n" + + "hTLnNbajaFRR5GhQpTzUNgBfF9VYSlNw/wMjpGsrh5RxaJCip52jbehmTgjMRhft\n" + + "jRYyml44PAVsCcR9uEoDpCZYpI1fHI1R+F8jd1C9rqprbSwwOG4xlg4SmvTHYs6e\n" + + "gBItQ/1p9XY+Sf4Wv1qOuOFL1qvV/5VyR2zdlOQCmKCeMgxt6a/tHLBDiAA67D44\n" + + "/vfdoNJl0CU2It0PO60jdCPFNWIRcxL+OSDqAoePeUC7xQ+JsTEIxuUE8+d6w6fc\n" + + "BV2mYb1flh22t46GLjh4gyo7xw3aL6L0L0jzlTT6IcEw6NIbaPbIKj/npQnHobYj\n" + + "XMuKLxbh7g==\n" + + "-----END CERTIFICATE-----"); + + // Subject: CN=BUSTER ASSISTENCIA TECNICA ELETRONICA LTDA - ME, + // O=BUSTER ASSISTENCIA TECNICA ELETRONICA LTDA - ME, + // L=S?o Paulo, + // ST=S?o Paulo, + // C=BR + // Issuer: CN=DigiCert Assured ID Code Signing CA-1, + // OU=www.digicert.com, + // O=DigiCert Inc, + // C=US + // Serial: 0a:38:9b:95:ee:73:6d:d1:3b:c0:ed:74:3f:d7:4d:2f + add("buster-assistencia-tecnica-electronica-ltda-3FD74D2F", + "-----BEGIN CERTIFICATE-----\n" + + "MIIG4DCCBcigAwIBAgIQCjible5zbdE7wO10P9dNLzANBgkqhkiG9w0BAQUFADBv\n" + + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" + + "d3cuZGlnaWNlcnQuY29tMS4wLAYDVQQDEyVEaWdpQ2VydCBBc3N1cmVkIElEIENv\n" + + "ZGUgU2lnbmluZyBDQS0xMB4XDTEyMTEwOTAwMDAwMFoXDTEzMTExNDEyMDAwMFow\n" + + "gasxCzAJBgNVBAYTAkJSMRMwEQYDVQQIDApTw6NvIFBhdWxvMRMwEQYDVQQHDApT\n" + + "w6NvIFBhdWxvMTgwNgYDVQQKEy9CVVNURVIgQVNTSVNURU5DSUEgVEVDTklDQSBF\n" + + "TEVUUk9OSUNBIExUREEgLSBNRTE4MDYGA1UEAxMvQlVTVEVSIEFTU0lTVEVOQ0lB\n" + + "IFRFQ05JQ0EgRUxFVFJPTklDQSBMVERBIC0gTUUwggEiMA0GCSqGSIb3DQEBAQUA\n" + + "A4IBDwAwggEKAoIBAQDAqNeEs5/B2CTXGjTOkUIdu6jV6qulOZwdw4sefHWYj1UR\n" + + "4z6zPk9kjpUgbnb402RFq88QtfInwddZ/wXn9OxMtDd/3TnC7HrhNS7ga79ZFL2V\n" + + "JnmzKHum2Yvh0q82QEJ9tHBR2X9VdKpUIH08Zs3k6cWWM1H0YX0cxA/HohhesQJW\n" + + "kwJ3urOIJiH/HeByDk8a1NS8safcCxk5vxvW4WvCg43iT09LeHY5Aa8abKw8lqVb\n" + + "0tD5ZSIjdmdj3TT1U37iAHLLRM2DXbxfdbhouUX1c5U1ZHAMA67HwjKiseOiDaHj\n" + + "NUGbC37C+cgbc9VVM/cURD8WvS0Kj6fQv7F2QtJDAgMBAAGjggM5MIIDNTAfBgNV\n" + + "HSMEGDAWgBR7aM4pqsAXvkl64eU/1qf3RY81MjAdBgNVHQ4EFgQU88EXKAyDsh30\n" + + "o9+Gu9a4xUy+FSMwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMD\n" + + "MHMGA1UdHwRsMGowM6AxoC+GLWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9hc3N1\n" + + "cmVkLWNzLTIwMTFhLmNybDAzoDGgL4YtaHR0cDovL2NybDQuZGlnaWNlcnQuY29t\n" + + "L2Fzc3VyZWQtY3MtMjAxMWEuY3JsMIIBxAYDVR0gBIIBuzCCAbcwggGzBglghkgB\n" + + "hv1sAwEwggGkMDoGCCsGAQUFBwIBFi5odHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9z\n" + + "c2wtY3BzLXJlcG9zaXRvcnkuaHRtMIIBZAYIKwYBBQUHAgIwggFWHoIBUgBBAG4A\n" + + "eQAgAHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQByAHQAaQBmAGkAYwBhAHQA\n" + + "ZQAgAGMAbwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBjAGUA\n" + + "IABvAGYAIAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAvAEMAUABTACAA\n" + + "YQBuAGQAIAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0AHkAIABBAGcA\n" + + "cgBlAGUAbQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBhAGIA\n" + + "aQBsAGkAdAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBhAHQA\n" + + "ZQBkACAAaABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBlAHIAZQBuAGMAZQAuMIGC\n" + + "BggrBgEFBQcBAQR2MHQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0\n" + + "LmNvbTBMBggrBgEFBQcwAoZAaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0Rp\n" + + "Z2lDZXJ0QXNzdXJlZElEQ29kZVNpZ25pbmdDQS0xLmNydDAMBgNVHRMBAf8EAjAA\n" + + "MA0GCSqGSIb3DQEBBQUAA4IBAQAei1QmiXepje8OIfo/WonD4MIXgpPr2dfRaquQ\n" + + "A8q63OpTRSveyqdQDCSPpDRF/nvO1Y30yksZvIH1tNBsW5LBdxAKN3lFdBlqBwtE\n" + + "Q3jHc0KVVYRJ0FBaGE/PJHmRajscdAhYIcMPhTga0u0tDK+wOHEq3993dfl6yHjA\n" + + "XHU2iW5pnk75ZoE39zALD5eKXT8ZXrET5c3XUFJKWA+XuGmdmyzqo0Au49PanBv9\n" + + "UlZnabYfqoMArqMS0tGSX4cGgi9/2E+pHG9BX4sFW+ZDumroOA2pxyMWEKjxePEL\n" + + "zCOfhbsRWdMLYepauaNZOIMZXmFwcrIl0TGMkTAtATz+XmZc\n" + + "-----END CERTIFICATE-----"); + } } From 71666c4c5ac79f96e2987e24c9015b0a03659ed0 Mon Sep 17 00:00:00 2001 From: Mike Duigou Date: Tue, 19 Feb 2013 11:56:49 -0800 Subject: [PATCH 049/180] 8004561: Additional functional interfaces, extension methods and name changes Adds additional functional interfaces for primitives and "Bi" (two operand). Adds utility extension methods. Includes some name changes for existing functional interfaces per EG decisions. Reviewed-by: briangoetz, darcy, chegar, dholmes --- .../time/chrono/HijrahDeviationReader.java | 8 +- .../util/concurrent/atomic/AtomicInteger.java | 8 +- .../concurrent/atomic/AtomicIntegerArray.java | 8 +- .../atomic/AtomicIntegerFieldUpdater.java | 8 +- .../util/concurrent/atomic/AtomicLong.java | 8 +- .../concurrent/atomic/AtomicLongArray.java | 8 +- .../atomic/AtomicLongFieldUpdater.java | 8 +- .../concurrent/atomic/AtomicReference.java | 8 +- .../atomic/AtomicReferenceArray.java | 8 +- .../atomic/AtomicReferenceFieldUpdater.java | 8 +- .../concurrent/atomic/DoubleAccumulator.java | 8 +- .../concurrent/atomic/LongAccumulator.java | 8 +- .../util/concurrent/atomic/Striped64.java | 8 +- .../java/util/function/BiConsumer.java | 50 +++++++++ .../java/util/function/BiFunction.java | 51 +++++++++ .../java/util/function/BiPredicate.java | 103 ++++++++++++++++++ .../java/util/function/BinaryOperator.java | 20 +--- .../java/util/function/BooleanSupplier.java | 44 ++++++++ .../function/{Block.java => Consumer.java} | 10 +- .../util/function/DoubleBinaryOperator.java | 13 +-- .../{DoubleBlock.java => DoubleConsumer.java} | 19 ++-- .../java/util/function/DoubleFunction.java | 19 ++-- .../java/util/function/DoublePredicate.java | 101 +++++++++++++++++ .../java/util/function/DoubleSupplier.java | 7 +- .../util/function/DoubleUnaryOperator.java | 8 +- .../classes/java/util/function/Function.java | 10 +- .../java/util/function/IntBinaryOperator.java | 5 +- .../{IntBlock.java => IntConsumer.java} | 19 ++-- .../java/util/function/IntFunction.java | 19 ++-- .../java/util/function/IntPredicate.java | 100 +++++++++++++++++ .../java/util/function/IntSupplier.java | 7 +- .../java/util/function/IntUnaryOperator.java | 9 +- .../util/function/LongBinaryOperator.java | 5 +- .../{LongBlock.java => LongConsumer.java} | 19 ++-- .../java/util/function/LongFunction.java | 19 ++-- .../java/util/function/LongPredicate.java | 100 +++++++++++++++++ .../java/util/function/LongSupplier.java | 9 +- .../java/util/function/LongUnaryOperator.java | 5 +- .../java/util/function/ObjDoubleConsumer.java | 48 ++++++++ .../java/util/function/ObjIntConsumer.java | 48 ++++++++ .../java/util/function/ObjLongConsumer.java | 48 ++++++++ .../classes/java/util/function/Predicate.java | 57 +++++++++- .../util/function/ToDoubleBiFunction.java | 50 +++++++++ .../java/util/function/ToDoubleFunction.java | 46 ++++++++ .../java/util/function/ToIntBiFunction.java | 50 +++++++++ .../java/util/function/ToIntFunction.java | 46 ++++++++ .../java/util/function/ToLongBiFunction.java | 50 +++++++++ .../java/util/function/ToLongFunction.java | 46 ++++++++ .../java/util/function/UnaryOperator.java | 16 +-- .../java/util/function/package-info.java | 69 +++++++++--- .../java/lang/PrimitiveSumMinMaxTest.java | 66 +++++------ 51 files changed, 1290 insertions(+), 225 deletions(-) create mode 100644 jdk/src/share/classes/java/util/function/BiConsumer.java create mode 100644 jdk/src/share/classes/java/util/function/BiFunction.java create mode 100644 jdk/src/share/classes/java/util/function/BiPredicate.java create mode 100644 jdk/src/share/classes/java/util/function/BooleanSupplier.java rename jdk/src/share/classes/java/util/function/{Block.java => Consumer.java} (84%) rename jdk/src/share/classes/java/util/function/{DoubleBlock.java => DoubleConsumer.java} (75%) create mode 100644 jdk/src/share/classes/java/util/function/DoublePredicate.java rename jdk/src/share/classes/java/util/function/{IntBlock.java => IntConsumer.java} (75%) create mode 100644 jdk/src/share/classes/java/util/function/IntPredicate.java rename jdk/src/share/classes/java/util/function/{LongBlock.java => LongConsumer.java} (75%) create mode 100644 jdk/src/share/classes/java/util/function/LongPredicate.java create mode 100644 jdk/src/share/classes/java/util/function/ObjDoubleConsumer.java create mode 100644 jdk/src/share/classes/java/util/function/ObjIntConsumer.java create mode 100644 jdk/src/share/classes/java/util/function/ObjLongConsumer.java create mode 100644 jdk/src/share/classes/java/util/function/ToDoubleBiFunction.java create mode 100644 jdk/src/share/classes/java/util/function/ToDoubleFunction.java create mode 100644 jdk/src/share/classes/java/util/function/ToIntBiFunction.java create mode 100644 jdk/src/share/classes/java/util/function/ToIntFunction.java create mode 100644 jdk/src/share/classes/java/util/function/ToLongBiFunction.java create mode 100644 jdk/src/share/classes/java/util/function/ToLongFunction.java diff --git a/jdk/src/share/classes/java/time/chrono/HijrahDeviationReader.java b/jdk/src/share/classes/java/time/chrono/HijrahDeviationReader.java index 67495d040eb..0c207af62bc 100644 --- a/jdk/src/share/classes/java/time/chrono/HijrahDeviationReader.java +++ b/jdk/src/share/classes/java/time/chrono/HijrahDeviationReader.java @@ -70,7 +70,7 @@ import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoField; import java.util.Arrays; -import java.util.function.Block; +import java.util.function.Consumer; /** * A reader for Hijrah Deviation files. @@ -126,13 +126,13 @@ final class HijrahDeviationReader { * @param typeId the name of the calendar * @param calendarType the calendar type * @return {@code true} if the file was read and each entry accepted by the - * Block; else {@code false} no configuration was done + * Consumer; else {@code false} no configuration was done * * @throws IOException for zip/jar file handling exception. * @throws ParseException if the format of the configuration file is wrong. */ static boolean readDeviation(String typeId, String calendarType, - Block block) throws IOException, ParseException { + Consumer consumer) throws IOException, ParseException { InputStream is = getConfigFileInputStream(typeId); if (is != null) { try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) { @@ -142,7 +142,7 @@ final class HijrahDeviationReader { num++; HijrahChronology.Deviation entry = parseLine(line, num); if (entry != null) { - block.accept(entry); + consumer.accept(entry); } } } diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java index b48ef72dfc9..8fed658a54c 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java @@ -219,7 +219,7 @@ public class AtomicInteger extends Number implements java.io.Serializable { int prev, next; do { prev = get(); - next = updateFunction.operateAsInt(prev); + next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return prev; } @@ -238,7 +238,7 @@ public class AtomicInteger extends Number implements java.io.Serializable { int prev, next; do { prev = get(); - next = updateFunction.operateAsInt(prev); + next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return next; } @@ -262,7 +262,7 @@ public class AtomicInteger extends Number implements java.io.Serializable { int prev, next; do { prev = get(); - next = accumulatorFunction.operateAsInt(prev, x); + next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSet(prev, next)); return prev; } @@ -286,7 +286,7 @@ public class AtomicInteger extends Number implements java.io.Serializable { int prev, next; do { prev = get(); - next = accumulatorFunction.operateAsInt(prev, x); + next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSet(prev, next)); return next; } diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java index 6e4d226ba80..7c259fee06f 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java @@ -263,7 +263,7 @@ public class AtomicIntegerArray implements java.io.Serializable { int prev, next; do { prev = getRaw(offset); - next = updateFunction.operateAsInt(prev); + next = updateFunction.applyAsInt(prev); } while (!compareAndSetRaw(offset, prev, next)); return prev; } @@ -284,7 +284,7 @@ public class AtomicIntegerArray implements java.io.Serializable { int prev, next; do { prev = getRaw(offset); - next = updateFunction.operateAsInt(prev); + next = updateFunction.applyAsInt(prev); } while (!compareAndSetRaw(offset, prev, next)); return next; } @@ -310,7 +310,7 @@ public class AtomicIntegerArray implements java.io.Serializable { int prev, next; do { prev = getRaw(offset); - next = accumulatorFunction.operateAsInt(prev, x); + next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSetRaw(offset, prev, next)); return prev; } @@ -336,7 +336,7 @@ public class AtomicIntegerArray implements java.io.Serializable { int prev, next; do { prev = getRaw(offset); - next = accumulatorFunction.operateAsInt(prev, x); + next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSetRaw(offset, prev, next)); return next; } diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java index fcd5dd05f28..4a8d1df5a63 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java @@ -281,7 +281,7 @@ public abstract class AtomicIntegerFieldUpdater { int prev, next; do { prev = get(obj); - next = updateFunction.operateAsInt(prev); + next = updateFunction.applyAsInt(prev); } while (!compareAndSet(obj, prev, next)); return prev; } @@ -301,7 +301,7 @@ public abstract class AtomicIntegerFieldUpdater { int prev, next; do { prev = get(obj); - next = updateFunction.operateAsInt(prev); + next = updateFunction.applyAsInt(prev); } while (!compareAndSet(obj, prev, next)); return next; } @@ -326,7 +326,7 @@ public abstract class AtomicIntegerFieldUpdater { int prev, next; do { prev = get(obj); - next = accumulatorFunction.operateAsInt(prev, x); + next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSet(obj, prev, next)); return prev; } @@ -351,7 +351,7 @@ public abstract class AtomicIntegerFieldUpdater { int prev, next; do { prev = get(obj); - next = accumulatorFunction.operateAsInt(prev, x); + next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSet(obj, prev, next)); return next; } diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLong.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLong.java index 2e58d29b211..35af7759ac7 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLong.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLong.java @@ -233,7 +233,7 @@ public class AtomicLong extends Number implements java.io.Serializable { long prev, next; do { prev = get(); - next = updateFunction.operateAsLong(prev); + next = updateFunction.applyAsLong(prev); } while (!compareAndSet(prev, next)); return prev; } @@ -252,7 +252,7 @@ public class AtomicLong extends Number implements java.io.Serializable { long prev, next; do { prev = get(); - next = updateFunction.operateAsLong(prev); + next = updateFunction.applyAsLong(prev); } while (!compareAndSet(prev, next)); return next; } @@ -276,7 +276,7 @@ public class AtomicLong extends Number implements java.io.Serializable { long prev, next; do { prev = get(); - next = accumulatorFunction.operateAsLong(prev, x); + next = accumulatorFunction.applyAsLong(prev, x); } while (!compareAndSet(prev, next)); return prev; } @@ -300,7 +300,7 @@ public class AtomicLong extends Number implements java.io.Serializable { long prev, next; do { prev = get(); - next = accumulatorFunction.operateAsLong(prev, x); + next = accumulatorFunction.applyAsLong(prev, x); } while (!compareAndSet(prev, next)); return next; } diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java index 2536a9b8e93..216479abeca 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java @@ -262,7 +262,7 @@ public class AtomicLongArray implements java.io.Serializable { long prev, next; do { prev = getRaw(offset); - next = updateFunction.operateAsLong(prev); + next = updateFunction.applyAsLong(prev); } while (!compareAndSetRaw(offset, prev, next)); return prev; } @@ -283,7 +283,7 @@ public class AtomicLongArray implements java.io.Serializable { long prev, next; do { prev = getRaw(offset); - next = updateFunction.operateAsLong(prev); + next = updateFunction.applyAsLong(prev); } while (!compareAndSetRaw(offset, prev, next)); return next; } @@ -309,7 +309,7 @@ public class AtomicLongArray implements java.io.Serializable { long prev, next; do { prev = getRaw(offset); - next = accumulatorFunction.operateAsLong(prev, x); + next = accumulatorFunction.applyAsLong(prev, x); } while (!compareAndSetRaw(offset, prev, next)); return prev; } @@ -335,7 +335,7 @@ public class AtomicLongArray implements java.io.Serializable { long prev, next; do { prev = getRaw(offset); - next = accumulatorFunction.operateAsLong(prev, x); + next = accumulatorFunction.applyAsLong(prev, x); } while (!compareAndSetRaw(offset, prev, next)); return next; } diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java index a7672263a77..e5c6e8a0044 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java @@ -284,7 +284,7 @@ public abstract class AtomicLongFieldUpdater { long prev, next; do { prev = get(obj); - next = updateFunction.operateAsLong(prev); + next = updateFunction.applyAsLong(prev); } while (!compareAndSet(obj, prev, next)); return prev; } @@ -304,7 +304,7 @@ public abstract class AtomicLongFieldUpdater { long prev, next; do { prev = get(obj); - next = updateFunction.operateAsLong(prev); + next = updateFunction.applyAsLong(prev); } while (!compareAndSet(obj, prev, next)); return next; } @@ -329,7 +329,7 @@ public abstract class AtomicLongFieldUpdater { long prev, next; do { prev = get(obj); - next = accumulatorFunction.operateAsLong(prev, x); + next = accumulatorFunction.applyAsLong(prev, x); } while (!compareAndSet(obj, prev, next)); return prev; } @@ -354,7 +354,7 @@ public abstract class AtomicLongFieldUpdater { long prev, next; do { prev = get(obj); - next = accumulatorFunction.operateAsLong(prev, x); + next = accumulatorFunction.applyAsLong(prev, x); } while (!compareAndSet(obj, prev, next)); return next; } diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReference.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReference.java index 95b88d127e2..ddce0734300 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReference.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReference.java @@ -157,7 +157,7 @@ public class AtomicReference implements java.io.Serializable { V prev, next; do { prev = get(); - next = updateFunction.operate(prev); + next = updateFunction.apply(prev); } while (!compareAndSet(prev, next)); return prev; } @@ -176,7 +176,7 @@ public class AtomicReference implements java.io.Serializable { V prev, next; do { prev = get(); - next = updateFunction.operate(prev); + next = updateFunction.apply(prev); } while (!compareAndSet(prev, next)); return next; } @@ -200,7 +200,7 @@ public class AtomicReference implements java.io.Serializable { V prev, next; do { prev = get(); - next = accumulatorFunction.operate(prev, x); + next = accumulatorFunction.apply(prev, x); } while (!compareAndSet(prev, next)); return prev; } @@ -224,7 +224,7 @@ public class AtomicReference implements java.io.Serializable { V prev, next; do { prev = get(); - next = accumulatorFunction.operate(prev, x); + next = accumulatorFunction.apply(prev, x); } while (!compareAndSet(prev, next)); return next; } diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java index 3e6ce969847..f8787ba1d40 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java @@ -217,7 +217,7 @@ public class AtomicReferenceArray implements java.io.Serializable { E prev, next; do { prev = getRaw(offset); - next = updateFunction.operate(prev); + next = updateFunction.apply(prev); } while (!compareAndSetRaw(offset, prev, next)); return prev; } @@ -238,7 +238,7 @@ public class AtomicReferenceArray implements java.io.Serializable { E prev, next; do { prev = getRaw(offset); - next = updateFunction.operate(prev); + next = updateFunction.apply(prev); } while (!compareAndSetRaw(offset, prev, next)); return next; } @@ -264,7 +264,7 @@ public class AtomicReferenceArray implements java.io.Serializable { E prev, next; do { prev = getRaw(offset); - next = accumulatorFunction.operate(prev, x); + next = accumulatorFunction.apply(prev, x); } while (!compareAndSetRaw(offset, prev, next)); return prev; } @@ -290,7 +290,7 @@ public class AtomicReferenceArray implements java.io.Serializable { E prev, next; do { prev = getRaw(offset); - next = accumulatorFunction.operate(prev, x); + next = accumulatorFunction.apply(prev, x); } while (!compareAndSetRaw(offset, prev, next)); return next; } diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java index a92d914ff77..933e5e4fc92 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java @@ -200,7 +200,7 @@ public abstract class AtomicReferenceFieldUpdater { V prev, next; do { prev = get(obj); - next = updateFunction.operate(prev); + next = updateFunction.apply(prev); } while (!compareAndSet(obj, prev, next)); return prev; } @@ -220,7 +220,7 @@ public abstract class AtomicReferenceFieldUpdater { V prev, next; do { prev = get(obj); - next = updateFunction.operate(prev); + next = updateFunction.apply(prev); } while (!compareAndSet(obj, prev, next)); return next; } @@ -245,7 +245,7 @@ public abstract class AtomicReferenceFieldUpdater { V prev, next; do { prev = get(obj); - next = accumulatorFunction.operate(prev, x); + next = accumulatorFunction.apply(prev, x); } while (!compareAndSet(obj, prev, next)); return prev; } @@ -270,7 +270,7 @@ public abstract class AtomicReferenceFieldUpdater { V prev, next; do { prev = get(obj); - next = accumulatorFunction.operate(prev, x); + next = accumulatorFunction.apply(prev, x); } while (!compareAndSet(obj, prev, next)); return next; } diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/DoubleAccumulator.java b/jdk/src/share/classes/java/util/concurrent/atomic/DoubleAccumulator.java index 17556500af3..277f185f869 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/DoubleAccumulator.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/DoubleAccumulator.java @@ -100,14 +100,14 @@ public class DoubleAccumulator extends Striped64 implements Serializable { Cell[] as; long b, v, r; int m; Cell a; if ((as = cells) != null || (r = Double.doubleToRawLongBits - (function.operateAsDouble + (function.applyAsDouble (Double.longBitsToDouble(b = base), x))) != b && !casBase(b, r)) { boolean uncontended = true; if (as == null || (m = as.length - 1) < 0 || (a = as[getProbe() & m]) == null || !(uncontended = (r = Double.doubleToRawLongBits - (function.operateAsDouble + (function.applyAsDouble (Double.longBitsToDouble(v = a.value), x))) == v || a.cas(v, r))) doubleAccumulate(x, function, uncontended); @@ -129,7 +129,7 @@ public class DoubleAccumulator extends Striped64 implements Serializable { if (as != null) { for (int i = 0; i < as.length; ++i) { if ((a = as[i]) != null) - result = function.operateAsDouble + result = function.applyAsDouble (result, Double.longBitsToDouble(a.value)); } } @@ -174,7 +174,7 @@ public class DoubleAccumulator extends Striped64 implements Serializable { if ((a = as[i]) != null) { double v = Double.longBitsToDouble(a.value); a.value = identity; - result = function.operateAsDouble(result, v); + result = function.applyAsDouble(result, v); } } } diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/LongAccumulator.java b/jdk/src/share/classes/java/util/concurrent/atomic/LongAccumulator.java index 855b09e44de..bfddcd3dcbd 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/LongAccumulator.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/LongAccumulator.java @@ -101,12 +101,12 @@ public class LongAccumulator extends Striped64 implements Serializable { public void accumulate(long x) { Cell[] as; long b, v, r; int m; Cell a; if ((as = cells) != null || - (r = function.operateAsLong(b = base, x)) != b && !casBase(b, r)) { + (r = function.applyAsLong(b = base, x)) != b && !casBase(b, r)) { boolean uncontended = true; if (as == null || (m = as.length - 1) < 0 || (a = as[getProbe() & m]) == null || !(uncontended = - (r = function.operateAsLong(v = a.value, x)) == v || + (r = function.applyAsLong(v = a.value, x)) == v || a.cas(v, r))) longAccumulate(x, function, uncontended); } @@ -127,7 +127,7 @@ public class LongAccumulator extends Striped64 implements Serializable { if (as != null) { for (int i = 0; i < as.length; ++i) { if ((a = as[i]) != null) - result = function.operateAsLong(result, a.value); + result = function.applyAsLong(result, a.value); } } return result; @@ -171,7 +171,7 @@ public class LongAccumulator extends Striped64 implements Serializable { if ((a = as[i]) != null) { long v = a.value; a.value = identity; - result = function.operateAsLong(result, v); + result = function.applyAsLong(result, v); } } } diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/Striped64.java b/jdk/src/share/classes/java/util/concurrent/atomic/Striped64.java index 03969d76dca..708b4c2574f 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/Striped64.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/Striped64.java @@ -253,7 +253,7 @@ abstract class Striped64 extends Number { else if (!wasUncontended) // CAS already known to fail wasUncontended = true; // Continue after rehash else if (a.cas(v = a.value, ((fn == null) ? v + x : - fn.operateAsLong(v, x)))) + fn.applyAsLong(v, x)))) break; else if (n >= NCPU || cells != as) collide = false; // At max size or stale @@ -291,7 +291,7 @@ abstract class Striped64 extends Number { break; } else if (casBase(v = base, ((fn == null) ? v + x : - fn.operateAsLong(v, x)))) + fn.applyAsLong(v, x)))) break; // Fall back on using base } } @@ -344,7 +344,7 @@ abstract class Striped64 extends Number { Double.doubleToRawLongBits (Double.longBitsToDouble(v) + x) : Double.doubleToRawLongBits - (fn.operateAsDouble + (fn.applyAsDouble (Double.longBitsToDouble(v), x))))) break; else if (n >= NCPU || cells != as) @@ -387,7 +387,7 @@ abstract class Striped64 extends Number { Double.doubleToRawLongBits (Double.longBitsToDouble(v) + x) : Double.doubleToRawLongBits - (fn.operateAsDouble + (fn.applyAsDouble (Double.longBitsToDouble(v), x))))) break; // Fall back on using base } diff --git a/jdk/src/share/classes/java/util/function/BiConsumer.java b/jdk/src/share/classes/java/util/function/BiConsumer.java new file mode 100644 index 00000000000..80bdcfa3b15 --- /dev/null +++ b/jdk/src/share/classes/java/util/function/BiConsumer.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + +/** + * An operation which accepts two input arguments and returns no result. This is + * the two-arity specialization of {@link Consumer}. Unlike most other + * functional interfaces, {@code BiConsumer} is expected to operate via + * side-effects. + * + * @param the type of the first argument to the {@code accept} operation. + * @param the type of the second argument to the {@code accept} operation. + * + * @see Consumer + * @since 1.8 + */ +@FunctionalInterface +public interface BiConsumer { + + /** + * Performs operations upon the provided objects which may modify those + * objects and/or external state. + * + * @param t an input object + * @param u an input object + */ + void accept(T t, U u); +} diff --git a/jdk/src/share/classes/java/util/function/BiFunction.java b/jdk/src/share/classes/java/util/function/BiFunction.java new file mode 100644 index 00000000000..85dc2a0a3cb --- /dev/null +++ b/jdk/src/share/classes/java/util/function/BiFunction.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + +/** + * Apply a function to the input arguments, yielding an appropriate result. This + * is the two-arity specialization of {@link Function}. A function may + * variously provide a mapping between types, object instances or keys and + * values or any other form of transformation upon the input. + * + * @param the type of the first argument to the {@code apply} operation. + * @param the type of the second argument to the {@code apply} operation. + * @param the type of results returned by the {@code apply} operation. + * + * @see Function + * @since 1.8 + */ +@FunctionalInterface +public interface BiFunction { + + /** + * Compute the result of applying the function to the input arguments + * + * @param t an input object + * @param u an input object + * @return the function result + */ + R apply(T t, U u); +} diff --git a/jdk/src/share/classes/java/util/function/BiPredicate.java b/jdk/src/share/classes/java/util/function/BiPredicate.java new file mode 100644 index 00000000000..9a8665fa151 --- /dev/null +++ b/jdk/src/share/classes/java/util/function/BiPredicate.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2010, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + +import java.util.Objects; + +/** + * Determines if the input objects match some criteria. This is the two-arity + * specialization of {@link Predicate}. + * + * @param the type of the first argument to {@code test}. + * @param the type of the second argument to {@code test}. + * + * @see Predicate + * @since 1.8 + */ +@FunctionalInterface +public interface BiPredicate { + + /** + * Return {@code true} if the inputs match some criteria. + * + * @param t an input object. + * @param u an input object. + * @return {@code true} if the inputs match some criteria. + */ + boolean test(T t, U u); + + /** + * Returns a predicate which evaluates to {@code true} only if this + * predicate and the provided predicate both evaluate to {@code true}. If + * this predicate returns {@code false} then the remaining predicate is not + * evaluated. + * + * @param p a predicate which will be logically-ANDed with this predicate. + * @return a new predicate which returns {@code true} only if both + * predicates return {@code true}. + */ + public default BiPredicate and(BiPredicate p) { + Objects.requireNonNull(p); + return (T t, U u) -> test(t, u) && p.test(t, u); + } + + /** + * Returns a predicate which negates the result of this predicate. + * + * @return a new predicate who's result is always the opposite of this + * predicate. + */ + public default BiPredicate negate() { + return (T t, U u) -> !test(t, u); + } + + /** + * Returns a predicate which evaluates to {@code true} if either this + * predicate or the provided predicate evaluates to {@code true}. If this + * predicate returns {@code true} then the remaining predicate is not + * evaluated. + * + * @param p a predicate which will be logically-ORed with this predicate. + * @return a new predicate which returns {@code true} if either predicate + * returns {@code true}. + */ + public default BiPredicate or(BiPredicate p) { + Objects.requireNonNull(p); + return (T t, U u) -> test(t, u) || p.test(t, u); + } + + /** + * Returns a predicate that evaluates to {@code true} if both or neither of + * the component predicates evaluate to {@code true}. + * + * @param p a predicate which will be logically-XORed with this predicate. + * @return a predicate that evaluates to {@code true} if both or neither of + * the component predicates evaluate to {@code true}. + */ + public default BiPredicate xor(BiPredicate p) { + Objects.requireNonNull(p); + return (T t, U u) -> test(t, u) ^ p.test(t, u); + } +} diff --git a/jdk/src/share/classes/java/util/function/BinaryOperator.java b/jdk/src/share/classes/java/util/function/BinaryOperator.java index 2e9050e59f2..5f1d5a41d83 100644 --- a/jdk/src/share/classes/java/util/function/BinaryOperator.java +++ b/jdk/src/share/classes/java/util/function/BinaryOperator.java @@ -25,24 +25,14 @@ package java.util.function; /** - * An operation upon two operands yielding a result. The operands and the result - * are all of the same type. + * An operation upon two operands yielding a result. This is a specialization of + * {@code BiFunction} where the operands and the result are all of the same type. * - * @param the type of operands to {@code operate} and of the result + * @param the type of operands to {@code apply} and of the result * + * @see BiFunction. * @since 1.8 */ @FunctionalInterface -public interface BinaryOperator { - - /** - * Returns the result of the operation upon the operands. - * The operands are named {@code left} and {@code right} for operations - * where the order of operands matters. - * - * @param left the left operand - * @param right the right operand - * @return the result of the operation - */ - public T operate(T left, T right); +public interface BinaryOperator extends BiFunction { } diff --git a/jdk/src/share/classes/java/util/function/BooleanSupplier.java b/jdk/src/share/classes/java/util/function/BooleanSupplier.java new file mode 100644 index 00000000000..f145b621156 --- /dev/null +++ b/jdk/src/share/classes/java/util/function/BooleanSupplier.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + + +/** + * A supplier of {@code boolean} values. This is the {@code boolean}-providing + * primitive specialization of {@link Supplier}. + * + * @see Supplier + * @since 1.8 + */ +@FunctionalInterface +public interface BooleanSupplier { + + /** + * Returns a {@code boolean} value. + * + * @return a {@code boolean} value + */ + public boolean getAsBoolean(); +} diff --git a/jdk/src/share/classes/java/util/function/Block.java b/jdk/src/share/classes/java/util/function/Consumer.java similarity index 84% rename from jdk/src/share/classes/java/util/function/Block.java rename to jdk/src/share/classes/java/util/function/Consumer.java index c41e9a45a5a..e9cb175d59b 100644 --- a/jdk/src/share/classes/java/util/function/Block.java +++ b/jdk/src/share/classes/java/util/function/Consumer.java @@ -25,19 +25,19 @@ package java.util.function; /** - * An operation upon an input object. The operation may modify that object or - * external state (other objects). + * An operation which accepts a single input argument and returns no result. + * Unlike most other functional interfaces, {@code Consumer} is expected to + * operate via side-effects. * * @param The type of input objects to {@code accept} * * @since 1.8 */ @FunctionalInterface -public interface Block { +public interface Consumer { /** - * Use the input object in operations which may modify that object or - * external state (other objects). + * Accept an input value. * * @param t the input object */ diff --git a/jdk/src/share/classes/java/util/function/DoubleBinaryOperator.java b/jdk/src/share/classes/java/util/function/DoubleBinaryOperator.java index f63403bb37e..de9855bd4d1 100644 --- a/jdk/src/share/classes/java/util/function/DoubleBinaryOperator.java +++ b/jdk/src/share/classes/java/util/function/DoubleBinaryOperator.java @@ -26,23 +26,22 @@ package java.util.function; /** * An operation on two {@code double} operands yielding a {@code double} result. + * This is the primitive type specialization of {@link BinaryOperator} for + * {@code double}. * + * @see BinaryOperator * @since 1.8 */ @FunctionalInterface -public interface DoubleBinaryOperator /* extends BinaryOperator */ { -// -// @Override -// public default Double operate(Double left, Double right) { return operateAsDouble((double) left, (double) right); } - +public interface DoubleBinaryOperator { /** * Returns the {@code double} result of the operation upon the * {@code double} operands. The parameters are named {@code left} and * {@code right} for operations where the order of parameters matters. * * @param left the left operand value - * @param right the right operand value + * @param right the right operand value * @return the result of the operation */ - public double operateAsDouble(double left, double right); + public double applyAsDouble(double left, double right); } diff --git a/jdk/src/share/classes/java/util/function/DoubleBlock.java b/jdk/src/share/classes/java/util/function/DoubleConsumer.java similarity index 75% rename from jdk/src/share/classes/java/util/function/DoubleBlock.java rename to jdk/src/share/classes/java/util/function/DoubleConsumer.java index ae000841ae1..2ea35749737 100644 --- a/jdk/src/share/classes/java/util/function/DoubleBlock.java +++ b/jdk/src/share/classes/java/util/function/DoubleConsumer.java @@ -25,22 +25,21 @@ package java.util.function; /** - * An operation upon a {@code double} input value. The operation may modify - * external state. - * - *

    This is the primitive type specialization of {@link Block} for - * {@code double} and also may be used as a {@code Block}. + * An operation which accepts a single double argument and returns no result. + * This is the primitive type specialization of {@link Consumer} for + * {@code double}. Unlike most other functional interfaces, + * {@code DoubleConsumer} is expected to operate via side-effects. * + * @see Consumer * @since 1.8 */ @FunctionalInterface -public interface DoubleBlock { +public interface DoubleConsumer { /** - * Use the {@code double} input value in an operation which may modify - * external state. + * Accept an input value. * - * @param t the input value + * @param value the input value */ - public void accept(double t); + public void accept(double value); } diff --git a/jdk/src/share/classes/java/util/function/DoubleFunction.java b/jdk/src/share/classes/java/util/function/DoubleFunction.java index d9c522c8e94..fcc6bb9dfde 100644 --- a/jdk/src/share/classes/java/util/function/DoubleFunction.java +++ b/jdk/src/share/classes/java/util/function/DoubleFunction.java @@ -25,22 +25,23 @@ package java.util.function; /** - * Apply a function to the input object yielding an appropriate {@code double} - * value; this is the {@code double}-bearing specialization for {@link Function}. + * Apply a function to the double-valued input argument, yielding an appropriate + * result. This is the {@code double}-consuming primitive specialization for + * {@link Function}. * - * @param the type of input objects to the function + * @param the type of output objects from the function * + * @see Function * @since 1.8 */ @FunctionalInterface -public interface DoubleFunction { +public interface DoubleFunction { /** - * Apply a function to the input object yielding an appropriate - * {@code double} value. + * Compute the result of applying the function to the input argument * - * @param t the input object - * @return the function result value + * @param value the input value + * @return the function result */ - public double applyAsDouble(T t); + public R apply(double value); } diff --git a/jdk/src/share/classes/java/util/function/DoublePredicate.java b/jdk/src/share/classes/java/util/function/DoublePredicate.java new file mode 100644 index 00000000000..e132f9b74d2 --- /dev/null +++ b/jdk/src/share/classes/java/util/function/DoublePredicate.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2010, 2013 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + +import java.util.Objects; + +/** + * Determines if the {@code double} input value matches some criteria. This is + * the {@code double}-consuming primitive type specialization of + * {@link Predicate}. + * + * @see Predicate + * @since 1.8 + */ +@FunctionalInterface +public interface DoublePredicate { + + /** + * Returns {@code true} if the input value matches some criteria. + * + * @param value the value to be tested. + * @return {@code true} if the input value matches some criteria, otherwise + * {@code false}. + */ + public boolean test(double value); + + /** + * Returns a predicate which evaluates to {@code true} only if this + * predicate and the provided predicate both evaluate to {@code true}. If + * this predicate returns {@code false} then the remaining predicate is not + * evaluated. + * + * @param p a predicate which will be logically-ANDed with this predicate. + * @return a new predicate which returns {@code true} only if both + * predicates return {@code true}. + */ + public default DoublePredicate and(DoublePredicate p) { + Objects.requireNonNull(p); + return (value) -> test(value) && p.test(value); + } + + /** + * Returns a predicate which negates the result of this predicate. + * + * @return a new predicate who's result is always the opposite of this + * predicate. + */ + public default DoublePredicate negate() { + return (value) -> !test(value); + } + + /** + * Returns a predicate which evaluates to {@code true} if either this + * predicate or the provided predicate evaluates to {@code true}. If this + * predicate returns {@code true} then the remaining predicate is not + * evaluated. + * + * @param p a predicate which will be logically-ANDed with this predicate. + * @return a new predicate which returns {@code true} if either predicate + * returns {@code true}. + */ + public default DoublePredicate or(DoublePredicate p) { + Objects.requireNonNull(p); + return (value) -> test(value) || p.test(value); + } + + /** + * Returns a predicate that evaluates to {@code true} if both or neither of + * the component predicates evaluate to {@code true}. + * + * @param p a predicate which will be logically-XORed with this predicate. + * @return a predicate that evaluates to {@code true} if all or none of the + * component predicates evaluate to {@code true}. + */ + public default DoublePredicate xor(DoublePredicate p) { + Objects.requireNonNull(p); + return (value) -> test(value) ^ p.test(value); + } +} diff --git a/jdk/src/share/classes/java/util/function/DoubleSupplier.java b/jdk/src/share/classes/java/util/function/DoubleSupplier.java index 19d75353045..9f9ab4e9f5a 100644 --- a/jdk/src/share/classes/java/util/function/DoubleSupplier.java +++ b/jdk/src/share/classes/java/util/function/DoubleSupplier.java @@ -25,11 +25,10 @@ package java.util.function; /** - * A supplier of {@code double} values. - * - *

    This is the primitive type specialization of {@link Supplier} for - * {@code double} and also may be used as a {@code Supplier}. + * A supplier of {@code double} values. This is the {@code double}-providing + * primitive specialization of {@link Supplier}. * + * @see Supplier * @since 1.8 */ @FunctionalInterface diff --git a/jdk/src/share/classes/java/util/function/DoubleUnaryOperator.java b/jdk/src/share/classes/java/util/function/DoubleUnaryOperator.java index 3843f8bc7ee..e9be79f5bb9 100644 --- a/jdk/src/share/classes/java/util/function/DoubleUnaryOperator.java +++ b/jdk/src/share/classes/java/util/function/DoubleUnaryOperator.java @@ -25,9 +25,11 @@ package java.util.function; /** - * An operation on a single {@code double} operand yielding a {@code double} - * result. + * An operation on a {@code double} operand yielding a {@code double} + * result. This is the primitive type specialization of {@link UnaryOperator} + * for {@code double}. * + * @see UnaryOperator * @since 1.8 */ @FunctionalInterface @@ -40,5 +42,5 @@ public interface DoubleUnaryOperator { * @param operand the operand value * @return the operation result value */ - public double operateAsDouble(double operand); + public double applyAsDouble(double operand); } diff --git a/jdk/src/share/classes/java/util/function/Function.java b/jdk/src/share/classes/java/util/function/Function.java index 82bae01701d..ff4b538c1a9 100644 --- a/jdk/src/share/classes/java/util/function/Function.java +++ b/jdk/src/share/classes/java/util/function/Function.java @@ -24,14 +24,14 @@ */ package java.util.function; + /** - * Apply a function to the input object yielding an appropriate result object. A + * Apply a function to the input argument, yielding an appropriate result. A * function may variously provide a mapping between types, object instances or * keys and values or any other form of transformation upon the input. * - * @param the type of input objects to the {@code apply} operation - * @param the type of result objects from the {@code apply} operation. May - * be the same type as {@code }. + * @param the type of the input to the {@code apply} operation. + * @param the type of the result of the {@code apply} operation. * * @since 1.8 */ @@ -39,7 +39,7 @@ package java.util.function; public interface Function { /** - * Yield an appropriate result object for the input object. + * Compute the result of applying the function to the input argument * * @param t the input object * @return the function result diff --git a/jdk/src/share/classes/java/util/function/IntBinaryOperator.java b/jdk/src/share/classes/java/util/function/IntBinaryOperator.java index e25c2ba101f..f139118e3f1 100644 --- a/jdk/src/share/classes/java/util/function/IntBinaryOperator.java +++ b/jdk/src/share/classes/java/util/function/IntBinaryOperator.java @@ -26,7 +26,10 @@ package java.util.function; /** * An operation on two {@code int} operands yielding an {@code int} result. + * This is the primitive type specialization of {@link BinaryOperator} for + * {@code int}. * + * @see BinaryOperator * @since 1.8 */ @FunctionalInterface @@ -41,5 +44,5 @@ public interface IntBinaryOperator { * @param right the right operand value * @return the result of the operation */ - public int operateAsInt(int left, int right); + public int applyAsInt(int left, int right); } diff --git a/jdk/src/share/classes/java/util/function/IntBlock.java b/jdk/src/share/classes/java/util/function/IntConsumer.java similarity index 75% rename from jdk/src/share/classes/java/util/function/IntBlock.java rename to jdk/src/share/classes/java/util/function/IntConsumer.java index 33cdbe79f51..28a6ec46e2f 100644 --- a/jdk/src/share/classes/java/util/function/IntBlock.java +++ b/jdk/src/share/classes/java/util/function/IntConsumer.java @@ -25,22 +25,21 @@ package java.util.function; /** - * An operation upon an {@code int} input value. The operation may modify - * external state. - * - *

    This is the primitive type specialization of {@link Block} for - * {@code int} and also may be used as a {@code Block}. + * An operation which accepts a single integer argument and returns no result. + * This is the primitive type specialization of {@link Consumer} for {@code int}. + * Unlike most other functional interfaces, {@code IntConsumer} is expected to + * operate via side-effects. * + * @see Consumer * @since 1.8 */ @FunctionalInterface -public interface IntBlock { +public interface IntConsumer { /** - * Use the {@code int} input value in an operation which may modify external - * state. + * Accept an input value. * - * @param t the input value + * @param value the input value */ - public void accept(int t); + public void accept(int value); } diff --git a/jdk/src/share/classes/java/util/function/IntFunction.java b/jdk/src/share/classes/java/util/function/IntFunction.java index 6e1418533fe..b5faecc0ea7 100644 --- a/jdk/src/share/classes/java/util/function/IntFunction.java +++ b/jdk/src/share/classes/java/util/function/IntFunction.java @@ -25,22 +25,23 @@ package java.util.function; /** - * Apply a function to the input object yielding an appropriate {@code int} - * value; this is the {@code int}-bearing specialization for {@link Function}. + * Apply a function to the integer-valued input argument, yielding an + * appropriate result. This is the {@code int}-consuming primitive + * specialization for {@link Function}. * - * @param the type of input objects to the function + * @param the type of output objects from the function * + * @see Function * @since 1.8 */ @FunctionalInterface -public interface IntFunction { +public interface IntFunction { /** - * Apply a function to the input object yielding an appropriate {@code int} - * value. + * Compute the result of applying the function to the input argument * - * @param t the input object - * @return the function result value + * @param value the input value + * @return the function result */ - public int applyAsInt(T t); + public R apply(int value); } diff --git a/jdk/src/share/classes/java/util/function/IntPredicate.java b/jdk/src/share/classes/java/util/function/IntPredicate.java new file mode 100644 index 00000000000..17cc49c754e --- /dev/null +++ b/jdk/src/share/classes/java/util/function/IntPredicate.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2010, 2013 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + +import java.util.Objects; + +/** + * Determines if the {@code int} input value matches some criteria. This is the + * {@code int}-consuming primitive type specialization of {@link Predicate}. + * + * @see Predicate + * @since 1.8 + */ +@FunctionalInterface +public interface IntPredicate { + + /** + * Returns {@code true} if the input value matches some criteria. + * + * @param value the value to be tested. + * @return {@code true} if the input value matches some criteria, otherwise + * {@code false} + */ + public boolean test(int value); + + /** + * Returns a predicate which evaluates to {@code true} only if this + * predicate and the provided predicate both evaluate to {@code true}. If + * this predicate returns {@code false} then the remaining predicate is not + * evaluated. + * + * @param p a predicate which will be logically-ANDed with this predicate. + * @return a new predicate which returns {@code true} only if both + * predicates return {@code true}. + */ + public default IntPredicate and(IntPredicate p) { + Objects.requireNonNull(p); + return (value) -> test(value) && p.test(value); + } + + /** + * Returns a predicate which negates the result of this predicate. + * + * @return a new predicate who's result is always the opposite of this + * predicate. + */ + public default IntPredicate negate() { + return (value) -> !test(value); + } + + /** + * Returns a predicate which evaluates to {@code true} if either this + * predicate or the provided predicate evaluates to {@code true}. If this + * predicate returns {@code true} then the remaining predicate is not + * evaluated. + * + * @param p a predicate which will be logically-ORed with this predicate. + * @return a new predicate which returns {@code true} if either predicate + * returns {@code true}. + */ + public default IntPredicate or(IntPredicate p) { + Objects.requireNonNull(p); + return (value) -> test(value) || p.test(value); + } + + /** + * Returns a predicate that evaluates to {@code true} if both or neither of + * the component predicates evaluate to {@code true}. + * + * @param p a predicate which will be logically-XORed with this predicate. + * @return a predicate that evaluates to {@code true} if both or neither of + * the component predicates evaluate to {@code true} + */ + public default IntPredicate xor(IntPredicate p) { + Objects.requireNonNull(p); + return (value) -> test(value) ^ p.test(value); + } +} diff --git a/jdk/src/share/classes/java/util/function/IntSupplier.java b/jdk/src/share/classes/java/util/function/IntSupplier.java index c73fc84e3be..d857b7882b4 100644 --- a/jdk/src/share/classes/java/util/function/IntSupplier.java +++ b/jdk/src/share/classes/java/util/function/IntSupplier.java @@ -25,11 +25,10 @@ package java.util.function; /** - * A supplier of {@code int} values. - * - *

    This is the primitive type specialization of {@link Supplier} for - * {@code int} and also may be used as a {@code Supplier}. + * A supplier of {@code int} values. This is the {@code int}-providing + * primitive specialization of {@link Supplier}. * + * @see Supplier * @since 1.8 */ @FunctionalInterface diff --git a/jdk/src/share/classes/java/util/function/IntUnaryOperator.java b/jdk/src/share/classes/java/util/function/IntUnaryOperator.java index 2c429951c28..a3b868dff54 100644 --- a/jdk/src/share/classes/java/util/function/IntUnaryOperator.java +++ b/jdk/src/share/classes/java/util/function/IntUnaryOperator.java @@ -26,18 +26,21 @@ package java.util.function; /** * An operation on a single {@code int} operand yielding an {@code int} result. + * This is the primitive type specialization of {@link UnaryOperator} for + * {@code int}. * + * @see UnaryOperator * @since 1.8 */ @FunctionalInterface public interface IntUnaryOperator { /** - * Returns the {@code int} result of the operation upon the {@code int} - * operand. + * Returns the {@code int} value result of the operation upon the + * {@code int} operand. * * @param operand the operand value * @return the operation result value */ - public int operateAsInt(int operand); + public int applyAsInt(int operand); } diff --git a/jdk/src/share/classes/java/util/function/LongBinaryOperator.java b/jdk/src/share/classes/java/util/function/LongBinaryOperator.java index f767c92a355..d08271d30b1 100644 --- a/jdk/src/share/classes/java/util/function/LongBinaryOperator.java +++ b/jdk/src/share/classes/java/util/function/LongBinaryOperator.java @@ -26,7 +26,10 @@ package java.util.function; /** * An operation on two {@code long} operands yielding a {@code long} result. + * This is the primitive type specialization of {@link BinaryOperator} for + * {@code long}. * + * @see BinaryOperator * @since 1.8 */ @FunctionalInterface @@ -41,5 +44,5 @@ public interface LongBinaryOperator { * @param right the right operand value * @return the result of the operation */ - public long operateAsLong(long left, long right); + public long applyAsLong(long left, long right); } diff --git a/jdk/src/share/classes/java/util/function/LongBlock.java b/jdk/src/share/classes/java/util/function/LongConsumer.java similarity index 75% rename from jdk/src/share/classes/java/util/function/LongBlock.java rename to jdk/src/share/classes/java/util/function/LongConsumer.java index 71606ecf9ed..072c0972a60 100644 --- a/jdk/src/share/classes/java/util/function/LongBlock.java +++ b/jdk/src/share/classes/java/util/function/LongConsumer.java @@ -25,22 +25,21 @@ package java.util.function; /** - * An operation upon a {@code long} input value. The operation may modify - * external state. - * - *

    This is the primitive type specialization of {@link Block} for - * {@code long} and also may be used as a {@code Block}. + * An operation which accepts a single long argument and returns no result. + * This is the {@code long}-consuming primitive type specialization of + * {@link Consumer}. Unlike most other functional interfaces, {@code LongConsumer} + * is expected to operate via side-effects. * + * @see Consumer * @since 1.8 */ @FunctionalInterface -public interface LongBlock { +public interface LongConsumer { /** - * Use the {@code long} input value in an operation which may modify - * external state. + * Accept an input value. * - * @param t the input value + * @param value the input value */ - public void accept(long t); + public void accept(long value); } diff --git a/jdk/src/share/classes/java/util/function/LongFunction.java b/jdk/src/share/classes/java/util/function/LongFunction.java index 61c4fbf6475..924eb43be17 100644 --- a/jdk/src/share/classes/java/util/function/LongFunction.java +++ b/jdk/src/share/classes/java/util/function/LongFunction.java @@ -25,22 +25,23 @@ package java.util.function; /** - * Apply a function to the input object yielding an appropriate {@code long} - * value; this is the {@code long}-bearing specialization for {@link Function}. + * Apply a function to the long-valued input argument, yielding an appropriate + * result. This is the {@code long}-consuming primitive specialization for + * {@link Function}. * - * @param the type of input objects to the function + * @param the type of output objects from the function * + * @see Function * @since 1.8 */ @FunctionalInterface -public interface LongFunction { +public interface LongFunction { /** - * Apply a function to the input object yielding an appropriate {@code long} - * value. + * Compute the result of applying the function to the input argument * - * @param t the input object - * @return the function result value + * @param value the input value + * @return the function result */ - public long applyAsLong(T t); + public R apply(long value); } diff --git a/jdk/src/share/classes/java/util/function/LongPredicate.java b/jdk/src/share/classes/java/util/function/LongPredicate.java new file mode 100644 index 00000000000..ca542a41246 --- /dev/null +++ b/jdk/src/share/classes/java/util/function/LongPredicate.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2010, 2013 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + +import java.util.Objects; + +/** + * Determines if the {@code long} input value matches some criteria. This is the + * {@code long}-consuming primitive type specialization of {@link Predicate}. + * + * @see Predicate + * @since 1.8 + */ +@FunctionalInterface +public interface LongPredicate { + + /** + * Returns {@code true} if the input value matches some criteria. + * + * @param value the value to be tested. + * @return {@code true} if the input value matches some criteria, otherwise + * {@code false}. + */ + public boolean test(long value); + + /** + * Returns a predicate which evaluates to {@code true} only if this + * predicate and the provided predicate both evaluate to {@code true}. If + * this predicate returns {@code false} then the remaining predicate is not + * evaluated. + * + * @param p a predicate which will be logically-ANDed with this predicate. + * @return a new predicate which returns {@code true} only if both + * predicates return {@code true}. + */ + public default LongPredicate and(LongPredicate p) { + Objects.requireNonNull(p); + return (value) -> test(value) && p.test(value); + } + + /** + * Returns a predicate which negates the result of this predicate. + * + * @return a new predicate who's result is always the opposite of this + * predicate. + */ + public default LongPredicate negate() { + return (value) -> !test(value); + } + + /** + * Returns a predicate which evaluates to {@code true} if either this + * predicate or the provided predicate evaluates to {@code true}. If this + * predicate returns {@code true} then the remaining predicate is not + * evaluated. + * + * @param p a predicate which will be logically-ORed with this predicate. + * @return a new predicate which returns {@code true} if either predicate + * returns {@code true}. + */ + public default LongPredicate or(LongPredicate p) { + Objects.requireNonNull(p); + return (value) -> test(value) || p.test(value); + } + + /** + * Returns a predicate that evaluates to {@code true} if both or neither of + * the component predicates evaluate to {@code true}. + * + * @param p a predicate which will be logically-XORed with this predicate. + * @return a predicate that evaluates to {@code true} if both or neither of + * the component predicates evaluate to {@code true}. + */ + public default LongPredicate xor(LongPredicate p) { + Objects.requireNonNull(p); + return (value) -> test(value) ^ p.test(value); + } +} diff --git a/jdk/src/share/classes/java/util/function/LongSupplier.java b/jdk/src/share/classes/java/util/function/LongSupplier.java index f56ad7df282..2d5a3def105 100644 --- a/jdk/src/share/classes/java/util/function/LongSupplier.java +++ b/jdk/src/share/classes/java/util/function/LongSupplier.java @@ -25,11 +25,10 @@ package java.util.function; /** - * A supplier of {@code long} values. - * - *

    This is the primitive type specialization of {@link Supplier} for - * {@code long} and also may be used as a {@code Supplier}. + * A supplier of {@code long} values. This is the {@code long}-providing + * primitive specialization of {@link Supplier}. * + * @see Supplier * @since 1.8 */ @FunctionalInterface @@ -38,7 +37,7 @@ public interface LongSupplier { /** * Returns a {@code long} value. * - * @return a {@code long} value. + * @return a {@code long} value */ public long getAsLong(); } diff --git a/jdk/src/share/classes/java/util/function/LongUnaryOperator.java b/jdk/src/share/classes/java/util/function/LongUnaryOperator.java index f27ddf5a81a..3632e2a118a 100644 --- a/jdk/src/share/classes/java/util/function/LongUnaryOperator.java +++ b/jdk/src/share/classes/java/util/function/LongUnaryOperator.java @@ -26,7 +26,10 @@ package java.util.function; /** * An operation on a single {@code long} operand yielding a {@code long} result. + * This is the primitive type specialization of {@link UnaryOperator} for + * {@code long}. * + * @see UnaryOperator * @since 1.8 */ @FunctionalInterface @@ -39,5 +42,5 @@ public interface LongUnaryOperator { * @param operand the operand value * @return the operation result value */ - public long operateAsLong(long operand); + public long applyAsLong(long operand); } diff --git a/jdk/src/share/classes/java/util/function/ObjDoubleConsumer.java b/jdk/src/share/classes/java/util/function/ObjDoubleConsumer.java new file mode 100644 index 00000000000..24e4c29327c --- /dev/null +++ b/jdk/src/share/classes/java/util/function/ObjDoubleConsumer.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + +/** + * An operation which accepts an object reference and a double, and returns no + * result. This is the {@code (reference, double)} specialization of + * {@link BiConsumer}. Unlike most other functional interfaces, + * {@code ObjDoubleConsumer} is expected to operate via side-effects. + * + * @param Type of reference argument to {@code accept()}. + * + * @see BiConsumer + * @since 1.8 + */ +@FunctionalInterface +public interface ObjDoubleConsumer { + + /** + * Accept a set of input values. + * + * @param t an input object + * @param value an input value + */ + public void accept(T t, double value); +} diff --git a/jdk/src/share/classes/java/util/function/ObjIntConsumer.java b/jdk/src/share/classes/java/util/function/ObjIntConsumer.java new file mode 100644 index 00000000000..fa63af5cff6 --- /dev/null +++ b/jdk/src/share/classes/java/util/function/ObjIntConsumer.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012, 2013 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + +/** + * An operation which accepts an object reference and an int, and returns no + * result. This is the {@code (reference, int)} specialization of + * {@link BiConsumer}. Unlike most other functional interfaces, + * {@code ObjIntConsumer} is expected to operate via side-effects. + * + * @param Type of reference argument to {@code accept()}. + * + * @see BiConsumer + * @since 1.8 + */ +@FunctionalInterface +public interface ObjIntConsumer { + + /** + * Accept a set of input values. + * + * @param t an input object + * @param value an input value + */ + public void accept(T t, int value); +} diff --git a/jdk/src/share/classes/java/util/function/ObjLongConsumer.java b/jdk/src/share/classes/java/util/function/ObjLongConsumer.java new file mode 100644 index 00000000000..c2f19fba741 --- /dev/null +++ b/jdk/src/share/classes/java/util/function/ObjLongConsumer.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + +/** + * An operation which accepts an object reference and a long, and returns no + * result. This is the {@code (reference, long)} specialization of + * {@link BiConsumer}. Unlike most other functional interfaces, + * {@code ObjLongConsumer} is expected to operate via side-effects. + * + * @param Type of reference argument to {@code accept()}. + * + * @see BiConsumer + * @since 1.8 + */ +@FunctionalInterface +public interface ObjLongConsumer { + + /** + * Accept a set of input values. + * + * @param t an input object + * @param value an input value + */ + public void accept(T t, long value); +} diff --git a/jdk/src/share/classes/java/util/function/Predicate.java b/jdk/src/share/classes/java/util/function/Predicate.java index 9b440787485..627771e26af 100644 --- a/jdk/src/share/classes/java/util/function/Predicate.java +++ b/jdk/src/share/classes/java/util/function/Predicate.java @@ -24,10 +24,12 @@ */ package java.util.function; +import java.util.Objects; + /** * Determines if the input object matches some criteria. * - * @param the type of input objects to {@code test} + * @param the type of argument to {@code test} * * @since 1.8 */ @@ -42,4 +44,57 @@ public interface Predicate { * {@code false} */ public boolean test(T t); + + /** + * Returns a predicate which evaluates to {@code true} only if this + * predicate and the provided predicate both evaluate to {@code true}. If + * this predicate returns {@code false} then the remaining predicate is not + * evaluated. + * + * @param p a predicate which will be logically-ANDed with this predicate. + * @return a new predicate which returns {@code true} only if both + * predicates return {@code true}. + */ + public default Predicate and(Predicate p) { + Objects.requireNonNull(p); + return (t) -> test(t) && p.test(t); + } + + /** + * Returns a predicate which negates the result of this predicate. + * + * @return a new predicate who's result is always the opposite of this + * predicate. + */ + public default Predicate negate() { + return (t) -> !test(t); + } + + /** + * Returns a predicate which evaluates to {@code true} if either this + * predicate or the provided predicate evaluates to {@code true}. If this + * predicate returns {@code true} then the remaining predicate is not + * evaluated. + * + * @param p a predicate which will be logically-ORed with this predicate. + * @return a new predicate which returns {@code true} if either predicate + * returns {@code true}. + */ + public default Predicate or(Predicate p) { + Objects.requireNonNull(p); + return (t) -> test(t) || p.test(t); + } + + /** + * Returns a predicate that evaluates to {@code true} if both or neither of + * the component predicates evaluate to {@code true}. + * + * @param p a predicate which will be logically-XORed with this predicte. + * @return a predicate that evaluates to {@code true} if both or neither of + * the component predicates evaluate to {@code true}. + */ + public default Predicate xor(Predicate p) { + Objects.requireNonNull(p); + return (t) -> test(t) ^ p.test(t); + } } diff --git a/jdk/src/share/classes/java/util/function/ToDoubleBiFunction.java b/jdk/src/share/classes/java/util/function/ToDoubleBiFunction.java new file mode 100644 index 00000000000..df299aa58d7 --- /dev/null +++ b/jdk/src/share/classes/java/util/function/ToDoubleBiFunction.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, 2013 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + +/** + * Apply a function to the input arguments, yielding an appropriate result. + * This is the {@code double}-bearing specialization for {@link BiFunction}. + * + * @param the type of the first argument to the {@code applyAsDouble} + * operation. + * @param the type of the second argument to the {@code applyAsDouble} + * operation. + * + * @see BiFunction. + * @since 1.8 + */ +@FunctionalInterface +public interface ToDoubleBiFunction { + + /** + * Compute the result of applying the function to the input arguments + * + * @param t an input object + * @param u an input object + * @return the function result value + */ + public double applyAsDouble(T t, U u); +} diff --git a/jdk/src/share/classes/java/util/function/ToDoubleFunction.java b/jdk/src/share/classes/java/util/function/ToDoubleFunction.java new file mode 100644 index 00000000000..87f19fce41e --- /dev/null +++ b/jdk/src/share/classes/java/util/function/ToDoubleFunction.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + +/** + * Apply a function to the input argument, yielding an appropriate result. + * This is the {@code double}-bearing specialization for {@link Function}. + * + * @param the type of input objects to the function + * + * @see Function + * @since 1.8 + */ +@FunctionalInterface +public interface ToDoubleFunction { + + /** + * Compute the result of applying the function to the input argument + * + * @param t the input object + * @return the function result value + */ + public double applyAsDouble(T t); +} diff --git a/jdk/src/share/classes/java/util/function/ToIntBiFunction.java b/jdk/src/share/classes/java/util/function/ToIntBiFunction.java new file mode 100644 index 00000000000..d7c727fa31c --- /dev/null +++ b/jdk/src/share/classes/java/util/function/ToIntBiFunction.java @@ -0,0 +1,50 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + +/** + * Apply a function to the input arguments, yielding an appropriate result. + * This is the {@code int}-bearing specialization for {@link BiFunction}. + * + * @param the type of the first argument to the {@code applyAsLong} + * operation. + * @param the type of the second argument to the {@code applyAsLong} + * operation. + * + * @see BiFunction + * @since 1.8 + */ +@FunctionalInterface +public interface ToIntBiFunction { + + /** + * Compute the result of applying the function to the input arguments + * + * @param t an input object + * @param u an input object + * @return the function result value + */ + public int applyAsInt(T t, U u); +} diff --git a/jdk/src/share/classes/java/util/function/ToIntFunction.java b/jdk/src/share/classes/java/util/function/ToIntFunction.java new file mode 100644 index 00000000000..848a7b4486c --- /dev/null +++ b/jdk/src/share/classes/java/util/function/ToIntFunction.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + +/** + * Apply a function to the input argument, yielding an appropriate result. + * This is the {@code int}-bearing specialization for {@link Function}. + * + * @param the type of input objects to the function + * + * @see Function + * @since 1.8 + */ +@FunctionalInterface +public interface ToIntFunction { + + /** + * Compute the result of applying the function to the input arguments + * + * @param t the input object + * @return the function result value + */ + public int applyAsInt(T t); +} diff --git a/jdk/src/share/classes/java/util/function/ToLongBiFunction.java b/jdk/src/share/classes/java/util/function/ToLongBiFunction.java new file mode 100644 index 00000000000..994fa49a536 --- /dev/null +++ b/jdk/src/share/classes/java/util/function/ToLongBiFunction.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + +/** + * Apply a function to the input arguments, yielding an appropriate result. + * This is the {@code long}-bearing specialization for {@link BiFunction}. + * + * @param the type of the first argument to the {@code applyAsLong} + * operation. + * @param the type of the second argument to the {@code applyAsLong} + * operation. + * + * @see BiFunction + * @since 1.8 + */ +@FunctionalInterface +public interface ToLongBiFunction { + + /** + * Compute the result of applying the function to the input arguments. + * + * @param t an input object + * @param u an input object + * @return the function result value + */ + public long applyAsLong(T t, U u); +} diff --git a/jdk/src/share/classes/java/util/function/ToLongFunction.java b/jdk/src/share/classes/java/util/function/ToLongFunction.java new file mode 100644 index 00000000000..6d5877b6814 --- /dev/null +++ b/jdk/src/share/classes/java/util/function/ToLongFunction.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.function; + +/** + * Apply a function to the input argument, yielding an appropriate result. + * This is the {@code long}-bearing specialization for {@link Function}. + * + * @param the type of input objects to the function + * + * @see Function + * @since 1.8 + */ +@FunctionalInterface +public interface ToLongFunction { + + /** + * Compute the result of applying the function to the input arguments. + * + * @param t the input object + * @return the function result value + */ + public long applyAsLong(T t); +} diff --git a/jdk/src/share/classes/java/util/function/UnaryOperator.java b/jdk/src/share/classes/java/util/function/UnaryOperator.java index a8aaa0dcd6b..8e92291887e 100644 --- a/jdk/src/share/classes/java/util/function/UnaryOperator.java +++ b/jdk/src/share/classes/java/util/function/UnaryOperator.java @@ -26,20 +26,14 @@ package java.util.function; /** * An operation upon a single operand yielding a result. The operand and the - * result are of the same type. + * result are of the same type. This is a specialization of {@code Function} for + * the case where the operand and result are of the same type. * - * @param the type of operand to {@code operate} and of the result + * @param the type of operand to {@code apply} and of the result * + * @see Function * @since 1.8 */ @FunctionalInterface -public interface UnaryOperator { - - /** - * Returns the result of the operation upon the operand. - * - * @param operand the operand - * @return the operation result - */ - public T operate(T operand); +public interface UnaryOperator extends Function { } diff --git a/jdk/src/share/classes/java/util/function/package-info.java b/jdk/src/share/classes/java/util/function/package-info.java index 0d1eecf5139..36eda330d19 100644 --- a/jdk/src/share/classes/java/util/function/package-info.java +++ b/jdk/src/share/classes/java/util/function/package-info.java @@ -22,27 +22,62 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /** - * Functional interfaces provide typing for lambda expressions. Each - * functional interface provides a single abstract method to which the lambda - * expression's parameter and return types are matched. + * Functional interfaces provide target types for lambda expressions + * and method references. Each functional interface has a single abstract method + * to which the lambda expression's parameter and return types are matched or + * adapted. Functional interfaces can provide a target type in multiple contexts, + * such as assignment context, method invocation, or cast context: * - *

    The interfaces in this package are all functional interfaces used with the - * collections and streams frameworks. The operation identified by each - * interface is generally applied to a collection or stream of objects. + *

    + *     Predicate<String> p = String::isEmpty;
    + *
    + *     stream.filter(e -> e.getSize() > 10)...
    + *
    + *     stream.map((ToIntFunction) e -> e.getSize())...
    + * 
    + * + *

    The interfaces in this package are functional interfaces used by the JDK, + * and are available to be used by user code as well. While they do not identify + * a complete set of function shapes to which lambda expressions might be adapted, + * they provide enough to cover common requirements. + * + *

    The interfaces in this package are annotated with @{link FunctionalInterface}. + * This annotation is not a requirement for the compiler to recognize an interface + * as a functional interface, but merely an aid to capture design intent and enlist the + * help of the compiler in identifying accidental violations of design intent. + * + *

    The functional interfaces in this package follow an extensible naming convention, + * as follows: * - *

    All functional interface implementations are expected to ensure that: *

      - *
    • When used for aggregate operations upon many elements it should not be - * assumed that the operation will be called upon elements in any specific order. - *
    • - *
    • {@code null} values are accepted and returned by these functional - * interfaces according to the constraints of the specification in which the - * functional interfaces are used. The functional interfaces themselves do not - * constrain or mandate use of {@code null} values. Most usages of the - * functional interfaces will define the role, if any, of {@code null} for that - * context. - *
    • + *
    • There are several basic function shapes, including {@link java.util.function.Function} ({@code T -> R}), + * {@link java.util.function.Consumer} ({@code T -> void}), + * {@link java.util.function.Predicate} ({@code T -> boolean}), + * and {@link java.util.function.Supplier} ({@code () -> T}). + *
    • + *
    • Function shapes have a natural arity based on how they are most commonly used. + * The basic shapes can be modified by an arity prefix to indicate a different arity, + * such as {@link java.util.function.BiFunction} ({@code (T, U) -> R}). + *
    • + *
    • There are additional derived function shapes which extend the basic function + * shapes, including {@link java.util.function.UnaryOperator} (extends {@code Function}) and + * {@link java.util.function.BinaryOperator} (extends {@code BiFunction}). + *
    • + *
    • Type parameters of functional interfaces can be specialized to primitives with + * additional type prefixes. To specialize the return type for a type that has both + * generic return type and generic arguments, we prefix {@code ToXxx}, as in + * {@link java.util.function.ToIntFunction}. Otherwise, type arguments are specialized left-to-right, + * as in {@link java.util.function.DoubleConsumer} or {@link java.util.function.ObjIntConsumer}. + * (The type prefix {@code Obj} is used to indicate that we don't want to specialize this parameter, + * but want to move on to the next parameter.) These schemes can be combined as in {@code IntToDoubleFunction}. + *
    • + *
    • If there are specialization prefixes for all arguments, the arity prefix may be left + * out (as in {@link java.util.function.ObjIntConsumer}). + *
    • *
    + * + * @see java.lang.FunctionalInterface */ package java.util.function; diff --git a/jdk/test/java/lang/PrimitiveSumMinMaxTest.java b/jdk/test/java/lang/PrimitiveSumMinMaxTest.java index 1c44109c83f..56ab6740a83 100644 --- a/jdk/test/java/lang/PrimitiveSumMinMaxTest.java +++ b/jdk/test/java/lang/PrimitiveSumMinMaxTest.java @@ -50,20 +50,20 @@ public class PrimitiveSumMinMaxTest { BinaryOperator xor = Boolean::logicalXor; Comparator cmp = Boolean::compare; - assertTrue(and.operate(true, true)); - assertFalse(and.operate(true, false)); - assertFalse(and.operate(false, true)); - assertFalse(and.operate(false, false)); + assertTrue(and.apply(true, true)); + assertFalse(and.apply(true, false)); + assertFalse(and.apply(false, true)); + assertFalse(and.apply(false, false)); - assertTrue(or.operate(true, true)); - assertTrue(or.operate(true, false)); - assertTrue(or.operate(false, true)); - assertFalse(or.operate(false, false)); + assertTrue(or.apply(true, true)); + assertTrue(or.apply(true, false)); + assertTrue(or.apply(false, true)); + assertFalse(or.apply(false, false)); - assertFalse(xor.operate(true, true)); - assertTrue(xor.operate(true, false)); - assertTrue(xor.operate(false, true)); - assertFalse(xor.operate(false, false)); + assertFalse(xor.apply(true, true)); + assertTrue(xor.apply(true, false)); + assertTrue(xor.apply(false, true)); + assertFalse(xor.apply(false, false)); assertEquals(Boolean.TRUE.compareTo(Boolean.TRUE), cmp.compare(true, true)); assertEquals(Boolean.TRUE.compareTo(Boolean.FALSE), cmp.compare(true, false)); @@ -83,12 +83,12 @@ public class PrimitiveSumMinMaxTest { int[] numbers = { -1, 0, 1, 100, Integer.MAX_VALUE, Integer.MIN_VALUE }; for (int i : numbers) { for (int j : numbers) { - assertEquals(i+j, (int) sum1.operate(i, j)); - assertEquals(i+j, sum2.operateAsInt(i, j)); - assertEquals(Math.max(i,j), (int) max1.operate(i, j)); - assertEquals(Math.max(i,j), max2.operateAsInt(i, j)); - assertEquals(Math.min(i,j), (int) min1.operate(i, j)); - assertEquals(Math.min(i,j), min2.operateAsInt(i, j)); + assertEquals(i+j, (int) sum1.apply(i, j)); + assertEquals(i+j, sum2.applyAsInt(i, j)); + assertEquals(Math.max(i,j), (int) max1.apply(i, j)); + assertEquals(Math.max(i,j), max2.applyAsInt(i, j)); + assertEquals(Math.min(i,j), (int) min1.apply(i, j)); + assertEquals(Math.min(i,j), min2.applyAsInt(i, j)); assertEquals(((Integer) i).compareTo(j), cmp.compare(i, j)); } } @@ -106,12 +106,12 @@ public class PrimitiveSumMinMaxTest { long[] numbers = { -1, 0, 1, 100, Long.MAX_VALUE, Long.MIN_VALUE }; for (long i : numbers) { for (long j : numbers) { - assertEquals(i+j, (long) sum1.operate(i, j)); - assertEquals(i+j, sum2.operateAsLong(i, j)); - assertEquals(Math.max(i,j), (long) max1.operate(i, j)); - assertEquals(Math.max(i,j), max2.operateAsLong(i, j)); - assertEquals(Math.min(i,j), (long) min1.operate(i, j)); - assertEquals(Math.min(i,j), min2.operateAsLong(i, j)); + assertEquals(i+j, (long) sum1.apply(i, j)); + assertEquals(i+j, sum2.applyAsLong(i, j)); + assertEquals(Math.max(i,j), (long) max1.apply(i, j)); + assertEquals(Math.max(i,j), max2.applyAsLong(i, j)); + assertEquals(Math.min(i,j), (long) min1.apply(i, j)); + assertEquals(Math.min(i,j), min2.applyAsLong(i, j)); assertEquals(((Long) i).compareTo(j), cmp.compare(i, j)); } } @@ -126,9 +126,9 @@ public class PrimitiveSumMinMaxTest { float[] numbers = { -1, 0, 1, 100, Float.MAX_VALUE, Float.MIN_VALUE }; for (float i : numbers) { for (float j : numbers) { - assertEquals(i+j, (float) sum1.operate(i, j)); - assertEquals(Math.max(i,j), (float) max1.operate(i, j)); - assertEquals(Math.min(i,j), (float) min1.operate(i, j)); + assertEquals(i+j, (float) sum1.apply(i, j)); + assertEquals(Math.max(i,j), (float) max1.apply(i, j)); + assertEquals(Math.min(i,j), (float) min1.apply(i, j)); assertEquals(((Float) i).compareTo(j), cmp.compare(i, j)); } } @@ -146,12 +146,12 @@ public class PrimitiveSumMinMaxTest { double[] numbers = { -1, 0, 1, 100, Double.MAX_VALUE, Double.MIN_VALUE }; for (double i : numbers) { for (double j : numbers) { - assertEquals(i+j, (double) sum1.operate(i, j)); - assertEquals(i+j, sum2.operateAsDouble(i, j)); - assertEquals(Math.max(i,j), (double) max1.operate(i, j)); - assertEquals(Math.max(i,j), max2.operateAsDouble(i, j)); - assertEquals(Math.min(i,j), (double) min1.operate(i, j)); - assertEquals(Math.min(i,j), min2.operateAsDouble(i, j)); + assertEquals(i+j, (double) sum1.apply(i, j)); + assertEquals(i+j, sum2.applyAsDouble(i, j)); + assertEquals(Math.max(i,j), (double) max1.apply(i, j)); + assertEquals(Math.max(i,j), max2.applyAsDouble(i, j)); + assertEquals(Math.min(i,j), (double) min1.apply(i, j)); + assertEquals(Math.min(i,j), min2.applyAsDouble(i, j)); assertEquals(((Double) i).compareTo(j), cmp.compare(i, j)); } } From ab4a830be8e7d3fe905afab852fe686764866aed Mon Sep 17 00:00:00 2001 From: John Zavgren Date: Tue, 19 Feb 2013 15:31:19 -0500 Subject: [PATCH 050/180] 8008107: [parfait] Use after free of pointer in jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c Reviewed-by: mullan, chegar --- jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c index bd0eab3c113..7ec69fda633 100644 --- a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c +++ b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c @@ -687,8 +687,8 @@ CK_SSL3_KEY_MAT_PARAMS jSsl3KeyMatParamToCKSsl3KeyMatParam(JNIEnv *env, jobject if ((*env)->ExceptionCheck(env)) { free(ckParam.RandomInfo.pClientRandom); free(ckParam.RandomInfo.pServerRandom); - free(ckParam.pReturnedKeyMaterial); free(ckParam.pReturnedKeyMaterial->pIVClient); + free(ckParam.pReturnedKeyMaterial); return ckParam; } From 2373a6318843669afbbd118567a42aeff69fb49f Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Tue, 19 Feb 2013 16:49:28 -0800 Subject: [PATCH 051/180] 8008262: pack200 should support MethodParameters - part 2 Reviewed-by: jrose --- .../com/sun/java/util/jar/pack/Attribute.java | 2 +- .../sun/java/util/jar/pack/BandStructure.java | 6 ++--- .../sun/java/util/jar/pack/PackageReader.java | 2 +- .../com/sun/java/util/jar/pack/bands.cpp | 2 +- .../native/com/sun/java/util/jar/pack/bands.h | 4 ++-- .../com/sun/java/util/jar/pack/unpack.cpp | 4 ++-- jdk/test/tools/pack200/AttributeTests.java | 22 +++++++++--------- jdk/test/tools/pack200/Utils.java | 23 ++++++++++++++++++- 8 files changed, 43 insertions(+), 22 deletions(-) diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java index f6ff030263e..a6033c97b14 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java @@ -177,7 +177,7 @@ class Attribute implements Comparable { define(sd, ATTR_CONTEXT_METHOD, "Synthetic", ""); define(sd, ATTR_CONTEXT_METHOD, "Deprecated", ""); define(sd, ATTR_CONTEXT_METHOD, "Exceptions", "NH[RCH]"); - define(sd, ATTR_CONTEXT_METHOD, "MethodParameters", "NB[RUNHI]"); + define(sd, ATTR_CONTEXT_METHOD, "MethodParameters", "NB[RUNHFH]"); //define(sd, ATTR_CONTEXT_METHOD, "Code", "HHNI[B]NH[PHPOHPOHRCNH]NH[RUHNI[B]]"); define(sd, ATTR_CONTEXT_CODE, "StackMapTable", diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java index fdfb87dc136..1a1ecef9055 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/BandStructure.java @@ -1505,7 +1505,7 @@ class BandStructure { // band for predefine method parameters IntBand method_MethodParameters_NB = method_attr_bands.newIntBand("method_MethodParameters_NB", BYTE1); CPRefBand method_MethodParameters_name_RUN = method_attr_bands.newCPRefBand("method_MethodParameters_name_RUN", UNSIGNED5, CONSTANT_Utf8, NULL_IS_OK); - IntBand method_MethodParameters_flag_I = method_attr_bands.newIntBand("method_MethodParameters_flag_I"); + IntBand method_MethodParameters_flag_FH = method_attr_bands.newIntBand("method_MethodParameters_flag_FH"); MultiBand class_attr_bands = class_bands.newMultiBand("(class_attr_bands)", UNSIGNED5); IntBand class_flags_hi = class_attr_bands.newIntBand("class_flags_hi"); @@ -1776,9 +1776,9 @@ class BandStructure { new Band[]{ method_MethodParameters_NB, method_MethodParameters_name_RUN, - method_MethodParameters_flag_I + method_MethodParameters_flag_FH }, - "MethodParameters", "NB[RUNHI]"); + "MethodParameters", "NB[RUNHFH]"); assert(attrCodeEmpty == Package.attrCodeEmpty); predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_METHOD, new Band[] { method_Signature_RS }, diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java index 319b8793347..df4687b4aff 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java @@ -1521,7 +1521,7 @@ class PackageReader extends BandStructure { // *method_Exceptions_RC :UNSIGNED5 (cp_Class) // *method_MethodParameters_NB: BYTE1 // *method_MethodParameters_RUN: UNSIGNED5 (cp_Utf8) - // *method_MethodParameters_I: UNSIGNED5 (flag) + // *method_MethodParameters_FH: UNSIGNED5 (flag) // // code_attr_bands: // *code_flags :UNSIGNED5 diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp index 8ad5e556c41..42340fa5cfd 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.cpp @@ -354,7 +354,7 @@ const band_init all_band_inits[] = { BAND_INIT(method_metadata_bands, -1, -1), BAND_INIT(method_MethodParameters_NB, BYTE1_spec, 0), BAND_INIT(method_MethodParameters_name_RUN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Utf8)), - BAND_INIT(method_MethodParameters_flag_I, UNSIGNED5_spec, 0), + BAND_INIT(method_MethodParameters_flag_FH, UNSIGNED5_spec, 0), BAND_INIT(method_attr_bands, -1, -1), BAND_INIT(class_flags_hi, UNSIGNED5_spec, 0), BAND_INIT(class_flags_lo, UNSIGNED5_spec, 0), diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h index c555936d02e..052cd5d71a5 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/bands.h @@ -214,7 +214,7 @@ enum band_number { e_method_metadata_bands, e_method_MethodParameters_NB, e_method_MethodParameters_name_RUN, - e_method_MethodParameters_flag_I, + e_method_MethodParameters_flag_FH, e_method_attr_bands, e_class_flags_hi, @@ -393,7 +393,7 @@ enum band_number { #define method_Signature_RS all_bands[e_method_Signature_RS] #define method_MethodParameters_NB all_bands[e_method_MethodParameters_NB] #define method_MethodParameters_name_RUN all_bands[e_method_MethodParameters_name_RUN] -#define method_MethodParameters_flag_I all_bands[e_method_MethodParameters_flag_I] +#define method_MethodParameters_flag_FH all_bands[e_method_MethodParameters_flag_FH] #define method_attr_bands all_bands[e_method_attr_bands] #define class_flags_hi all_bands[e_class_flags_hi] #define class_flags_lo all_bands[e_class_flags_lo] diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp index 4b5e38a0de1..9ce0308089f 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp @@ -2488,7 +2488,7 @@ void unpacker::read_attrs(int attrc, int obj_count) { method_MethodParameters_NB.readData(count); count = method_MethodParameters_NB.getIntTotal(); method_MethodParameters_name_RUN.readData(count); - method_MethodParameters_flag_I.readData(count); + method_MethodParameters_flag_FH.readData(count); CHECK; break; @@ -4431,7 +4431,7 @@ int unpacker::write_attrs(int attrc, julong indexBits) { putu1(count = method_MethodParameters_NB.getByte()); for (j = 0; j < count; j++) { putref(method_MethodParameters_name_RUN.getRefN()); - putu4(method_MethodParameters_flag_I.getInt()); + putu2(method_MethodParameters_flag_FH.getInt()); } break; diff --git a/jdk/test/tools/pack200/AttributeTests.java b/jdk/test/tools/pack200/AttributeTests.java index d4a40a90cc5..6526737b732 100644 --- a/jdk/test/tools/pack200/AttributeTests.java +++ b/jdk/test/tools/pack200/AttributeTests.java @@ -29,7 +29,7 @@ import java.util.List; import static java.nio.file.StandardOpenOption.*; /* * @test - * @bug 6746111 8005252 + * @bug 6746111 8005252 8008262 * @summary tests various classfile format and attribute handling by pack200 * @compile -XDignore.symbol.file Utils.java AttributeTests.java * @run main AttributeTests @@ -67,17 +67,17 @@ public class AttributeTests { File testjarFile = new File(cwd, "test" + Utils.JAR_FILE_EXT); Utils.jar("cvf", testjarFile.getName(), javaClassName); - // pack using --repack - File outjarFile = new File(cwd, "out" + Utils.JAR_FILE_EXT); - scratch.clear(); - scratch.add(Utils.getPack200Cmd()); - scratch.add("--repack"); - scratch.add("--unknown-attribute=error"); - scratch.add(outjarFile.getName()); - scratch.add(testjarFile.getName()); - Utils.runExec(scratch); + // pack using native --repack + File nativejarFile = new File(cwd, "out-n" + Utils.JAR_FILE_EXT); + Utils.repack(testjarFile, nativejarFile, false, + "--unknown-attribute=error"); + Utils.doCompareVerify(testjarFile, nativejarFile); - Utils.doCompareVerify(testjarFile, outjarFile); + // pack using java --repack + File javajarFile = new File(cwd, "out-j" + Utils.JAR_FILE_EXT); + Utils.repack(testjarFile, javajarFile, true, + "--unknown-attribute=error"); + Utils.doCompareBitWise(nativejarFile, javajarFile); } /* * this test checks to see if we get the expected strings for output diff --git a/jdk/test/tools/pack200/Utils.java b/jdk/test/tools/pack200/Utils.java index 0e2269822f5..07a64595e9f 100644 --- a/jdk/test/tools/pack200/Utils.java +++ b/jdk/test/tools/pack200/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2013, 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 @@ -314,6 +314,27 @@ class Utils { throw new RuntimeException("jar command failed"); } } + static List repack(File inFile, File outFile, + boolean disableNative, String... extraOpts) { + List cmdList = new ArrayList<>(); + cmdList.clear(); + cmdList.add(Utils.getJavaCmd()); + cmdList.add("-ea"); + cmdList.add("-esa"); + if (disableNative) { + cmdList.add("-Dcom.sun.java.util.jar.pack.disable.native=true"); + } + cmdList.add("com.sun.java.util.jar.pack.Driver"); + cmdList.add("--repack"); + if (extraOpts != null) { + for (String opt: extraOpts) { + cmdList.add(opt); + } + } + cmdList.add(outFile.getName()); + cmdList.add(inFile.getName()); + return Utils.runExec(cmdList); + } // given a jar file foo.jar will write to foo.pack static void pack(JarFile jarFile, File packFile) throws IOException { From 0a5d02aaa60acf6be9426a2fc7ea06e6f826c9bd Mon Sep 17 00:00:00 2001 From: Katja Kantserova Date: Wed, 13 Feb 2013 10:24:24 +0100 Subject: [PATCH 052/180] 8008089: Delete OS dependent check in JdkFinder.getExecutable() Reviewed-by: egahlin, alanb --- jdk/test/lib/testlibrary/jdk/testlibrary/JdkFinder.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/JdkFinder.java b/jdk/test/lib/testlibrary/jdk/testlibrary/JdkFinder.java index fa038faccd4..d109778f22a 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/JdkFinder.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/JdkFinder.java @@ -38,10 +38,6 @@ public final class JdkFinder { } binPath += File.separatorChar + "bin" + File.separatorChar + executable; - File toolFile = new File(binPath); - if (!toolFile.exists()) { - throw new RuntimeException(binPath + " does not exist"); - } return binPath; } From 05b1c69fc0b1d62bd103e33d29e59b6e1de33401 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 13 Mar 2013 09:44:45 +0100 Subject: [PATCH 053/180] 8009761: Deoptimization on sparc doesn't set Llast_SP correctly in the interpreter frames it creates Deoptimization doesn't set up callee frames so that they restore caller frames correctly. Reviewed-by: kvn --- .../src/cpu/sparc/vm/cppInterpreter_sparc.cpp | 3 +- .../sparc/vm/templateInterpreter_sparc.cpp | 12 +- hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp | 3 +- .../cpu/x86/vm/templateInterpreter_x86_32.cpp | 3 +- .../cpu/x86/vm/templateInterpreter_x86_64.cpp | 3 +- .../src/cpu/zero/vm/cppInterpreter_zero.cpp | 3 +- .../vm/interpreter/abstractInterpreter.hpp | 9 +- .../src/share/vm/runtime/deoptimization.cpp | 1 + hotspot/src/share/vm/runtime/vframeArray.cpp | 15 +- hotspot/src/share/vm/runtime/vframeArray.hpp | 2 + .../test/compiler/8009761/Test8009761.java | 255 ++++++++++++++++++ 11 files changed, 295 insertions(+), 14 deletions(-) create mode 100644 hotspot/test/compiler/8009761/Test8009761.java diff --git a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp index 4918746db13..b1451fb0bae 100644 --- a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp @@ -2194,7 +2194,8 @@ int AbstractInterpreter::layout_activation(Method* method, int callee_locals_size, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { assert(popframe_extra_args == 0, "NEED TO FIX"); // NOTE this code must exactly mimic what InterpreterGenerator::generate_compute_interpreter_state() diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp index b5cfa00f975..4a6372ae0de 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp @@ -1581,7 +1581,8 @@ int AbstractInterpreter::layout_activation(Method* method, int callee_local_count, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { // Note: This calculation must exactly parallel the frame setup // in InterpreterGenerator::generate_fixed_frame. // If f!=NULL, set up the following variables: @@ -1664,6 +1665,15 @@ int AbstractInterpreter::layout_activation(Method* method, int delta = local_words - parm_words; int computed_sp_adjustment = (delta > 0) ? round_to(delta, WordsPerLong) : 0; *interpreter_frame->register_addr(I5_savedSP) = (intptr_t) (fp + computed_sp_adjustment) - STACK_BIAS; + if (!is_bottom_frame) { + // Llast_SP is set below for the current frame to SP (with the + // extra space for the callee's locals). Here we adjust + // Llast_SP for the caller's frame, removing the extra space + // for the current method's locals. + *caller->register_addr(Llast_SP) = *interpreter_frame->register_addr(I5_savedSP); + } else { + assert(*caller->register_addr(Llast_SP) >= *interpreter_frame->register_addr(I5_savedSP), "strange Llast_SP"); + } } else { assert(caller->is_compiled_frame() || caller->is_entry_frame(), "only possible cases"); // Don't have Lesp available; lay out locals block in the caller diff --git a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp index 55b29fb2f6c..c568c6f4d3a 100644 --- a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp +++ b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp @@ -2361,7 +2361,8 @@ int AbstractInterpreter::layout_activation(Method* method, int callee_locals, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { assert(popframe_extra_args == 0, "FIX ME"); // NOTE this code must exactly mimic what InterpreterGenerator::generate_compute_interpreter_state() diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp index a562bee3e53..5df98394cf5 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp @@ -1585,7 +1585,8 @@ int AbstractInterpreter::layout_activation(Method* method, int callee_locals, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { // Note: This calculation must exactly parallel the frame setup // in AbstractInterpreterGenerator::generate_method_entry. // If interpreter_frame!=NULL, set up the method, locals, and monitors. diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp index 26eadba79b2..c446cb3c9b1 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp @@ -1599,7 +1599,8 @@ int AbstractInterpreter::layout_activation(Method* method, int callee_locals, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { // Note: This calculation must exactly parallel the frame setup // in AbstractInterpreterGenerator::generate_method_entry. // If interpreter_frame!=NULL, set up the method, locals, and monitors. diff --git a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp index a199d037cbc..10501655dbb 100644 --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp @@ -919,7 +919,8 @@ int AbstractInterpreter::layout_activation(Method* method, int callee_locals, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { assert(popframe_extra_args == 0, "what to do?"); assert(!is_top_frame || (!callee_locals && !callee_param_count), "top frame should have no caller"); diff --git a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp index 7cd621318f7..264d4fffbf6 100644 --- a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp @@ -186,7 +186,8 @@ class AbstractInterpreter: AllStatic { int caller_actual_parameters, int callee_params, int callee_locals, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { return layout_activation(method, temps, popframe_args, @@ -196,7 +197,8 @@ class AbstractInterpreter: AllStatic { callee_locals, (frame*)NULL, (frame*)NULL, - is_top_frame); + is_top_frame, + is_bottom_frame); } static int layout_activation(Method* method, @@ -208,7 +210,8 @@ class AbstractInterpreter: AllStatic { int callee_locals, frame* caller, frame* interpreter_frame, - bool is_top_frame); + bool is_top_frame, + bool is_bottom_frame); // Runtime support static bool is_not_reached( methodHandle method, int bci); diff --git a/hotspot/src/share/vm/runtime/deoptimization.cpp b/hotspot/src/share/vm/runtime/deoptimization.cpp index 8f735b7d6fb..4a8d52b1284 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.cpp +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp @@ -425,6 +425,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread callee_parameters, callee_locals, index == 0, + index == array->frames() - 1, popframe_extra_args); // This pc doesn't have to be perfect just good enough to identify the frame // as interpreted so the skeleton frame will be walkable diff --git a/hotspot/src/share/vm/runtime/vframeArray.cpp b/hotspot/src/share/vm/runtime/vframeArray.cpp index d00e9f00954..3fda9e6dc1d 100644 --- a/hotspot/src/share/vm/runtime/vframeArray.cpp +++ b/hotspot/src/share/vm/runtime/vframeArray.cpp @@ -160,6 +160,7 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, int callee_locals, frame* caller, bool is_top_frame, + bool is_bottom_frame, int exec_mode) { JavaThread* thread = (JavaThread*) Thread::current(); @@ -275,7 +276,8 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, callee_locals, caller, iframe(), - is_top_frame); + is_top_frame, + is_bottom_frame); // Update the pc in the frame object and overwrite the temporary pc // we placed in the skeletal frame now that we finally know the @@ -420,6 +422,7 @@ int vframeArrayElement::on_stack_size(int caller_actual_parameters, int callee_parameters, int callee_locals, bool is_top_frame, + bool is_bottom_frame, int popframe_extra_stack_expression_els) const { assert(method()->max_locals() == locals()->size(), "just checking"); int locks = monitors() == NULL ? 0 : monitors()->number_of_monitors(); @@ -431,7 +434,8 @@ int vframeArrayElement::on_stack_size(int caller_actual_parameters, caller_actual_parameters, callee_parameters, callee_locals, - is_top_frame); + is_top_frame, + is_bottom_frame); } @@ -522,7 +526,7 @@ void vframeArray::unpack_to_stack(frame &unpack_frame, int exec_mode, int caller // Do the unpacking of interpreter frames; the frame at index 0 represents the top activation, so it has no callee // Unpack the frames from the oldest (frames() -1) to the youngest (0) - frame caller_frame = me; + frame* caller_frame = &me; for (index = frames() - 1; index >= 0 ; index--) { vframeArrayElement* elem = element(index); // caller int callee_parameters, callee_locals; @@ -542,13 +546,14 @@ void vframeArray::unpack_to_stack(frame &unpack_frame, int exec_mode, int caller elem->unpack_on_stack(caller_actual_parameters, callee_parameters, callee_locals, - &caller_frame, + caller_frame, index == 0, + index == frames() - 1, exec_mode); if (index == frames() - 1) { Deoptimization::unwind_callee_save_values(elem->iframe(), this); } - caller_frame = *elem->iframe(); + caller_frame = elem->iframe(); caller_actual_parameters = callee_parameters; } deallocate_monitor_chunks(); diff --git a/hotspot/src/share/vm/runtime/vframeArray.hpp b/hotspot/src/share/vm/runtime/vframeArray.hpp index b505c35712f..5ebe7b897eb 100644 --- a/hotspot/src/share/vm/runtime/vframeArray.hpp +++ b/hotspot/src/share/vm/runtime/vframeArray.hpp @@ -88,6 +88,7 @@ class vframeArrayElement : public _ValueObj { int on_stack_size(int caller_actual_parameters, int callee_parameters, int callee_locals, + bool is_bottom_frame, bool is_top_frame, int popframe_extra_stack_expression_els) const; @@ -97,6 +98,7 @@ class vframeArrayElement : public _ValueObj { int callee_locals, frame* caller, bool is_top_frame, + bool is_bottom_frame, int exec_mode); #ifndef PRODUCT diff --git a/hotspot/test/compiler/8009761/Test8009761.java b/hotspot/test/compiler/8009761/Test8009761.java new file mode 100644 index 00000000000..c897ab40069 --- /dev/null +++ b/hotspot/test/compiler/8009761/Test8009761.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2013, 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 8009761 + * @summary Deoptimization on sparc doesn't set Llast_SP correctly in the interpreter frames it creates + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation Test8009761 + * + */ + +public class Test8009761 { + + static class UnloadedClass { + volatile int i; + } + + static Object m1(boolean deopt) { + // When running interpreted, on sparc, the caller's stack is + // extended for the locals and the caller's frame is restored + // on return. + long l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, + l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, + l25, l26, l27, l28, l29, l30, l31, l32, l33, l34, l35, l36, + l37, l38, l39, l40, l41, l42, l43, l44, l45, l46, l47, l48, + l49, l50, l51, l52, l53, l54, l55, l56, l57, l58, l59, l60, + l61, l62, l63, l64, l65, l66, l67, l68, l69, l70, l71, l72, + l73, l74, l75, l76, l77, l78, l79, l80, l81, l82, l83, l84, + l85, l86, l87, l88, l89, l90, l91, l92, l93, l94, l95, l96, + l97, l98, l99, l100, l101, l102, l103, l104, l105, l106, l107, + l108, l109, l110, l111, l112, l113, l114, l115, l116, l117, + l118, l119, l120, l121, l122, l123, l124, l125, l126, l127, + l128, l129, l130, l131, l132, l133, l134, l135, l136, l137, + l138, l139, l140, l141, l142, l143, l144, l145, l146, l147, + l148, l149, l150, l151, l152, l153, l154, l155, l156, l157, + l158, l159, l160, l161, l162, l163, l164, l165, l166, l167, + l168, l169, l170, l171, l172, l173, l174, l175, l176, l177, + l178, l179, l180, l181, l182, l183, l184, l185, l186, l187, + l188, l189, l190, l191, l192, l193, l194, l195, l196, l197, + l198, l199, l200, l201, l202, l203, l204, l205, l206, l207, + l208, l209, l210, l211, l212, l213, l214, l215, l216, l217, + l218, l219, l220, l221, l222, l223, l224, l225, l226, l227, + l228, l229, l230, l231, l232, l233, l234, l235, l236, l237, + l238, l239, l240, l241, l242, l243, l244, l245, l246, l247, + l248, l249, l250, l251, l252, l253, l254, l255, l256, l257, + l258, l259, l260, l261, l262, l263, l264, l265, l266, l267, + l268, l269, l270, l271, l272, l273, l274, l275, l276, l277, + l278, l279, l280, l281, l282, l283, l284, l285, l286, l287, + l288, l289, l290, l291, l292, l293, l294, l295, l296, l297, + l298, l299, l300, l301, l302, l303, l304, l305, l306, l307, + l308, l309, l310, l311, l312, l313, l314, l315, l316, l317, + l318, l319, l320, l321, l322, l323, l324, l325, l326, l327, + l328, l329, l330, l331, l332, l333, l334, l335, l336, l337, + l338, l339, l340, l341, l342, l343, l344, l345, l346, l347, + l348, l349, l350, l351, l352, l353, l354, l355, l356, l357, + l358, l359, l360, l361, l362, l363, l364, l365, l366, l367, + l368, l369, l370, l371, l372, l373, l374, l375, l376, l377, + l378, l379, l380, l381, l382, l383, l384, l385, l386, l387, + l388, l389, l390, l391, l392, l393, l394, l395, l396, l397, + l398, l399, l400, l401, l402, l403, l404, l405, l406, l407, + l408, l409, l410, l411, l412, l413, l414, l415, l416, l417, + l418, l419, l420, l421, l422, l423, l424, l425, l426, l427, + l428, l429, l430, l431, l432, l433, l434, l435, l436, l437, + l438, l439, l440, l441, l442, l443, l444, l445, l446, l447, + l448, l449, l450, l451, l452, l453, l454, l455, l456, l457, + l458, l459, l460, l461, l462, l463, l464, l465, l466, l467, + l468, l469, l470, l471, l472, l473, l474, l475, l476, l477, + l478, l479, l480, l481, l482, l483, l484, l485, l486, l487, + l488, l489, l490, l491, l492, l493, l494, l495, l496, l497, + l498, l499, l500, l501, l502, l503, l504, l505, l506, l507, + l508, l509, l510, l511; + + long ll0, ll1, ll2, ll3, ll4, ll5, ll6, ll7, ll8, ll9, ll10, ll11, ll12, + ll13, ll14, ll15, ll16, ll17, ll18, ll19, ll20, ll21, ll22, ll23, ll24, + ll25, ll26, ll27, ll28, ll29, ll30, ll31, ll32, ll33, ll34, ll35, ll36, + ll37, ll38, ll39, ll40, ll41, ll42, ll43, ll44, ll45, ll46, ll47, ll48, + ll49, ll50, ll51, ll52, ll53, ll54, ll55, ll56, ll57, ll58, ll59, ll60, + ll61, ll62, ll63, ll64, ll65, ll66, ll67, ll68, ll69, ll70, ll71, ll72, + ll73, ll74, ll75, ll76, ll77, ll78, ll79, ll80, ll81, ll82, ll83, ll84, + ll85, ll86, ll87, ll88, ll89, ll90, ll91, ll92, ll93, ll94, ll95, ll96, + ll97, ll98, ll99, ll100, ll101, ll102, ll103, ll104, ll105, ll106, ll107, + ll108, ll109, ll110, ll111, ll112, ll113, ll114, ll115, ll116, ll117, + ll118, ll119, ll120, ll121, ll122, ll123, ll124, ll125, ll126, ll127, + ll128, ll129, ll130, ll131, ll132, ll133, ll134, ll135, ll136, ll137, + ll138, ll139, ll140, ll141, ll142, ll143, ll144, ll145, ll146, ll147, + ll148, ll149, ll150, ll151, ll152, ll153, ll154, ll155, ll156, ll157, + ll158, ll159, ll160, ll161, ll162, ll163, ll164, ll165, ll166, ll167, + ll168, ll169, ll170, ll171, ll172, ll173, ll174, ll175, ll176, ll177, + ll178, ll179, ll180, ll181, ll182, ll183, ll184, ll185, ll186, ll187, + ll188, ll189, ll190, ll191, ll192, ll193, ll194, ll195, ll196, ll197, + ll198, ll199, ll200, ll201, ll202, ll203, ll204, ll205, ll206, ll207, + ll208, ll209, ll210, ll211, ll212, ll213, ll214, ll215, ll216, ll217, + ll218, ll219, ll220, ll221, ll222, ll223, ll224, ll225, ll226, ll227, + ll228, ll229, ll230, ll231, ll232, ll233, ll234, ll235, ll236, ll237, + ll238, ll239, ll240, ll241, ll242, ll243, ll244, ll245, ll246, ll247, + ll248, ll249, ll250, ll251, ll252, ll253, ll254, ll255, ll256, ll257, + ll258, ll259, ll260, ll261, ll262, ll263, ll264, ll265, ll266, ll267, + ll268, ll269, ll270, ll271, ll272, ll273, ll274, ll275, ll276, ll277, + ll278, ll279, ll280, ll281, ll282, ll283, ll284, ll285, ll286, ll287, + ll288, ll289, ll290, ll291, ll292, ll293, ll294, ll295, ll296, ll297, + ll298, ll299, ll300, ll301, ll302, ll303, ll304, ll305, ll306, ll307, + ll308, ll309, ll310, ll311, ll312, ll313, ll314, ll315, ll316, ll317, + ll318, ll319, ll320, ll321, ll322, ll323, ll324, ll325, ll326, ll327, + ll328, ll329, ll330, ll331, ll332, ll333, ll334, ll335, ll336, ll337, + ll338, ll339, ll340, ll341, ll342, ll343, ll344, ll345, ll346, ll347, + ll348, ll349, ll350, ll351, ll352, ll353, ll354, ll355, ll356, ll357, + ll358, ll359, ll360, ll361, ll362, ll363, ll364, ll365, ll366, ll367, + ll368, ll369, ll370, ll371, ll372, ll373, ll374, ll375, ll376, ll377, + ll378, ll379, ll380, ll381, ll382, ll383, ll384, ll385, ll386, ll387, + ll388, ll389, ll390, ll391, ll392, ll393, ll394, ll395, ll396, ll397, + ll398, ll399, ll400, ll401, ll402, ll403, ll404, ll405, ll406, ll407, + ll408, ll409, ll410, ll411, ll412, ll413, ll414, ll415, ll416, ll417, + ll418, ll419, ll420, ll421, ll422, ll423, ll424, ll425, ll426, ll427, + ll428, ll429, ll430, ll431, ll432, ll433, ll434, ll435, ll436, ll437, + ll438, ll439, ll440, ll441, ll442, ll443, ll444, ll445, ll446, ll447, + ll448, ll449, ll450, ll451, ll452, ll453, ll454, ll455, ll456, ll457, + ll458, ll459, ll460, ll461, ll462, ll463, ll464, ll465, ll466, ll467, + ll468, ll469, ll470, ll471, ll472, ll473, ll474, ll475, ll476, ll477, + ll478, ll479, ll480, ll481, ll482, ll483, ll484, ll485, ll486, ll487, + ll488, ll489, ll490, ll491, ll492, ll493, ll494, ll495, ll496, ll497, + ll498, ll499, ll500, ll501, ll502, ll503, ll504, ll505, ll506, ll507, + ll508, ll509, ll510, ll511; + + if (deopt) { + UnloadedClass res = new UnloadedClass(); // sufficient to force deopt with c2 but not c1 + res.i = 0; // forces deopt with c1 + return res; + } + return null; + } + + static int count = 0; + + static void m2() { + // Will be called recursively until a stack overflow + // exception. Makes sure it has a lot of locals so that it's + // not called a sufficient number of times to trigger + // compilation. + + long l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, + l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, + l25, l26, l27, l28, l29, l30, l31, l32, l33, l34, l35, l36, + l37, l38, l39, l40, l41, l42, l43, l44, l45, l46, l47, l48, + l49, l50, l51, l52, l53, l54, l55, l56, l57, l58, l59, l60, + l61, l62, l63, l64, l65, l66, l67, l68, l69, l70, l71, l72, + l73, l74, l75, l76, l77, l78, l79, l80, l81, l82, l83, l84, + l85, l86, l87, l88, l89, l90, l91, l92, l93, l94, l95, l96, + l97, l98, l99, l100, l101, l102, l103, l104, l105, l106, l107, + l108, l109, l110, l111, l112, l113, l114, l115, l116, l117, + l118, l119, l120, l121, l122, l123, l124, l125, l126, l127, + l128, l129, l130, l131, l132, l133, l134, l135, l136, l137, + l138, l139, l140, l141, l142, l143, l144, l145, l146, l147, + l148, l149, l150, l151, l152, l153, l154, l155, l156, l157, + l158, l159, l160, l161, l162, l163, l164, l165, l166, l167, + l168, l169, l170, l171, l172, l173, l174, l175, l176, l177, + l178, l179, l180, l181, l182, l183, l184, l185, l186, l187, + l188, l189, l190, l191, l192, l193, l194, l195, l196, l197, + l198, l199, l200, l201, l202, l203, l204, l205, l206, l207, + l208, l209, l210, l211, l212, l213, l214, l215, l216, l217, + l218, l219, l220, l221, l222, l223, l224, l225, l226, l227, + l228, l229, l230, l231, l232, l233, l234, l235, l236, l237, + l238, l239, l240, l241, l242, l243, l244, l245, l246, l247, + l248, l249, l250, l251, l252, l253, l254, l255, l256, l257, + l258, l259, l260, l261, l262, l263, l264, l265, l266, l267, + l268, l269, l270, l271, l272, l273, l274, l275, l276, l277, + l278, l279, l280, l281, l282, l283, l284, l285, l286, l287, + l288, l289, l290, l291, l292, l293, l294, l295, l296, l297, + l298, l299, l300, l301, l302, l303, l304, l305, l306, l307, + l308, l309, l310, l311, l312, l313, l314, l315, l316, l317, + l318, l319, l320, l321, l322, l323, l324, l325, l326, l327, + l328, l329, l330, l331, l332, l333, l334, l335, l336, l337, + l338, l339, l340, l341, l342, l343, l344, l345, l346, l347, + l348, l349, l350, l351, l352, l353, l354, l355, l356, l357, + l358, l359, l360, l361, l362, l363, l364, l365, l366, l367, + l368, l369, l370, l371, l372, l373, l374, l375, l376, l377, + l378, l379, l380, l381, l382, l383, l384, l385, l386, l387, + l388, l389, l390, l391, l392, l393, l394, l395, l396, l397, + l398, l399, l400, l401, l402, l403, l404, l405, l406, l407, + l408, l409, l410, l411, l412, l413, l414, l415, l416, l417, + l418, l419, l420, l421, l422, l423, l424, l425, l426, l427, + l428, l429, l430, l431, l432, l433, l434, l435, l436, l437, + l438, l439, l440, l441, l442, l443, l444, l445, l446, l447, + l448, l449, l450, l451, l452, l453, l454, l455, l456, l457, + l458, l459, l460, l461, l462, l463, l464, l465, l466, l467, + l468, l469, l470, l471, l472, l473, l474, l475, l476, l477, + l478, l479, l480, l481, l482, l483, l484, l485, l486, l487, + l488, l489, l490, l491, l492, l493, l494, l495, l496, l497, + l498, l499, l500, l501, l502, l503, l504, l505, l506, l507, + l508, l509, l510, l511; + + count++; + m2(); + } + + static Object m3(boolean overflow_stack, boolean deopt) { + if (overflow_stack) { + m2(); + return null; + } + Object o = m1(deopt); + if (deopt) { + m2(); + } + return o; + } + + static public void main(String[] args) { + int c1; + // Call m2 from m3 recursively until stack overflow. Count the number of recursive calls. + try { + m3(true, false); + } catch(StackOverflowError soe) { + } + c1 = count; + // Force the compilation of m3() that will inline m1() + for (int i = 0; i < 20000; i++) { + m3(false, false); + } + count = 0; + // Force deoptimization of m3() in m1(), then return from m1() + // to m3(), call recursively m2(). If deoptimization correctly + // built the interpreter stack for m3()/m1() then we should be + // able to call m2() recursively as many times as before. + try { + m3(false, true); + } catch(StackOverflowError soe) { + } + if (c1 != count) { + System.out.println("Failed: init recursive calls: " + c1 + ". After deopt " + count); + System.exit(97); + } else { + System.out.println("PASSED"); + } + } +} From b26473a6cfc7886e194478ee90944c12eda6b06d Mon Sep 17 00:00:00 2001 From: Niclas Adlertz Date: Wed, 13 Mar 2013 10:56:54 +0100 Subject: [PATCH 054/180] 8009721: Make PhaseLive independent from regalloc Moved class definition of LRG_List from chaitin.hpp to live.hpp Reviewed-by: kvn, rbackman, roland --- hotspot/src/share/vm/opto/chaitin.hpp | 25 ------------------------- hotspot/src/share/vm/opto/live.hpp | 26 +++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/hotspot/src/share/vm/opto/chaitin.hpp b/hotspot/src/share/vm/opto/chaitin.hpp index 340e46d49b1..fc8010b851e 100644 --- a/hotspot/src/share/vm/opto/chaitin.hpp +++ b/hotspot/src/share/vm/opto/chaitin.hpp @@ -187,31 +187,6 @@ public: #endif }; -//------------------------------LRG_List--------------------------------------- -// Map Node indices to Live RanGe indices. -// Array lookup in the optimized case. -class LRG_List : public ResourceObj { - friend class VMStructs; - uint _cnt, _max; - uint* _lidxs; - ReallocMark _nesting; // assertion check for reallocations -public: - LRG_List( uint max ); - - uint lookup( uint nidx ) const { - return _lidxs[nidx]; - } - uint operator[] (uint nidx) const { return lookup(nidx); } - - void map( uint nidx, uint lidx ) { - assert( nidx < _cnt, "oob" ); - _lidxs[nidx] = lidx; - } - void extend( uint nidx, uint lidx ); - - uint Size() const { return _cnt; } -}; - //------------------------------IFG-------------------------------------------- // InterFerence Graph // An undirected graph implementation. Created with a fixed number of diff --git a/hotspot/src/share/vm/opto/live.hpp b/hotspot/src/share/vm/opto/live.hpp index c7714fecc4f..8a266c19067 100644 --- a/hotspot/src/share/vm/opto/live.hpp +++ b/hotspot/src/share/vm/opto/live.hpp @@ -33,11 +33,35 @@ #include "opto/regmask.hpp" class Block; -class LRG_List; class PhaseCFG; class VectorSet; class IndexSet; +//------------------------------LRG_List--------------------------------------- +// Map Node indices to Live RanGe indices. +// Array lookup in the optimized case. +class LRG_List : public ResourceObj { + friend class VMStructs; + uint _cnt, _max; + uint* _lidxs; + ReallocMark _nesting; // assertion check for reallocations +public: + LRG_List( uint max ); + + uint lookup( uint nidx ) const { + return _lidxs[nidx]; + } + uint operator[] (uint nidx) const { return lookup(nidx); } + + void map( uint nidx, uint lidx ) { + assert( nidx < _cnt, "oob" ); + _lidxs[nidx] = lidx; + } + void extend( uint nidx, uint lidx ); + + uint Size() const { return _cnt; } +}; + //------------------------------PhaseLive-------------------------------------- // Compute live-in/live-out class PhaseLive : public Phase { From bcbdbf99960a47faf45fd8ee12864ac989d2bfd1 Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Wed, 13 Feb 2013 10:25:09 +0100 Subject: [PATCH 055/180] 8005772: Stubs report compile id -1 in phase events Use 0 to indicate id is NA, -1 for error or uninitalized Reviewed-by: kvn, twisti --- hotspot/src/share/vm/compiler/compileBroker.cpp | 2 +- hotspot/src/share/vm/opto/compile.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 6f4e671c165..9214166e905 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -505,7 +505,7 @@ void CompileTask::log_task(xmlStream* log) { ResourceMark rm(thread); // - if (_compile_id != 0) log->print(" compile_id='%d'", _compile_id); + log->print(" compile_id='%d'", _compile_id); if (_osr_bci != CompileBroker::standard_entry_bci) { log->print(" compile_kind='osr'"); // same as nmethod::compile_kind } // else compile_kind='c2c' diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 568af91f127..a4657819c44 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -892,7 +892,7 @@ Compile::Compile( ciEnv* ci_env, : Phase(Compiler), _env(ci_env), _log(ci_env->log()), - _compile_id(-1), + _compile_id(0), _save_argument_registers(save_arg_registers), _method(NULL), _stub_name(stub_name), From 24b144ccd9f9de649d43d7f4ef49d23f620d75e5 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Thu, 14 Feb 2013 13:01:03 +0000 Subject: [PATCH 056/180] 8008201: Add java/lang/Class/asSubclass/BasicUnit.java to the ProblemList Reviewed-by: mcimadamore --- jdk/test/ProblemList.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 840a9274293..7c621e00884 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -134,6 +134,9 @@ java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java generic-all # 7196801 java/lang/management/MemoryMXBean/LowMemoryTest2.sh generic-all +# 8008200 +java/lang/Class/asSubclass/BasicUnit.java generic-all + ############################################################################ # jdk_management From 1930d1f090ff59cfbeda117ea9a8c6739f1c70a1 Mon Sep 17 00:00:00 2001 From: Peter Levart Date: Wed, 13 Feb 2013 14:50:14 -0800 Subject: [PATCH 057/180] 8008167: IdentityHashMap.[keySet|values|entrySet].toArray speed-up Reviewed-by: mduigou, martin --- .../classes/java/util/IdentityHashMap.java | 98 ++++++++++++++++--- 1 file changed, 85 insertions(+), 13 deletions(-) diff --git a/jdk/src/share/classes/java/util/IdentityHashMap.java b/jdk/src/share/classes/java/util/IdentityHashMap.java index 0a71e5bd5a9..f05bd144e04 100644 --- a/jdk/src/share/classes/java/util/IdentityHashMap.java +++ b/jdk/src/share/classes/java/util/IdentityHashMap.java @@ -25,6 +25,7 @@ package java.util; import java.io.*; +import java.lang.reflect.Array; /** * This class implements the Map interface with a hash table, using @@ -1010,6 +1011,37 @@ public class IdentityHashMap result += System.identityHashCode(key); return result; } + public Object[] toArray() { + return toArray(new Object[size()]); + } + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + int expectedModCount = modCount; + int size = size(); + if (a.length < size) + a = (T[]) Array.newInstance(a.getClass().getComponentType(), size); + Object[] tab = table; + int ti = 0; + for (int si = 0; si < tab.length; si += 2) { + Object key; + if ((key = tab[si]) != null) { // key present ? + // more elements than expected -> concurrent modification from other thread + if (ti >= size) { + throw new ConcurrentModificationException(); + } + a[ti++] = (T) unmaskNull(key); // unmask key + } + } + // fewer elements than expected or concurrent modification from other thread detected + if (ti < size || expectedModCount != modCount) { + throw new ConcurrentModificationException(); + } + // final null marker as per spec + if (ti < a.length) { + a[ti] = null; + } + return a; + } } /** @@ -1062,6 +1094,36 @@ public class IdentityHashMap public void clear() { IdentityHashMap.this.clear(); } + public Object[] toArray() { + return toArray(new Object[size()]); + } + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + int expectedModCount = modCount; + int size = size(); + if (a.length < size) + a = (T[]) Array.newInstance(a.getClass().getComponentType(), size); + Object[] tab = table; + int ti = 0; + for (int si = 0; si < tab.length; si += 2) { + if (tab[si++] != null) { // key present ? + // more elements than expected -> concurrent modification from other thread + if (ti >= size) { + throw new ConcurrentModificationException(); + } + a[ti++] = (T) tab[si]; // copy value + } + } + // fewer elements than expected or concurrent modification from other thread detected + if (ti < size || expectedModCount != modCount) { + throw new ConcurrentModificationException(); + } + // final null marker as per spec + if (ti < a.length) { + a[ti] = null; + } + return a; + } } /** @@ -1149,25 +1211,35 @@ public class IdentityHashMap } public Object[] toArray() { - int size = size(); - Object[] result = new Object[size]; - Iterator> it = iterator(); - for (int i = 0; i < size; i++) - result[i] = new AbstractMap.SimpleEntry<>(it.next()); - return result; + return toArray(new Object[size()]); } @SuppressWarnings("unchecked") public T[] toArray(T[] a) { + int expectedModCount = modCount; int size = size(); if (a.length < size) - a = (T[])java.lang.reflect.Array - .newInstance(a.getClass().getComponentType(), size); - Iterator> it = iterator(); - for (int i = 0; i < size; i++) - a[i] = (T) new AbstractMap.SimpleEntry<>(it.next()); - if (a.length > size) - a[size] = null; + a = (T[]) Array.newInstance(a.getClass().getComponentType(), size); + Object[] tab = table; + int ti = 0; + for (int si = 0; si < tab.length; si += 2) { + Object key; + if ((key = tab[si]) != null) { // key present ? + // more elements than expected -> concurrent modification from other thread + if (ti >= size) { + throw new ConcurrentModificationException(); + } + a[ti++] = (T) new AbstractMap.SimpleEntry(unmaskNull(key), tab[si + 1]); + } + } + // fewer elements than expected or concurrent modification from other thread detected + if (ti < size || expectedModCount != modCount) { + throw new ConcurrentModificationException(); + } + // final null marker as per spec + if (ti < a.length) { + a[ti] = null; + } return a; } } From 07c7afeaac66498536cee778971c4df14d5da520 Mon Sep 17 00:00:00 2001 From: Bharadwaj Yadavalli Date: Thu, 14 Feb 2013 11:09:07 -0800 Subject: [PATCH 058/180] 8007736: VerifyError for use of static method in interface Reviewed-by: mchung --- jdk/src/share/native/common/check_code.c | 25 +++++++++++--- jdk/test/vm/verifier/TestStaticIF.java | 44 ++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 jdk/test/vm/verifier/TestStaticIF.java diff --git a/jdk/src/share/native/common/check_code.c b/jdk/src/share/native/common/check_code.c index c761a3d9158..7ecf096a679 100644 --- a/jdk/src/share/native/common/check_code.c +++ b/jdk/src/share/native/common/check_code.c @@ -206,6 +206,8 @@ enum { #define LDC_METHOD_HANDLE_MAJOR_VERSION 51 +#define STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION 52 + #define ALLOC_STACK_SIZE 16 /* big enough */ typedef struct alloc_stack_type { @@ -1246,11 +1248,24 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) jclass cb = context->class; fullinfo_type clazz_info; int is_constructor, is_internal, is_invokedynamic; - int kind = (opcode == JVM_OPC_invokeinterface - ? 1 << JVM_CONSTANT_InterfaceMethodref - : opcode == JVM_OPC_invokedynamic - ? 1 << JVM_CONSTANT_NameAndType - : 1 << JVM_CONSTANT_Methodref); + int kind; + + switch (opcode ) { + case JVM_OPC_invokestatic: + kind = ((context->major_version < STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION) + ? (1 << JVM_CONSTANT_Methodref) + : ((1 << JVM_CONSTANT_InterfaceMethodref) | (1 << JVM_CONSTANT_Methodref))); + break; + case JVM_OPC_invokedynamic: + kind = 1 << JVM_CONSTANT_NameAndType; + break; + case JVM_OPC_invokeinterface: + kind = 1 << JVM_CONSTANT_InterfaceMethodref; + break; + default: + kind = 1 << JVM_CONSTANT_Methodref; + } + is_invokedynamic = opcode == JVM_OPC_invokedynamic; /* Make sure the constant pool item is the right type. */ verify_constant_pool_type(context, key, kind); diff --git a/jdk/test/vm/verifier/TestStaticIF.java b/jdk/test/vm/verifier/TestStaticIF.java new file mode 100644 index 00000000000..5a6776f3fc6 --- /dev/null +++ b/jdk/test/vm/verifier/TestStaticIF.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, 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 8007736 + * @summary Test static interface method. + * @run main/othervm -Xverify:all -XX:-UseSplitVerifier TestStaticIF + */ + +public class TestStaticIF implements StaticMethodInInterface { + + public static void main(String[] args) { + System.out.printf("main: %s%n", StaticMethodInInterface.get()); + } +} + +interface StaticMethodInInterface { + + public static String get() { + return "Hello from StaticMethodInInterface.get()"; + } +} From 2fd9426c20bd546c9007b4f29821f5359e6033df Mon Sep 17 00:00:00 2001 From: Dmeetry Degrave Date: Fri, 15 Feb 2013 01:49:36 +0400 Subject: [PATCH 059/180] 7199858: Marshal exception is wrong Reviewed-by: lancea --- .../classes/com/sun/corba/se/impl/corba/TypeCodeImpl.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/corba/src/share/classes/com/sun/corba/se/impl/corba/TypeCodeImpl.java b/corba/src/share/classes/com/sun/corba/se/impl/corba/TypeCodeImpl.java index c9b6e55fd6a..7e926ddba63 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/corba/TypeCodeImpl.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/corba/TypeCodeImpl.java @@ -2189,10 +2189,7 @@ public final class TypeCodeImpl extends TypeCode if (labelIndex == _unionLabels.length) { // check if label has not been found - if (_defaultIndex == -1) - // throw exception if default was not expected - throw wrapper.unexpectedUnionDefault() ; - else + if (_defaultIndex != -1) // must be of the default branch type _memberTypes[_defaultIndex].copy(src, dst); } From f5e3306d7504137bcfe7f0c493b2d4d74f761aa2 Mon Sep 17 00:00:00 2001 From: Jia-Hong Chen Date: Thu, 14 Feb 2013 14:14:38 -0800 Subject: [PATCH 060/180] 8008173: [parfait] #1173 Uninitialised variable -- TransformHelper.cpp Reviewed-by: prr, vadim --- jdk/src/share/native/sun/java2d/loops/TransformHelper.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jdk/src/share/native/sun/java2d/loops/TransformHelper.c b/jdk/src/share/native/sun/java2d/loops/TransformHelper.c index 23bba354756..72334550250 100644 --- a/jdk/src/share/native/sun/java2d/loops/TransformHelper.c +++ b/jdk/src/share/native/sun/java2d/loops/TransformHelper.c @@ -353,6 +353,9 @@ Java_sun_java2d_loops_TransformHelper_Transform pInterpFunc = pBicubicFunc; maxlinepix = LINE_SIZE / 16; break; + default: + // Should not happen, but just in case. + return; } srcInfo.bounds.x1 = sx1; From a433a8918dfd3fcf59935706a68571c043f8bb11 Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Fri, 15 Feb 2013 01:17:31 +0000 Subject: [PATCH 061/180] 8008254: j.u.Calendar.JavatimeTest failed at TL b78 pit testing To use j.t.ZoneId zone name to keep round-trip Reviewed-by: okutsu --- jdk/test/java/util/Calendar/JavatimeTest.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/jdk/test/java/util/Calendar/JavatimeTest.java b/jdk/test/java/util/Calendar/JavatimeTest.java index 5b9a7101805..d7b211705f4 100644 --- a/jdk/test/java/util/Calendar/JavatimeTest.java +++ b/jdk/test/java/util/Calendar/JavatimeTest.java @@ -23,7 +23,7 @@ /* *@test - *@bug 8007520 + *@bug 8007520 8008254 *@summary Test those bridge methods to/from java.time date/time classes */ @@ -53,13 +53,10 @@ public class JavatimeTest { int nanos = r.nextInt(NANOS_PER_SECOND); int nanos_ms = nanos / 1000000 * 1000000; // millis precision long millis = secs * 1000 + r.nextInt(1000); - LocalDateTime ldt = LocalDateTime.ofEpochSecond(secs, nanos, ZoneOffset.UTC); LocalDateTime ldt_ms = LocalDateTime.ofEpochSecond(secs, nanos_ms, ZoneOffset.UTC); Instant inst = Instant.ofEpochSecond(secs, nanos); Instant inst_ms = Instant.ofEpochSecond(secs, nanos_ms); - //System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); - ///////////// java.util.Date ///////////////////////// Date jud = new java.util.Date(millis); Instant inst0 = jud.toInstant(); @@ -77,6 +74,8 @@ public class JavatimeTest { } //////////// java.util.GregorianCalendar ///////////// GregorianCalendar cal = new GregorianCalendar(); + // non-roundtrip of tz name between j.u.tz and j.t.zid + cal.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault())); cal.setGregorianChange(new java.util.Date(Long.MIN_VALUE)); cal.setFirstDayOfWeek(Calendar.MONDAY); cal.setMinimalDaysInFirstWeek(4); @@ -84,6 +83,9 @@ public class JavatimeTest { ZonedDateTime zdt0 = cal.toZonedDateTime(); if (cal.getTimeInMillis() != zdt0.toInstant().toEpochMilli() || !cal.equals(GregorianCalendar.from(zdt0))) { + System.out.println("cal:" + cal); + System.out.println("zdt:" + zdt0); + System.out.println("calNew:" + GregorianCalendar.from(zdt0)); System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); throw new RuntimeException("FAILED: gcal -> zdt -> gcal"); } From 5287640ec65a3b3541ff7dfd689f5471f2e4f427 Mon Sep 17 00:00:00 2001 From: Alexander Scherbatiy Date: Fri, 15 Feb 2013 14:24:42 +0400 Subject: [PATCH 062/180] 7173873: JFrame.setDefaultCloseOperation(EXIT_ON_CLOSE) will never lead to SE if EXIT_ON_CLOSE is already set Reviewed-by: malenkov, serb --- jdk/src/share/classes/javax/swing/JFrame.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/jdk/src/share/classes/javax/swing/JFrame.java b/jdk/src/share/classes/javax/swing/JFrame.java index cccd6f98aa5..aee994eecf9 100644 --- a/jdk/src/share/classes/javax/swing/JFrame.java +++ b/jdk/src/share/classes/javax/swing/JFrame.java @@ -387,13 +387,14 @@ public class JFrame extends Frame implements WindowConstants, operation != EXIT_ON_CLOSE) { throw new IllegalArgumentException("defaultCloseOperation must be one of: DO_NOTHING_ON_CLOSE, HIDE_ON_CLOSE, DISPOSE_ON_CLOSE, or EXIT_ON_CLOSE"); } - if (this.defaultCloseOperation != operation) { - if (operation == EXIT_ON_CLOSE) { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkExit(0); - } + + if (operation == EXIT_ON_CLOSE) { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkExit(0); } + } + if (this.defaultCloseOperation != operation) { int oldValue = this.defaultCloseOperation; this.defaultCloseOperation = operation; firePropertyChange("defaultCloseOperation", oldValue, operation); From 4615442550640167be71a639b992519b14522cc0 Mon Sep 17 00:00:00 2001 From: Frank Ding Date: Fri, 15 Feb 2013 15:05:58 +0400 Subject: [PATCH 063/180] 8008289: DefaultButtonModel instance keeps stale listeners in html FormView Reviewed-by: malenkov, alexsch --- .../javax/swing/text/html/FormView.java | 63 +++++++- .../swing/text/html/7189299/bug7189299.java | 138 ++++++++++++++++++ 2 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 jdk/test/javax/swing/text/html/7189299/bug7189299.java diff --git a/jdk/src/share/classes/javax/swing/text/html/FormView.java b/jdk/src/share/classes/javax/swing/text/html/FormView.java index 294637272f3..2d25516f339 100644 --- a/jdk/src/share/classes/javax/swing/text/html/FormView.java +++ b/jdk/src/share/classes/javax/swing/text/html/FormView.java @@ -159,6 +159,10 @@ public class FormView extends ComponentView implements ActionListener { attr.getAttribute(StyleConstants.NameAttribute); JComponent c = null; Object model = attr.getAttribute(StyleConstants.ModelAttribute); + + // Remove listeners previously registered in shared model + // when a new UI component is replaced. See bug 7189299. + removeStaleListenerForModel(model); if (t == HTML.Tag.INPUT) { c = createInputComponent(attr, model); } else if (t == HTML.Tag.SELECT) { @@ -310,6 +314,63 @@ public class FormView extends ComponentView implements ActionListener { return c; } + private void removeStaleListenerForModel(Object model) { + if (model instanceof DefaultButtonModel) { + // case of JButton whose model is DefaultButtonModel + // Need to remove stale ActionListener, ChangeListener and + // ItemListener that are instance of AbstractButton$Handler. + DefaultButtonModel buttonModel = (DefaultButtonModel) model; + String listenerClass = "javax.swing.AbstractButton$Handler"; + for (ActionListener listener : buttonModel.getActionListeners()) { + if (listenerClass.equals(listener.getClass().getName())) { + buttonModel.removeActionListener(listener); + } + } + for (ChangeListener listener : buttonModel.getChangeListeners()) { + if (listenerClass.equals(listener.getClass().getName())) { + buttonModel.removeChangeListener(listener); + } + } + for (ItemListener listener : buttonModel.getItemListeners()) { + if (listenerClass.equals(listener.getClass().getName())) { + buttonModel.removeItemListener(listener); + } + } + } else if (model instanceof AbstractListModel) { + // case of JComboBox and JList + // For JList, the stale ListDataListener is instance + // BasicListUI$Handler. + // For JComboBox, there are 2 stale ListDataListeners, which are + // BasicListUI$Handler and BasicComboBoxUI$Handler. + AbstractListModel listModel = (AbstractListModel) model; + String listenerClass1 = + "javax.swing.plaf.basic.BasicListUI$Handler"; + String listenerClass2 = + "javax.swing.plaf.basic.BasicComboBoxUI$Handler"; + for (ListDataListener listener : listModel.getListDataListeners()) { + if (listenerClass1.equals(listener.getClass().getName()) + || listenerClass2.equals(listener.getClass().getName())) + { + listModel.removeListDataListener(listener); + } + } + } else if (model instanceof AbstractDocument) { + // case of JPasswordField, JTextField and JTextArea + // All have 2 stale DocumentListeners. + String listenerClass1 = + "javax.swing.plaf.basic.BasicTextUI$UpdateHandler"; + String listenerClass2 = + "javax.swing.text.DefaultCaret$Handler"; + AbstractDocument docModel = (AbstractDocument) model; + for (DocumentListener listener : docModel.getDocumentListeners()) { + if (listenerClass1.equals(listener.getClass().getName()) + || listenerClass2.equals(listener.getClass().getName())) + { + docModel.removeDocumentListener(listener); + } + } + } + } /** * Determines the maximum span for this view along an @@ -347,7 +408,7 @@ public class FormView extends ComponentView implements ActionListener { /** - * Responsible for processeing the ActionEvent. + * Responsible for processing the ActionEvent. * If the element associated with the FormView, * has a type of "submit", "reset", "text" or "password" * then the action is processed. In the case of a "submit" diff --git a/jdk/test/javax/swing/text/html/7189299/bug7189299.java b/jdk/test/javax/swing/text/html/7189299/bug7189299.java new file mode 100644 index 00000000000..70d2057c89f --- /dev/null +++ b/jdk/test/javax/swing/text/html/7189299/bug7189299.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2013 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. + */ + +/* + * Portions Copyright (c) 2013 IBM Corporation + */ +import java.awt.BorderLayout; +import java.awt.Toolkit; + +import java.awt.event.ActionListener; +import javax.swing.DefaultButtonModel; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyleContext; +import javax.swing.text.html.HTMLEditorKit; +import sun.awt.SunToolkit; + + +/* + * @test + * @bug 8008289 + * @summary Shared ButtonModel instance should deregister previous listeners. + * @author Frank Ding + */ +public class bug7189299 { + + private static JEditorPane html; + private static JFrame frame; + + private static void setup() { + /** + * Note the input type is not restricted to "submit". Types "image", + * "checkbox", "radio" have the same problem. + */ + html = new JEditorPane("text/html", + "
    " + + "" + + "
    "); + frame = new JFrame(); + frame.setLayout(new BorderLayout()); + frame.add(html, BorderLayout.CENTER); + frame.setSize(200, 100); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + } + + private static void doTest() { + /* + * Calling updateComponentTreeUI creates a new FormView instance with + * its own associated JButton instance. The same DefaultButtonModel + * instance is used for both FormView's. + * + * The action listeners associated with (the JButton for) the first + * FormView should be unregistered from this common DefaultButtonModel, + * such that only those for the new FormView remain. + */ + SwingUtilities.updateComponentTreeUI(html); + } + + private static void verifySingleDefaultButtonModelListener() { + HTMLEditorKit htmlEditorKit = (HTMLEditorKit) html.getEditorKit(); + StyleContext.NamedStyle style = ((StyleContext.NamedStyle) htmlEditorKit + .getInputAttributes()); + DefaultButtonModel model = ((DefaultButtonModel) style + .getAttribute(StyleConstants.ModelAttribute)); + ActionListener[] listeners = model.getActionListeners(); + int actionListenerNum = listeners.length; + if (actionListenerNum != 1) { + throw new RuntimeException( + "Expected single ActionListener object registered with " + + "DefaultButtonModel; found " + actionListenerNum + + " listeners registered."); + } + + int changeListenerNum = model.getChangeListeners().length; + if (changeListenerNum != 1) { + throw new RuntimeException( + "Expected at most one ChangeListener object registered " + + "with DefaultButtonModel; found " + changeListenerNum + + " listeners registered."); + } + int itemListenerNum = model.getItemListeners().length; + if (itemListenerNum != 1) { + throw new RuntimeException( + "Expected at most one ItemListener object registered " + + "with DefaultButtonModel; found " + itemListenerNum + + " listeners registered."); + } + } + + public static void main(String[] args) throws Exception { + final SunToolkit toolkit = ((SunToolkit) Toolkit.getDefaultToolkit()); + + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + setup(); + } + }); + toolkit.realSync(); + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + try { + verifySingleDefaultButtonModelListener(); + doTest(); + verifySingleDefaultButtonModelListener(); + } finally { + frame.dispose(); + } + } + }); + } +} From 5c9a25d2d24fcd098fc0d901b90f7fa99d6c3f14 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Fri, 15 Feb 2013 11:06:52 +0000 Subject: [PATCH 064/180] 8008223: java/net/BindException/Test.java fails rarely Reviewed-by: khazra, alanb --- jdk/test/java/net/BindException/Test.java | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/jdk/test/java/net/BindException/Test.java b/jdk/test/java/net/BindException/Test.java index 19bba9af90b..11d37e4b9c9 100644 --- a/jdk/test/java/net/BindException/Test.java +++ b/jdk/test/java/net/BindException/Test.java @@ -46,7 +46,7 @@ public class Test { static int failures; static void doTest(Object test[], InetAddress ia1, InetAddress ia2, - boolean silent) { + boolean silent) throws Exception { String s1_type = (String)test[0]; String s2_type = (String)test[1]; int port = 0; @@ -64,11 +64,10 @@ public class Test { boolean failed = false; Exception failed_exc = null; + Socket sock1 = null; + ServerSocket ss = null; + DatagramSocket dsock1 = null; try { - Socket sock1, sock2; - ServerSocket ss; - DatagramSocket dsock1, dsock2; - /* bind the first socket */ if (s1_type.equals("Socket")) { @@ -90,16 +89,18 @@ public class Test { /* bind the second socket */ if (s2_type.equals("Socket")) { - sock2 = new Socket(); - sock2.bind( new InetSocketAddress(ia2, port)); + try (Socket sock2 = new Socket()) { + sock2.bind( new InetSocketAddress(ia2, port)); + } } if (s2_type.equals("ServerSocket")) { - ss = new ServerSocket(port, 0, ia2); + try (ServerSocket ss2 = new ServerSocket(port, 0, ia2)) { } } if (s2_type.equals("DatagramSocket")) { - dsock2 = new DatagramSocket( new InetSocketAddress(ia2, port) ); + try (DatagramSocket ds = + new DatagramSocket(new InetSocketAddress(ia2, port))) { } } } catch (BindException be) { @@ -107,6 +108,10 @@ public class Test { } catch (Exception e) { failed = true; failed_exc = e; + } finally { + if (sock1 != null) sock1.close(); + if (ss != null) ss.close(); + if (dsock1 != null) dsock1.close(); } /* From d273278133c0c40521669c741791c2d4a22c005f Mon Sep 17 00:00:00 2001 From: Vera Akulova Date: Fri, 15 Feb 2013 17:46:39 +0400 Subject: [PATCH 065/180] 8005920: After pressing combination Windows Key and M key, the frame, the instruction and the dialog can't be minimized Reviewed-by: serb, denis --- .../java/awt/Modal/WsDisabledStyle/Winkey/Winkey.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/jdk/test/java/awt/Modal/WsDisabledStyle/Winkey/Winkey.java b/jdk/test/java/awt/Modal/WsDisabledStyle/Winkey/Winkey.java index 9136e79f40e..5b927f8d520 100644 --- a/jdk/test/java/awt/Modal/WsDisabledStyle/Winkey/Winkey.java +++ b/jdk/test/java/awt/Modal/WsDisabledStyle/Winkey/Winkey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2013, 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 @@ -22,8 +22,8 @@ */ /* - @test %I% %E% - @bug 6572263 6571808 + @test + @bug 6572263 6571808 8005920 @summary PIT:FileDialog minimized to taskbar(through 'Show Desktop')selecting the fileDialog using windowList @author dmitry.cherepanov: area=awt.modal @run main/manual Winkey @@ -48,12 +48,14 @@ public class Winkey String[] instructions = { + " 0. This test is for MS Windows only, if you use other OS, press \"pass\" button.", " 1. there is a frame with a 'show modal' button, ", " 2. press the button to show a modal dialog, ", " 3. the modal dialog will be shown over the frame, ", " 4. please verify that all (5.1, 5.2.1, 5.2.2) the following tests pass: ", " ", " 5.1. press combination Windows Key and M key to minimize all windows, ", + " note that the modal dialog and modal blocked windows are NOT minimized", " 5.2. press combination Windows Key and D key to show desktop, ", " 5.2.1. restore the dialog by choosing this one in the ALT-TAB list, ", " 5.2.2. restore the dialog by mouse click on taskbar (on java or any other item)", From 381aecb7c2c6cb88891be2bbfdfe377cdc4ad7f5 Mon Sep 17 00:00:00 2001 From: Robert Field Date: Sat, 16 Feb 2013 12:36:54 -0800 Subject: [PATCH 066/180] 8004970: Implement serialization in the lambda metafactory Reviewed-by: forax --- .../AbstractValidatingLambdaMetafactory.java | 156 ++++++++----- .../invoke/InnerClassLambdaMetafactory.java | 168 +++++++------- .../java/lang/invoke/LambdaMetafactory.java | 112 +++++++++- .../java/lang/invoke/MethodHandleInfo.java | 33 ++- .../java/lang/invoke/SerializedLambda.java | 209 ++++++++++++++++++ .../invoke/TypeConvertingMethodAdapter.java | 36 ++- .../invoke/lambda/LambdaSerialization.java | 84 +++++++ 7 files changed, 639 insertions(+), 159 deletions(-) create mode 100644 jdk/src/share/classes/java/lang/invoke/SerializedLambda.java create mode 100644 jdk/test/java/lang/invoke/lambda/LambdaSerialization.java diff --git a/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java b/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java index 516443dc186..892a9dd5316 100644 --- a/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java +++ b/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java @@ -34,11 +34,11 @@ import sun.invoke.util.Wrapper; import static sun.invoke.util.Wrapper.*; /** - * Abstract implementation of a meta-factory which provides parameter unrolling and input validation. + * Abstract implementation of a lambda metafactory which provides parameter unrolling and input validation. * - * @author Robert Field + * @see LambdaMetafactory */ -/*non-public*/ abstract class AbstractValidatingLambdaMetafactory { +/* package */ abstract class AbstractValidatingLambdaMetafactory { /* * For context, the comments for the following fields are marked in quotes with their values, given this program: @@ -54,16 +54,19 @@ import static sun.invoke.util.Wrapper.*; final Class targetClass; // The class calling the meta-factory via invokedynamic "class X" final MethodType invokedType; // The type of the invoked method "(CC)II" final Class samBase; // The type of the returned instance "interface JJ" - final boolean isSerializable; // Should the returned instance be serializable + final MethodHandle samMethod; // Raw method handle for the functional interface method final MethodHandleInfo samInfo; // Info about the SAM method handle "MethodHandleInfo[9 II.foo(Object)Object]" final Class samClass; // Interface containing the SAM method "interface II" final MethodType samMethodType; // Type of the SAM method "(Object)Object" + final MethodHandle implMethod; // Raw method handle for the implementation method final MethodHandleInfo implInfo; // Info about the implementation method handle "MethodHandleInfo[5 CC.impl(int)String]" final int implKind; // Invocation kind for implementation "5"=invokevirtual final boolean implIsInstanceMethod; // Is the implementation an instance method "true" final Class implDefiningClass; // Type defining the implementation "class CC" final MethodType implMethodType; // Type of the implementation method "(int)String" final MethodType instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object" + final boolean isSerializable; // Should the returned instance be serializable + final Class[] markerInterfaces; // Additional marker interfaces to be implemented /** @@ -80,27 +83,35 @@ import static sun.invoke.util.Wrapper.*; * @param implMethod The implementation method which should be called (with suitable adaptation of argument * types, return types, and adjustment for captured arguments) when methods of the resulting * functional interface instance are invoked. - * @param instantiatedMethodType The signature of the SAM method from the functional interface's perspective + * @param instantiatedMethodType The signature of the primary functional interface method after type variables + * are substituted with their instantiation from the capture site * @throws ReflectiveOperationException + * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated */ AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller, MethodType invokedType, MethodHandle samMethod, MethodHandle implMethod, - MethodType instantiatedMethodType) - throws ReflectiveOperationException { + MethodType instantiatedMethodType, + int flags, + Class[] markerInterfaces) + throws ReflectiveOperationException, LambdaConversionException { this.targetClass = caller.lookupClass(); this.invokedType = invokedType; this.samBase = invokedType.returnType(); - this.isSerializable = Serializable.class.isAssignableFrom(samBase); + this.samMethod = samMethod; this.samInfo = new MethodHandleInfo(samMethod); this.samClass = samInfo.getDeclaringClass(); this.samMethodType = samInfo.getMethodType(); + this.implMethod = implMethod; this.implInfo = new MethodHandleInfo(implMethod); - this.implKind = implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeSpecial? MethodHandleInfo.REF_invokeVirtual : implInfo.getReferenceKind(); // @@@ Temp work-around to hotspot incorrectly converting to invokespecial + // @@@ Temporary work-around pending resolution of 8005119 + this.implKind = (implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeSpecial) + ? MethodHandleInfo.REF_invokeVirtual + : implInfo.getReferenceKind(); this.implIsInstanceMethod = implKind == MethodHandleInfo.REF_invokeVirtual || implKind == MethodHandleInfo.REF_invokeSpecial || @@ -109,6 +120,30 @@ import static sun.invoke.util.Wrapper.*; this.implMethodType = implInfo.getMethodType(); this.instantiatedMethodType = instantiatedMethodType; + + if (!samClass.isInterface()) { + throw new LambdaConversionException(String.format( + "Functional interface %s is not an interface", + samClass.getName())); + } + + boolean foundSerializableSupertype = Serializable.class.isAssignableFrom(samBase); + for (Class c : markerInterfaces) { + if (!c.isInterface()) { + throw new LambdaConversionException(String.format( + "Marker interface %s is not an interface", + c.getName())); + } + foundSerializableSupertype |= Serializable.class.isAssignableFrom(c); + } + this.isSerializable = ((flags & LambdaMetafactory.FLAG_SERIALIZABLE) != 0) + || foundSerializableSupertype; + + if (isSerializable && !foundSerializableSupertype) { + markerInterfaces = Arrays.copyOf(markerInterfaces, markerInterfaces.length + 1); + markerInterfaces[markerInterfaces.length-1] = Serializable.class; + } + this.markerInterfaces = markerInterfaces; } /** @@ -127,8 +162,9 @@ import static sun.invoke.util.Wrapper.*; void validateMetafactoryArgs() throws LambdaConversionException { // Check target type is a subtype of class where SAM method is defined if (!samClass.isAssignableFrom(samBase)) { - throw new LambdaConversionException(String.format("Invalid target type %s for lambda conversion; not a subtype of functional interface %s", - samBase.getName(), samClass.getName())); + throw new LambdaConversionException( + String.format("Invalid target type %s for lambda conversion; not a subtype of functional interface %s", + samBase.getName(), samClass.getName())); } switch (implKind) { @@ -149,14 +185,16 @@ import static sun.invoke.util.Wrapper.*; final int samArity = samMethodType.parameterCount(); final int instantiatedArity = instantiatedMethodType.parameterCount(); if (implArity + receiverArity != capturedArity + samArity) { - throw new LambdaConversionException(String.format("Incorrect number of parameters for %s method %s; %d captured parameters, %d functional interface parameters, %d implementation parameters", - implIsInstanceMethod ? "instance" : "static", implInfo, - capturedArity, samArity, implArity)); + throw new LambdaConversionException( + String.format("Incorrect number of parameters for %s method %s; %d captured parameters, %d functional interface method parameters, %d implementation parameters", + implIsInstanceMethod ? "instance" : "static", implInfo, + capturedArity, samArity, implArity)); } if (instantiatedArity != samArity) { - throw new LambdaConversionException(String.format("Incorrect number of parameters for %s method %s; %d functional interface parameters, %d SAM method parameters", - implIsInstanceMethod ? "instance" : "static", implInfo, - instantiatedArity, samArity)); + throw new LambdaConversionException( + String.format("Incorrect number of parameters for %s method %s; %d instantiated parameters, %d functional interface method parameters", + implIsInstanceMethod ? "instance" : "static", implInfo, + instantiatedArity, samArity)); } // If instance: first captured arg (receiver) must be subtype of class where impl method is defined @@ -180,8 +218,9 @@ import static sun.invoke.util.Wrapper.*; // check receiver type if (!implDefiningClass.isAssignableFrom(receiverClass)) { - throw new LambdaConversionException(String.format("Invalid receiver type %s; not a subtype of implementation type %s", - receiverClass, implDefiningClass)); + throw new LambdaConversionException( + String.format("Invalid receiver type %s; not a subtype of implementation type %s", + receiverClass, implDefiningClass)); } } else { // no receiver @@ -196,7 +235,8 @@ import static sun.invoke.util.Wrapper.*; Class capturedParamType = invokedType.parameterType(i + capturedStart); if (!capturedParamType.equals(implParamType)) { throw new LambdaConversionException( - String.format("Type mismatch in captured lambda parameter %d: expecting %s, found %s", i, capturedParamType, implParamType)); + String.format("Type mismatch in captured lambda parameter %d: expecting %s, found %s", + i, capturedParamType, implParamType)); } } // Check for adaptation match on SAM arguments @@ -206,7 +246,8 @@ import static sun.invoke.util.Wrapper.*; Class instantiatedParamType = instantiatedMethodType.parameterType(i + samOffset); if (!isAdaptableTo(instantiatedParamType, implParamType, true)) { throw new LambdaConversionException( - String.format("Type mismatch for lambda argument %d: %s is not convertible to %s", i, instantiatedParamType, implParamType)); + String.format("Type mismatch for lambda argument %d: %s is not convertible to %s", + i, instantiatedParamType, implParamType)); } } @@ -218,7 +259,8 @@ import static sun.invoke.util.Wrapper.*; : implMethodType.returnType(); if (!isAdaptableToAsReturn(actualReturnType, expectedType)) { throw new LambdaConversionException( - String.format("Type mismatch for lambda return: %s is not convertible to %s", actualReturnType, expectedType)); + String.format("Type mismatch for lambda return: %s is not convertible to %s", + actualReturnType, expectedType)); } } @@ -274,8 +316,8 @@ import static sun.invoke.util.Wrapper.*; } - /*********** Logging support -- for debugging only - static final Executor logPool = Executors.newSingleThreadExecutor(); // @@@ For debugging only + /*********** Logging support -- for debugging only, uncomment as needed + static final Executor logPool = Executors.newSingleThreadExecutor(); protected static void log(final String s) { MethodHandleProxyLambdaMetafactory.logPool.execute(new Runnable() { @Override @@ -297,17 +339,21 @@ import static sun.invoke.util.Wrapper.*; ***********************/ /** - * Find the SAM method and corresponding methods which should be bridged. SAM method and those to be bridged - * will have the same name and number of parameters. Check for matching default methods (non-abstract), they - * should not be bridged-over and indicate a complex bridging situation. + * Find the functional interface method and corresponding abstract methods + * which should be bridged. The functional interface method and those to be + * bridged will have the same name and number of parameters. Check for + * matching default methods (non-abstract), the VM will create bridges for + * default methods; We don't have enough readily available type information + * to distinguish between where the functional interface method should be + * bridged and where the default method should be bridged; This situation is + * flagged. */ class MethodAnalyzer { private final Method[] methods = samBase.getMethods(); - private final List methodsFound = new ArrayList<>(methods.length); private Method samMethod = null; private final List methodsToBridge = new ArrayList<>(methods.length); - private boolean defaultMethodFound = false; + private boolean conflictFoundBetweenDefaultAndBridge = false; MethodAnalyzer() { String samMethodName = samInfo.getName(); @@ -315,31 +361,36 @@ import static sun.invoke.util.Wrapper.*; int samParamLength = samParamTypes.length; Class samReturnType = samMethodType.returnType(); Class objectClass = Object.class; + List defaultMethods = new ArrayList<>(methods.length); for (Method m : methods) { if (m.getName().equals(samMethodName) && m.getDeclaringClass() != objectClass) { Class[] mParamTypes = m.getParameterTypes(); if (mParamTypes.length == samParamLength) { + // Method matches name and parameter length -- and is not Object if (Modifier.isAbstract(m.getModifiers())) { - // Exclude methods with duplicate signatures - if (methodUnique(m)) { - if (m.getReturnType().equals(samReturnType) && Arrays.equals(mParamTypes, samParamTypes)) { - // Exact match, this is the SAM method signature - samMethod = m; - } else { - methodsToBridge.add(m); - } + // Method is abstract + if (m.getReturnType().equals(samReturnType) + && Arrays.equals(mParamTypes, samParamTypes)) { + // Exact match, this is the SAM method signature + samMethod = m; + } else if (!hasMatchingBridgeSignature(m)) { + // Record bridges, exclude methods with duplicate signatures + methodsToBridge.add(m); } } else { - // This is a default method, flag for special processing - defaultMethodFound = true; - // Ignore future matching abstracts. - // Note, due to reabstraction, this is really a punt, hence pass-off to VM - methodUnique(m); + // Record default methods for conflict testing + defaultMethods.add(m); } } } } + for (Method dm : defaultMethods) { + if (hasMatchingBridgeSignature(dm)) { + conflictFoundBetweenDefaultAndBridge = true; + break; + } + } } Method getSamMethod() { @@ -350,27 +401,26 @@ import static sun.invoke.util.Wrapper.*; return methodsToBridge; } - boolean wasDefaultMethodFound() { - return defaultMethodFound; + boolean conflictFoundBetweenDefaultAndBridge() { + return conflictFoundBetweenDefaultAndBridge; } /** - * Search the list of previously found methods to determine if there is a method with the same signature - * (return and parameter types) as the specified method. If it wasn't found before, add to the found list. + * Search the list of previously found bridge methods to determine if there is a method with the same signature + * (return and parameter types) as the specified method. * * @param m The method to match - * @return False if the method was found, True otherwise + * @return True if the method was found, False otherwise */ - private boolean methodUnique(Method m) { + private boolean hasMatchingBridgeSignature(Method m) { Class[] ptypes = m.getParameterTypes(); Class rtype = m.getReturnType(); - for (Method md : methodsFound) { + for (Method md : methodsToBridge) { if (md.getReturnType().equals(rtype) && Arrays.equals(ptypes, md.getParameterTypes())) { + return true; + } + } return false; } } - methodsFound.add(m); - return true; - } - } } diff --git a/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index 13999001cdc..f2bb8ebc62c 100644 --- a/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -36,21 +36,28 @@ import java.security.AccessController; import java.security.PrivilegedAction; /** - * InnerClassLambdaMetafactory + * Lambda metafactory implementation which dynamically creates an inner-class-like class per lambda callsite. + * + * @see LambdaMetafactory */ -/*non-public*/ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory { +/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory { private static final int CLASSFILE_VERSION = 51; - private static final Type TYPE_VOID = Type.getType(void.class); private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE); private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl"; - private static final String NAME_SERIALIZABLE = "java/io/Serializable"; private static final String NAME_CTOR = ""; //Serialization support - private static final String NAME_SERIALIZED_LAMBDA = "com/oracle/java/lang/invoke/SerializedLambdaImpl"; + private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda"; private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;"; private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace"; private static final String NAME_OBJECT = "java/lang/Object"; + private static final String DESCR_CTOR_SERIALIZED_LAMBDA + = MethodType.methodType(void.class, + String.class, + int.class, String.class, String.class, String.class, + int.class, String.class, String.class, String.class, + String.class, + Object[].class).toMethodDescriptorString(); // Used to ensure that each spun class name is unique private static final AtomicInteger counter = new AtomicInteger(0); @@ -70,7 +77,7 @@ import java.security.PrivilegedAction; private final Type[] instantiatedArgumentTypes; // ASM types for the functional interface arguments /** - * Meta-factory constructor. + * General meta-factory constructor, standard cases and allowing for uncommon options such as serialization. * * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges * of the caller. @@ -83,16 +90,23 @@ import java.security.PrivilegedAction; * @param implMethod The implementation method which should be called (with suitable adaptation of argument * types, return types, and adjustment for captured arguments) when methods of the resulting * functional interface instance are invoked. - * @param instantiatedMethodType The signature of the SAM method from the functional interface's perspective + * @param instantiatedMethodType The signature of the primary functional interface method after type variables + * are substituted with their instantiation from the capture site + * @param flags A bitmask containing flags that may influence the translation of this lambda expression. Defined + * fields include FLAG_SERIALIZABLE. + * @param markerInterfaces Additional interfaces which the lambda object should implement. * @throws ReflectiveOperationException + * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated */ public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, MethodType invokedType, MethodHandle samMethod, MethodHandle implMethod, - MethodType instantiatedMethodType) - throws ReflectiveOperationException { - super(caller, invokedType, samMethod, implMethod, instantiatedMethodType); + MethodType instantiatedMethodType, + int flags, + Class[] markerInterfaces) + throws ReflectiveOperationException, LambdaConversionException { + super(caller, invokedType, samMethod, implMethod, instantiatedMethodType, flags, markerInterfaces); implMethodClassName = implDefiningClass.getName().replace('.', '/'); implMethodName = implInfo.getName(); implMethodDesc = implMethodType.toMethodDescriptorString(); @@ -109,7 +123,6 @@ import java.security.PrivilegedAction; argNames[i] = "arg$" + (i + 1); } instantiatedArgumentTypes = Type.getArgumentTypes(instantiatedMethodType.toMethodDescriptorString()); - } /** @@ -120,7 +133,8 @@ import java.security.PrivilegedAction; * * @return a CallSite, which, when invoked, will return an instance of the * functional interface - * @throws ReflectiveOperationException, LambdaConversionException + * @throws ReflectiveOperationException + * @throws LambdaConversionException If properly formed functional interface is not found */ @Override CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException { @@ -151,8 +165,8 @@ import java.security.PrivilegedAction; } else { return new ConstantCallSite( MethodHandles.Lookup.IMPL_LOOKUP - .findConstructor(innerClass, constructorType) - .asType(constructorType.changeReturnType(samBase))); + .findConstructor(innerClass, constructorType) + .asType(constructorType.changeReturnType(samBase))); } } @@ -161,16 +175,23 @@ import java.security.PrivilegedAction; * interface, define and return the class. * * @return a Class which implements the functional interface + * @throws LambdaConversionException If properly formed functional interface is not found */ - private Class spinInnerClass() throws LambdaConversionException { + private Class spinInnerClass() throws LambdaConversionException { String samName = samBase.getName().replace('.', '/'); - - cw.visit(CLASSFILE_VERSION, ACC_SUPER, lambdaClassName, null, NAME_MAGIC_ACCESSOR_IMPL, - isSerializable ? new String[]{samName, NAME_SERIALIZABLE} : new String[]{samName}); + String[] interfaces = new String[markerInterfaces.length + 1]; + interfaces[0] = samName; + for (int i=0; i) Unsafe.getUnsafe().defineClass(lambdaClassName, classBytes, 0, classBytes.length, loader, pd); + return (Class) Unsafe.getUnsafe().defineClass(lambdaClassName, classBytes, 0, classBytes.length, + loader, pd); } /** @@ -253,40 +273,44 @@ import java.security.PrivilegedAction; } /** - * Generate the serialization method (if needed) + * Generate the writeReplace method (if needed for serialization) */ - /****** This code is out of date -- known to be wrong -- and not currently used ****** - private void generateSerializationMethod(Type samType, String samMethodName) { - String samMethodDesc = samMethodType.toMethodDescriptorString(); - TypeConvertingMethodAdapter mv = new TypeConvertingMethodAdapter(cw.visitMethod(ACC_PRIVATE + ACC_FINAL, NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE, null, null)); + private void generateWriteReplace() { + TypeConvertingMethodAdapter mv + = new TypeConvertingMethodAdapter(cw.visitMethod(ACC_PRIVATE + ACC_FINAL, + NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE, + null, null)); mv.visitCode(); mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA); - mv.dup(); - mv.visitLdcInsn(samType); - mv.visitLdcInsn(samMethodName); - mv.visitLdcInsn(samMethodDesc); - mv.visitLdcInsn(Type.getType(implDefiningClass)); - mv.visitLdcInsn(implMethodName); - mv.visitLdcInsn(implMethodDesc); + mv.visitInsn(DUP);; + mv.visitLdcInsn(targetClass.getName().replace('.', '/')); + mv.visitLdcInsn(samInfo.getReferenceKind()); + mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/')); + mv.visitLdcInsn(samInfo.getName()); + mv.visitLdcInsn(samInfo.getMethodType().toMethodDescriptorString()); + mv.visitLdcInsn(implInfo.getReferenceKind()); + mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/')); + mv.visitLdcInsn(implInfo.getName()); + mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString()); + mv.visitLdcInsn(instantiatedMethodType.toMethodDescriptorString()); mv.iconst(argTypes.length); mv.visitTypeInsn(ANEWARRAY, NAME_OBJECT); for (int i = 0; i < argTypes.length; i++) { - mv.dup(); + mv.visitInsn(DUP); mv.iconst(i); mv.visitVarInsn(ALOAD, 0); - mv.getfield(lambdaClassName, argNames[i], argTypes[i].getDescriptor()); - mv.boxIfPrimitive(argTypes[i]); + mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor()); + mv.boxIfTypePrimitive(argTypes[i]); mv.visitInsn(AASTORE); } - mv.invokespecial(NAME_SERIALIZED_LAMBDA, NAME_CTOR, - "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V"); + mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR, + DESCR_CTOR_SERIALIZED_LAMBDA); mv.visitInsn(ARETURN); mv.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored mv.visitEnd(); } - ********/ /** * Generate a method which calls the lambda implementation method, @@ -321,11 +345,11 @@ import java.security.PrivilegedAction; if (implKind == MethodHandleInfo.REF_newInvokeSpecial) { visitTypeInsn(NEW, implMethodClassName); - dup(); + visitInsn(DUP);; } for (int i = 0; i < argTypes.length; i++) { visitVarInsn(ALOAD, 0); - getfield(lambdaClassName, argNames[i], argTypes[i].getDescriptor()); + visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor()); } convertArgumentTypes(Type.getArgumentTypes(m)); @@ -337,7 +361,7 @@ import java.security.PrivilegedAction; // Note: if adapting from non-void to void, the 'return' instruction will pop the unneeded result Type samReturnType = Type.getReturnType(m); convertType(implMethodReturnType, samReturnType, samReturnType); - areturn(samReturnType); + visitInsn(samReturnType.getOpcode(Opcodes.IRETURN)); visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored visitEnd(); @@ -352,7 +376,7 @@ import java.security.PrivilegedAction; Type rcvrType = samArgumentTypes[0]; Type instantiatedRcvrType = instantiatedArgumentTypes[0]; - load(lvIndex + 1, rcvrType); + visitVarInsn(rcvrType.getOpcode(ILOAD), lvIndex + 1); lvIndex += rcvrType.getSize(); convertType(rcvrType, Type.getType(implDefiningClass), instantiatedRcvrType); } @@ -362,7 +386,7 @@ import java.security.PrivilegedAction; Type targetType = implMethodArgumentTypes[argOffset + i]; Type instantiatedArgType = instantiatedArgumentTypes[i]; - load(lvIndex + 1, argType); + visitVarInsn(argType.getOpcode(ILOAD), lvIndex + 1); lvIndex += argType.getSize(); convertType(argType, targetType, instantiatedArgType); } @@ -388,45 +412,5 @@ import java.security.PrivilegedAction; throw new InternalError("Unexpected invocation kind: " + implKind); } } - - /** - * The following methods are copied from - * org.objectweb.asm.commons.InstructionAdapter. Part of ASM: a very - * small and fast Java bytecode manipulation framework. Copyright (c) - * 2000-2005 INRIA, France Telecom All rights reserved. - * - * Subclass with that (removing these methods) if that package/class is - * ever added to the JDK. - */ - private void iconst(final int cst) { - if (cst >= -1 && cst <= 5) { - mv.visitInsn(Opcodes.ICONST_0 + cst); - } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) { - mv.visitIntInsn(Opcodes.BIPUSH, cst); - } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) { - mv.visitIntInsn(Opcodes.SIPUSH, cst); - } else { - mv.visitLdcInsn(cst); - } - } - - private void load(final int var, final Type type) { - mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), var); - } - - private void dup() { - mv.visitInsn(Opcodes.DUP); - } - - private void areturn(final Type t) { - mv.visitInsn(t.getOpcode(Opcodes.IRETURN)); - } - - private void getfield( - final String owner, - final String name, - final String desc) { - mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, desc); - } } } diff --git a/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java b/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java index 378494b48d3..24c0c72c71c 100644 --- a/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java +++ b/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java @@ -42,14 +42,13 @@ package java.lang.invoke; * method, and the static types of the captured lambda arguments, and link a call site which, when invoked, * produces the lambda object. * - *

    Two pieces of information are needed about the functional interface: the SAM method and the type of the SAM - * method in the functional interface. The type can be different when parameterized types are used. For example, - * consider - * interface I<T> { int m(T x); } if this SAM type is used in a lambda - * I<Byte> v = ..., we need both the actual SAM method which has the signature - * (Object)int and the functional interface type of the method, which has signature - * (Byte)int. The latter is the instantiated erased functional interface method type, or - * simply instantiated method type. + *

    When parameterized types are used, the instantiated type of the functional interface method may be different + * from that in the functional interface. For example, consider + * interface I<T> { int m(T x); } if this functional interface type is used in a lambda + * I<Byte> v = ..., we need both the actual functional interface method which has the signature + * (Object)int and the erased instantiated type of the functional interface method (or simply + * instantiated method type), which has signature + * (Byte)int. * *

    While functional interfaces only have a single abstract method from the language perspective (concrete * methods in Object are and default methods may be present), at the bytecode level they may actually have multiple @@ -138,11 +137,25 @@ package java.lang.invoke; * * * + * The default bootstrap ({@link #metaFactory}) represents the common cases and uses an optimized protocol. + * Alternate bootstraps (e.g., {@link #altMetaFactory}) exist to support uncommon cases such as serialization + * or additional marker superinterfaces. * */ public class LambdaMetafactory { + /** Flag for alternate metafactories indicating the lambda object is must to be serializable */ + public static final int FLAG_SERIALIZABLE = 1 << 0; + /** + * Flag for alternate metafactories indicating the lambda object implements other marker interfaces + * besides Serializable + */ + public static final int FLAG_MARKERS = 1 << 1; + + private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + +/** * Standard meta-factory for conversion of lambda expressions or method references to functional interfaces. * * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges @@ -158,7 +171,8 @@ public class LambdaMetafactory { * @param implMethod The implementation method which should be called (with suitable adaptation of argument * types, return types, and adjustment for captured arguments) when methods of the resulting * functional interface instance are invoked. - * @param instantiatedMethodType The signature of the SAM method from the functional interface's perspective + * @param instantiatedMethodType The signature of the primary functional interface method after type variables + * are substituted with their instantiation from the capture site * @return a CallSite, which, when invoked, will return an instance of the functional interface * @throws ReflectiveOperationException * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated @@ -171,7 +185,85 @@ public class LambdaMetafactory { MethodType instantiatedMethodType) throws ReflectiveOperationException, LambdaConversionException { AbstractValidatingLambdaMetafactory mf; - mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType); + mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType, + 0, EMPTY_CLASS_ARRAY); + mf.validateMetafactoryArgs(); + return mf.buildCallSite(); + } + + /** + * Alternate meta-factory for conversion of lambda expressions or method references to functional interfaces, + * which supports serialization and other uncommon options. + * + * The declared argument list for this method is: + * + * CallSite altMetaFactory(MethodHandles.Lookup caller, + * String invokedName, + * MethodType invokedType, + * Object... args) + * + * but it behaves as if the argument list is: + * + * CallSite altMetaFactory(MethodHandles.Lookup caller, + * String invokedName, + * MethodType invokedType, + * MethodHandle samMethod + * MethodHandle implMethod, + * MethodType instantiatedMethodType, + * int flags, + * int markerInterfaceCount, // IF flags has MARKERS set + * Class... markerInterfaces // IF flags has MARKERS set + * ) + * + * + * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges + * of the caller. + * @param invokedName Stacked automatically by VM; the name of the invoked method as it appears at the call site. + * Currently unused. + * @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the + * expected static type of the returned lambda object, and the static types of the captured + * arguments for the lambda. In the event that the implementation method is an instance method, + * the first argument in the invocation signature will correspond to the receiver. + * @param samMethod The primary method in the functional interface to which the lambda or method reference is + * being converted, represented as a method handle. + * @param implMethod The implementation method which should be called (with suitable adaptation of argument + * types, return types, and adjustment for captured arguments) when methods of the resulting + * functional interface instance are invoked. + * @param instantiatedMethodType The signature of the primary functional interface method after type variables + * are substituted with their instantiation from the capture site + * @param flags A bitmask containing flags that may influence the translation of this lambda expression. Defined + * fields include FLAG_SERIALIZABLE and FLAG_MARKERS. + * @param markerInterfaceCount If the FLAG_MARKERS flag is set, this is a count of the number of additional + * marker interfaces + * @param markerInterfaces If the FLAG_MARKERS flag is set, this consists of Class objects identifying additional + * marker interfaces which the lambda object should implement, whose count equals + * markerInterfaceCount + * @return a CallSite, which, when invoked, will return an instance of the functional interface + * @throws ReflectiveOperationException + * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated + */ + public static CallSite altMetaFactory(MethodHandles.Lookup caller, + String invokedName, + MethodType invokedType, + Object... args) + throws ReflectiveOperationException, LambdaConversionException { + MethodHandle samMethod = (MethodHandle)args[0]; + MethodHandle implMethod = (MethodHandle)args[1]; + MethodType instantiatedMethodType = (MethodType)args[2]; + int flags = (Integer) args[3]; + Class[] markerInterfaces; + int argIndex = 4; + if ((flags & FLAG_MARKERS) != 0) { + int markerCount = (Integer) args[argIndex++]; + markerInterfaces = new Class[markerCount]; + System.arraycopy(args, argIndex, markerInterfaces, 0, markerCount); + argIndex += markerCount; + } + else + markerInterfaces = EMPTY_CLASS_ARRAY; + AbstractValidatingLambdaMetafactory mf; + mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType, + flags, markerInterfaces); mf.validateMetafactoryArgs(); return mf.buildCallSite(); } diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java index b73dd6350cd..ae579ab84c4 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java @@ -26,8 +26,11 @@ package java.lang.invoke; import java.lang.invoke.MethodHandleNatives.Constants; -//Not yet public: public -class MethodHandleInfo { +/** + * Cracking (reflecting) method handles back into their constituent symbolic parts. + * + */ +final class MethodHandleInfo { public static final int REF_NONE = Constants.REF_NONE, REF_getField = Constants.REF_getField, @@ -65,7 +68,33 @@ class MethodHandleInfo { return methodType; } + public int getModifiers() { + return -1; //TODO + } + public int getReferenceKind() { return referenceKind; } + + static String getReferenceKindString(int referenceKind) { + switch (referenceKind) { + case REF_NONE: return "REF_NONE"; + case REF_getField: return "getfield"; + case REF_getStatic: return "getstatic"; + case REF_putField: return "putfield"; + case REF_putStatic: return "putstatic"; + case REF_invokeVirtual: return "invokevirtual"; + case REF_invokeStatic: return "invokestatic"; + case REF_invokeSpecial: return "invokespecial"; + case REF_newInvokeSpecial: return "newinvokespecial"; + case REF_invokeInterface: return "invokeinterface"; + default: return "UNKNOWN_REFENCE_KIND" + "[" + referenceKind + "]"; + } + } + + @Override + public String toString() { + return String.format("%s %s.%s:%s", getReferenceKindString(referenceKind), + declaringClass.getName(), name, methodType); + } } diff --git a/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java b/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java new file mode 100644 index 00000000000..1a2db3f072a --- /dev/null +++ b/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java @@ -0,0 +1,209 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.lang.invoke; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Objects; + +/** + * Serialized form of a lambda expression. The properties of this class represent the information that is present + * at the lambda factory site, including the identity of the primary functional interface method, the identity of the + * implementation method, and any variables captured from the local environment at the time of lambda capture. + * + * @see LambdaMetafactory + */ +public final class SerializedLambda implements Serializable { + private static final long serialVersionUID = 8025925345765570181L; + private final String capturingClass; + private final String functionalInterfaceClass; + private final String functionalInterfaceMethodName; + private final String functionalInterfaceMethodSignature; + private final int functionalInterfaceMethodKind; + private final String implClass; + private final String implMethodName; + private final String implMethodSignature; + private final int implMethodKind; + private final String instantiatedMethodType; + private final Object[] capturedArgs; + + /** + * Create a {@code SerializedLambda} from the low-level information present at the lambda factory site. + * + * @param capturingClass The class in which the lambda expression appears + * @param functionalInterfaceMethodKind Method handle kind (see {@link MethodHandleInfo}) for the + * functional interface method handle present at the lambda factory site + * @param functionalInterfaceClass Name, in slash-delimited form, for the functional interface class present at the + * lambda factory site + * @param functionalInterfaceMethodName Name of the primary method for the functional interface present at the + * lambda factory site + * @param functionalInterfaceMethodSignature Signature of the primary method for the functional interface present + * at the lambda factory site + * @param implMethodKind Method handle kind for the implementation method + * @param implClass Name, in slash-delimited form, for the class holding the implementation method + * @param implMethodName Name of the implementation method + * @param implMethodSignature Signature of the implementation method + * @param instantiatedMethodType The signature of the primary functional interface method after type variables + * are substituted with their instantiation from the capture site + * @param capturedArgs The dynamic arguments to the lambda factory site, which represent variables captured by + * the lambda + */ + public SerializedLambda(String capturingClass, + int functionalInterfaceMethodKind, + String functionalInterfaceClass, + String functionalInterfaceMethodName, + String functionalInterfaceMethodSignature, + int implMethodKind, + String implClass, + String implMethodName, + String implMethodSignature, + String instantiatedMethodType, + Object[] capturedArgs) { + this.capturingClass = capturingClass; + this.functionalInterfaceMethodKind = functionalInterfaceMethodKind; + this.functionalInterfaceClass = functionalInterfaceClass; + this.functionalInterfaceMethodName = functionalInterfaceMethodName; + this.functionalInterfaceMethodSignature = functionalInterfaceMethodSignature; + this.implMethodKind = implMethodKind; + this.implClass = implClass; + this.implMethodName = implMethodName; + this.implMethodSignature = implMethodSignature; + this.instantiatedMethodType = instantiatedMethodType; + this.capturedArgs = Objects.requireNonNull(capturedArgs).clone(); + } + + /** Get the name of the class that captured this lambda */ + public String getCapturingClass() { + return capturingClass; + } + + /** Get the name of the functional interface class to which this lambda has been converted */ + public String getFunctionalInterfaceClass() { + return functionalInterfaceClass; + } + + /** Get the name of the primary method for the functional interface to which this lambda has been converted */ + public String getFunctionalInterfaceMethodName() { + return functionalInterfaceMethodName; + } + + /** Get the signature of the primary method for the functional interface to which this lambda has been converted */ + public String getFunctionalInterfaceMethodSignature() { + return functionalInterfaceMethodSignature; + } + + /** Get the method handle kind (see {@link MethodHandleInfo}) of the primary method for the functional interface + * to which this lambda has been converted */ + public int getFunctionalInterfaceMethodKind() { + return functionalInterfaceMethodKind; + } + + /** Get the name of the class containing the implementation method */ + public String getImplClass() { + return implClass; + } + + /** Get the name of the implementation method */ + public String getImplMethodName() { + return implMethodName; + } + + /** Get the signature of the implementation method */ + public String getImplMethodSignature() { + return implMethodSignature; + } + + /** Get the method handle kind (see {@link MethodHandleInfo}) of the implementation method */ + public int getImplMethodKind() { + return implMethodKind; + } + + /** + * Get the signature of the primary functional interface method after type variables are substituted with + * their instantiation from the capture site + */ + public final String getInstantiatedMethodType() { + return instantiatedMethodType; + } + + /** Get the count of dynamic arguments to the lambda capture site */ + public int getCapturedArgCount() { + return capturedArgs.length; + } + + /** Get a dynamic argument to the lambda capture site */ + public Object getCapturedArg(int i) { + return capturedArgs[i]; + } + + private Object readResolve() throws ReflectiveOperationException { + try { + Method deserialize = AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Method run() throws Exception { + Class clazz = Class.forName(capturingClass.replace('/', '.'), true, + Thread.currentThread().getContextClassLoader()); + Method m = clazz.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class); + m.setAccessible(true); + return m; + } + }); + + return deserialize.invoke(null, this); + } + catch (PrivilegedActionException e) { + Exception cause = e.getException(); + if (cause instanceof ReflectiveOperationException) + throw (ReflectiveOperationException) cause; + else if (cause instanceof RuntimeException) + throw (RuntimeException) cause; + else + throw new RuntimeException("Exception in SerializedLambda.readResolve", e); + } + } + + @Override + public String toString() { + return String.format("SerializedLambda[capturingClass=%s, functionalInterfaceMethod=%s %s.%s:%s, " + + "implementation=%s %s.%s:%s, instantiatedMethodType=%s, numCaptured=%d]", + capturingClass, MethodHandleInfo.getReferenceKindString(functionalInterfaceMethodKind), + functionalInterfaceClass, functionalInterfaceMethodName, functionalInterfaceMethodSignature, + MethodHandleInfo.getReferenceKindString(implMethodKind), implClass, implMethodName, + implMethodSignature, instantiatedMethodType, capturedArgs.length); + } + + /* + // @@@ Review question: is it worthwhile implementing a versioned serialization protocol? + + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + } + + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + } +*/ +} diff --git a/jdk/src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java b/jdk/src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java index 7384bee464c..3aa63c84ae7 100644 --- a/jdk/src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java +++ b/jdk/src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java @@ -27,6 +27,7 @@ package java.lang.invoke; import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.Type; import sun.invoke.util.Wrapper; import static sun.invoke.util.Wrapper.*; @@ -49,6 +50,9 @@ class TypeConvertingMethodAdapter extends MethodVisitor { private static final Wrapper[] FROM_WRAPPER_NAME = new Wrapper[16]; + // Table of wrappers for primitives, indexed by ASM type sorts + private static final Wrapper[] FROM_TYPE_SORT = new Wrapper[16]; + static { for (Wrapper w : Wrapper.values()) { if (w.basicTypeChar() != 'L') { @@ -71,6 +75,15 @@ class TypeConvertingMethodAdapter extends MethodVisitor { initWidening(DOUBLE, Opcodes.I2D, BYTE, SHORT, INT, CHAR); initWidening(DOUBLE, Opcodes.F2D, FLOAT); initWidening(DOUBLE, Opcodes.L2D, LONG); + + FROM_TYPE_SORT[Type.BYTE] = Wrapper.BYTE; + FROM_TYPE_SORT[Type.SHORT] = Wrapper.SHORT; + FROM_TYPE_SORT[Type.INT] = Wrapper.INT; + FROM_TYPE_SORT[Type.LONG] = Wrapper.LONG; + FROM_TYPE_SORT[Type.CHAR] = Wrapper.CHAR; + FROM_TYPE_SORT[Type.FLOAT] = Wrapper.FLOAT; + FROM_TYPE_SORT[Type.DOUBLE] = Wrapper.DOUBLE; + FROM_TYPE_SORT[Type.BOOLEAN] = Wrapper.BOOLEAN; } private static void initWidening(Wrapper to, int opcode, Wrapper... from) { @@ -124,8 +137,9 @@ class TypeConvertingMethodAdapter extends MethodVisitor { return "()" + w.basicTypeChar(); } - void boxIfPrimitive(Wrapper w) { - if (w.zero() != null) { + void boxIfTypePrimitive(Type t) { + Wrapper w = FROM_TYPE_SORT[t.getSort()]; + if (w != null) { box(w); } } @@ -264,4 +278,22 @@ class TypeConvertingMethodAdapter extends MethodVisitor { } } } + + /** + * The following method is copied from + * org.objectweb.asm.commons.InstructionAdapter. Part of ASM: a very small + * and fast Java bytecode manipulation framework. + * Copyright (c) 2000-2005 INRIA, France Telecom All rights reserved. + */ + void iconst(final int cst) { + if (cst >= -1 && cst <= 5) { + mv.visitInsn(Opcodes.ICONST_0 + cst); + } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) { + mv.visitIntInsn(Opcodes.BIPUSH, cst); + } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) { + mv.visitIntInsn(Opcodes.SIPUSH, cst); + } else { + mv.visitLdcInsn(cst); + } + } } diff --git a/jdk/test/java/lang/invoke/lambda/LambdaSerialization.java b/jdk/test/java/lang/invoke/lambda/LambdaSerialization.java new file mode 100644 index 00000000000..1e7ba6dbe5b --- /dev/null +++ b/jdk/test/java/lang/invoke/lambda/LambdaSerialization.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2013, 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 8004970 +@summary Lambda serialization + +*/ + +import java.io.*; + +public class LambdaSerialization { + + static int assertionCount = 0; + + static void assertTrue(boolean cond) { + assertionCount++; + if (!cond) + throw new AssertionError(); + } + + public static void main(String[] args) throws Exception { + try { + // Write lambdas out + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutput out = new ObjectOutputStream(baos); + + write(out, z -> "[" + z + "]" ); + write(out, z -> z + z ); + write(out, z -> "blah" ); + out.flush(); + out.close(); + + // Read them back + ByteArrayInputStream bais = + new ByteArrayInputStream(baos.toByteArray()); + ObjectInputStream in = new ObjectInputStream(bais); + readAssert(in, "[X]"); + readAssert(in, "XX"); + readAssert(in, "blah"); + in.close(); + } catch (IOException e) { + e.printStackTrace(); + throw e; + } + assertTrue(assertionCount == 3); + } + + static void write(ObjectOutput out, LSI lamb) throws IOException { + out.writeObject(lamb); + } + + static void readAssert(ObjectInputStream in, String expected) throws IOException, ClassNotFoundException { + LSI ls = (LSI) in.readObject(); + String result = ls.convert("X"); + System.out.printf("Result: %s\n", result); + assertTrue(result.equals(expected)); + } +} + +interface LSI extends Serializable { + String convert(String x); +} From c64f5833d2a76756309b2f4a71b4ee3090f98d94 Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Sun, 17 Feb 2013 01:01:15 +0000 Subject: [PATCH 067/180] 8008348: The leftover jdk/make/tools/javazic causes build problems with hs25-b19 control To remove jdk/make/tools/javazic from the jdk repo Reviewed-by: alanb --- jdk/make/tools/javazic/Makefile | 43 - .../src/build/tools/javazic/BackEnd.java | 70 -- .../src/build/tools/javazic/Checksum.java | 69 -- .../src/build/tools/javazic/DayOfWeek.java | 56 -- .../tools/src/build/tools/javazic/Gen.java | 347 -------- .../tools/src/build/tools/javazic/GenDoc.java | 781 ------------------ .../tools/src/build/tools/javazic/Main.java | 238 ------ .../src/build/tools/javazic/Mappings.java | 197 ----- .../tools/src/build/tools/javazic/Month.java | 94 --- .../tools/src/build/tools/javazic/Rule.java | 184 ----- .../src/build/tools/javazic/RuleDay.java | 190 ----- .../src/build/tools/javazic/RuleRec.java | 232 ------ .../tools/src/build/tools/javazic/Simple.java | 188 ----- .../tools/src/build/tools/javazic/Time.java | 343 -------- .../src/build/tools/javazic/Timezone.java | 454 ---------- .../tools/src/build/tools/javazic/Zone.java | 168 ---- .../src/build/tools/javazic/ZoneRec.java | 252 ------ .../src/build/tools/javazic/Zoneinfo.java | 569 ------------- 18 files changed, 4475 deletions(-) delete mode 100644 jdk/make/tools/javazic/Makefile delete mode 100644 jdk/make/tools/src/build/tools/javazic/BackEnd.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/Checksum.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/DayOfWeek.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/Gen.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/GenDoc.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/Main.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/Mappings.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/Month.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/Rule.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/RuleDay.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/RuleRec.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/Simple.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/Time.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/Timezone.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/Zone.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/ZoneRec.java delete mode 100644 jdk/make/tools/src/build/tools/javazic/Zoneinfo.java diff --git a/jdk/make/tools/javazic/Makefile b/jdk/make/tools/javazic/Makefile deleted file mode 100644 index 4545c4d491c..00000000000 --- a/jdk/make/tools/javazic/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# -# Copyright (c) 1998, 2005, 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. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# 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. -# - -# -# Makefile for building the javazic tool -# - -BUILDDIR = ../.. -PACKAGE = build.tools.javazic -PRODUCT = javazic -PROGRAM = javazic -include $(BUILDDIR)/common/Defs.gmk - -BUILDTOOL_SOURCE_ROOT = $(BUILDDIR)/tools/src -BUILDTOOL_MAIN = $(PKGDIR)/Main.java - -# -# Build tool jar rules. -# -include $(BUILDDIR)/common/BuildToolJar.gmk - diff --git a/jdk/make/tools/src/build/tools/javazic/BackEnd.java b/jdk/make/tools/src/build/tools/javazic/BackEnd.java deleted file mode 100644 index bfeda032037..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/BackEnd.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2000, 2004, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -/** - * BackEnd is an abstract base class for a back-end of compiling - * Olson's zoneinfo database and generating Java zoneinfo database. - * - * @since 1.4 - */ -abstract class BackEnd { - - /** - * Receives each zone's TimeZone information which was created by - * {@link Zoneinfo#parse} in class Zoneinfo, - * and processes it. - * - * @param tz Timezone object for each zone - * @return 0 if no error occurred, otherwise 1. - */ - abstract int processZoneinfo(Timezone tz); - - /** - * Receives whole information which is generated by JavaZic's front-end - * in the form of Mapping object and generates all Java zone information - * files. - * - * @param m Mappings object which is generated by - * {@link Main#compile() Main.compile()}. - * @return 0 if no error occurred, otherwise 1. - */ - abstract int generateSrc(Mappings m); - - /** - * Decides which backend class should be used and returns its instance. - * @return an instance of backend class - */ - static BackEnd getBackEnd() { - if (Zoneinfo.isYearForTimeZoneDataSpecified) { - return new Simple(); - } else if (Main.outputDoc) { - return new GenDoc(); - } else { - return new Gen(); - } - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/Checksum.java b/jdk/make/tools/src/build/tools/javazic/Checksum.java deleted file mode 100644 index 565395d5c8d..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/Checksum.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2000, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -import java.util.zip.CRC32; - -/** - * Checksum provides methods for calculating a CRC32 value for a - * transitions table. - * - * @since 1.4 - */ -public class Checksum extends CRC32 -{ - /** - * Updates the CRC32 value from each byte of the given int - * value. The bytes are used in the big endian order. - * @param val the int value - */ - public void update(int val) { - byte[] b = new byte[4]; - b[0] = (byte)((val >>> 24) & 0xff); - b[1] = (byte)((val >>> 16) & 0xff); - b[2] = (byte)((val >>> 8) & 0xff); - b[3] = (byte)(val & 0xff); - update(b); - } - - /** - * Updates the CRC32 value from each byte of the given long - * value. The bytes are used in the big endian order. - * @param val the long value - */ - void update(long val) { - byte[] b = new byte[8]; - b[0] = (byte)((val >>> 56) & 0xff); - b[1] = (byte)((val >>> 48) & 0xff); - b[2] = (byte)((val >>> 40) & 0xff); - b[3] = (byte)((val >>> 32) & 0xff); - b[4] = (byte)((val >>> 24) & 0xff); - b[5] = (byte)((val >>> 16) & 0xff); - b[6] = (byte)((val >>> 8) & 0xff); - b[7] = (byte)(val & 0xff); - update(b); - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/DayOfWeek.java b/jdk/make/tools/src/build/tools/javazic/DayOfWeek.java deleted file mode 100644 index 9df8163fe5e..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/DayOfWeek.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2004, 2006, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -/** - * Day of week enum. - * - * @since 1.6 - */ - -enum DayOfWeek { - SUNDAY("Sun"), - MONDAY("Mon"), - TUESDAY("Tue"), - WEDNESDAY("Wed"), - THURSDAY("Thu"), - FRIDAY("Fri"), - SATURDAY("Sat"); - - private final String abbr; - - private DayOfWeek(String abbr) { - this.abbr = abbr; - } - - String getAbbr() { - return abbr; - } - - int value() { - return ordinal() + 1; - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/Gen.java b/jdk/make/tools/src/build/tools/javazic/Gen.java deleted file mode 100644 index 8f3a8c5a37a..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/Gen.java +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -import java.io.IOException; -import java.io.File; -import java.io.FileOutputStream; -import java.io.DataOutputStream; -import java.io.RandomAccessFile; -import java.util.List; -import java.util.Map; -import java.util.Set; -import sun.util.calendar.ZoneInfoFile; - -/** - * Gen is one of back-end classes of javazic, and generates - * ZoneInfoMappings and zone-specific file for each zone. - */ -class Gen extends BackEnd { - - /** - * Generates datafile in binary TLV format for each time zone. - * Regarding contents of output files, see {@link ZoneInfoFile}. - * - * @param Timezone - * @return 0 if no errors, or 1 if error occurred. - */ - int processZoneinfo(Timezone tz) { - try { - int size; - String outputDir = Main.getOutputDir(); - String zonefile = ZoneInfoFile.getFileName(tz.getName()); - - /* If outputDir doesn't end with file-separator, adds it. */ - if (!outputDir.endsWith(File.separator)) { - outputDir += File.separatorChar; - } - - /* If zonefile includes file-separator, it's treated as part of - * pathname. And make directory if necessary. - */ - int index = zonefile.lastIndexOf(File.separatorChar); - if (index != -1) { - outputDir += zonefile.substring(0, index+1); - } - File outD = new File(outputDir); - outD.mkdirs(); - - FileOutputStream fos = - new FileOutputStream(outputDir + zonefile.substring(index+1)); - DataOutputStream dos = new DataOutputStream(fos); - - /* Output Label */ - dos.write(ZoneInfoFile.JAVAZI_LABEL, 0, - ZoneInfoFile.JAVAZI_LABEL.length); - - /* Output Version of ZoneInfoFile */ - dos.writeByte(ZoneInfoFile.JAVAZI_VERSION); - - List transitions = tz.getTransitions(); - if (transitions != null) { - List dstOffsets = tz.getDstOffsets(); - List offsets = tz.getOffsets(); - - if ((dstOffsets == null && offsets != null) || - (dstOffsets != null && offsets == null)) { - Main.panic("Data not exist. (dstOffsets or offsets)"); - return 1; - } - - /* Output Transition records */ - dos.writeByte(ZoneInfoFile.TAG_Transition); - size = transitions.size(); - dos.writeShort((size * 8) & 0xFFFF); - int dstoffset; - for (int i = 0; i < size; i++) { - /* if DST offset is 0, this means DST isn't used. - * (NOT: offset's index is 0.) - */ - if ((dstoffset = dstOffsets.get(i).intValue()) == -1) { - dstoffset = 0; - } - - dos.writeLong((transitions.get(i).longValue() << 12) - | (dstoffset << 4) - | offsets.get(i).intValue()); - - } - - /* Output data for GMTOffset */ - List gmtoffset = tz.getGmtOffsets(); - dos.writeByte(ZoneInfoFile.TAG_Offset); - size = gmtoffset.size(); - dos.writeShort((size * 4) & 0xFFFF); - for (int i = 0; i < size; i++) { - dos.writeInt(gmtoffset.get(i)); - } - } - - /* Output data for SimpleTimeZone */ - List stz = tz.getLastRules(); - if (stz != null) { - RuleRec[] rr = new RuleRec[2]; - boolean wall = true; - - rr[0] = stz.get(0); - rr[1] = stz.get(1); - - dos.writeByte(ZoneInfoFile.TAG_SimpleTimeZone); - wall = rr[0].getTime().isWall() && rr[1].getTime().isWall(); - if (wall) { - dos.writeShort(32); - } else { - dos.writeShort(40); - } - - for (int i = 0; i < 2; i++) { - dos.writeInt(rr[i].getMonthNum() - 1); // 0-based month number - dos.writeInt(rr[i].getDay().getDayForSimpleTimeZone()); - dos.writeInt(rr[i].getDay().getDayOfWeekForSimpleTimeZoneInt()); - dos.writeInt((int)rr[i].getTime().getTime()); - if (!wall) { - dos.writeInt((rr[i].getTime().getType() & 0xFF) - 1); - } - } - } - - /* Output RawOffset */ - dos.writeByte(ZoneInfoFile.TAG_RawOffset); - dos.writeShort(4); - dos.writeInt(tz.getRawOffset()); - - /* Output willGMTOffsetChange flag */ - if (tz.willGMTOffsetChange()) { - dos.writeByte(ZoneInfoFile.TAG_GMTOffsetWillChange); - dos.writeShort(1); - dos.writeByte(1); - } - - /* Output LastDSTSaving */ - dos.writeByte(ZoneInfoFile.TAG_LastDSTSaving); - dos.writeShort(2); - dos.writeShort(tz.getLastDSTSaving()/1000); - - /* Output checksum */ - dos.writeByte(ZoneInfoFile.TAG_CRC32); - dos.writeShort(4); - dos.writeInt(tz.getCRC32()); - - fos.close(); - dos.close(); - } catch(IOException e) { - Main.panic("IO error: "+e.getMessage()); - return 1; - } - - return 0; - } - - /** - * Generates ZoneInfoMappings in binary TLV format for each zone. - * Regarding contents of output files, see {@link ZoneInfoFile}. - * - * @param Mappings - * @return 0 if no errors, or 1 if error occurred. - */ - int generateSrc(Mappings map) { - try { - int index; - int block_size; - int roi_size; - long fp; - String outputDir = Main.getOutputDir(); - - /* If outputDir doesn't end with file-separator, adds it. */ - if (!outputDir.endsWith(File.separator)) { - outputDir += File.separatorChar; - } - - File outD = new File(outputDir); - outD.mkdirs(); - - /* Open ZoneInfoMapping file to write. */ - RandomAccessFile raf = - new RandomAccessFile(outputDir + ZoneInfoFile.JAVAZM_FILE_NAME, "rw"); - - /* Whether rawOffsetIndex list exists or not. */ - List roi = map.getRawOffsetsIndex(); - if (roi == null) { - Main.panic("Data not exist. (rawOffsetsIndex)"); - return 1; - } - roi_size = roi.size(); - - /* Whether rawOffsetIndexTable list exists or not. */ - List> roit = map.getRawOffsetsIndexTable(); - if (roit == null || roit.size() != roi_size) { - Main.panic("Data not exist. (rawOffsetsIndexTable) Otherwise, Invalid size"); - return 1; - } - - /* Output Label */ - raf.write(ZoneInfoFile.JAVAZM_LABEL, 0, - ZoneInfoFile.JAVAZM_LABEL.length); - - /* Output Version */ - raf.writeByte(ZoneInfoFile.JAVAZM_VERSION); - - index = ZoneInfoFile.JAVAZM_LABEL.length + 2; - - /* Output Version of Olson's tzdata */ - byte[] b = Main.getVersionName().getBytes("UTF-8"); - raf.writeByte(ZoneInfoFile.TAG_TZDataVersion); - raf.writeShort((b.length+1) & 0xFFFF); - raf.write(b); - raf.writeByte(0x00); - index += b.length + 4; - - /* Output ID list. */ - raf.writeByte(ZoneInfoFile.TAG_ZoneIDs); - block_size = 2; - raf.writeShort(block_size & 0xFFFF); - short nID = 0; - raf.writeShort(nID & 0xFFFF); - for (int i = 0; i < roi_size; i++) { - for (String key : roit.get(i)) { - byte size = (byte)key.getBytes("UTF-8").length; - raf.writeByte(size & 0xFF); - raf.write(key.getBytes("UTF-8"), 0, size); - block_size += 1 + size; - nID++; - } - } - fp = raf.getFilePointer(); - raf.seek(index); - raf.writeShort((block_size) & 0xFFFF); - raf.writeShort(nID & 0xFFFF); - raf.seek(fp); - - /* Output sorted rawOffset list. */ - raf.writeByte(ZoneInfoFile.TAG_RawOffsets); - index += 3 + block_size; - block_size = roi_size * 4; - raf.writeShort(block_size & 0xFFFF); - for (int i = 0; i < roi_size; i++) { - raf.writeInt(Integer.parseInt(roi.get(i).toString())); - } - - /* Output sorted rawOffsetIndex list. */ - raf.writeByte(ZoneInfoFile.TAG_RawOffsetIndices); - index += 3 + block_size; - block_size = 0; - raf.writeShort(block_size & 0xFFFF); - int num; - for (int i = 0; i < roi_size; i++) { - num = roit.get(i).size(); - block_size += num; - for (int j = 0; j < num; j++) { - raf.writeByte(i); - } - } - fp = raf.getFilePointer(); - raf.seek(index); - raf.writeShort((block_size) & 0xFFFF); - raf.seek(fp); - - /* Whether alias list exists or not. */ - Map a = map.getAliases(); - if (a == null) { - Main.panic("Data not exist. (aliases)"); - return 0; - } - - /* Output ID list. */ - raf.writeByte(ZoneInfoFile.TAG_ZoneAliases); - index += 3 + block_size; - block_size = 2; - raf.writeShort(block_size & 0xFFFF); - raf.writeShort(a.size() & 0xFFFF); - for (String key : a.keySet()) { - String alias = a.get(key); - byte key_size = (byte)key.length(); - byte alias_size = (byte)alias.length(); - raf.writeByte(key_size & 0xFF); - raf.write(key.getBytes("UTF-8"), 0, key_size); - raf.writeByte(alias_size & 0xFF); - raf.write(alias.getBytes("UTF-8"), 0, alias_size); - block_size += 2 + key_size + alias_size; - } - fp = raf.getFilePointer(); - raf.seek(index); - raf.writeShort((block_size) & 0xFFFF); - raf.seek(fp); - - /* Output the exclude list if it exists. */ - List excludedZones = map.getExcludeList(); - if (excludedZones != null) { - raf.writeByte(ZoneInfoFile.TAG_ExcludedZones); - index += 3 + block_size; - block_size = 2; - raf.writeShort(block_size & 0xFFFF); // place holder - raf.writeShort(excludedZones.size()); // the number of excluded zones - for (String name : excludedZones) { - byte size = (byte) name.length(); - raf.writeByte(size); // byte length - raf.write(name.getBytes("UTF-8"), 0, size); // zone name - block_size += 1 + size; - } - fp = raf.getFilePointer(); - raf.seek(index); - raf.writeShort(block_size & 0xFFFF); - raf.seek(fp); - } - - /* Close ZoneInfoMapping file. */ - raf.close(); - } catch(IOException e) { - Main.panic("IO error: "+e.getMessage()); - return 1; - } - - return 0; - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/GenDoc.java b/jdk/make/tools/src/build/tools/javazic/GenDoc.java deleted file mode 100644 index c598b9b9dc5..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/GenDoc.java +++ /dev/null @@ -1,781 +0,0 @@ -/* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; -import java.util.StringTokenizer; -import java.util.TreeMap; -import java.util.TreeSet; -import sun.util.calendar.ZoneInfoFile; - -/** - * GenDoc is one of back-end classes of javazic, and generates - * index.html and other html files which prints the detailed time zone - * information for each zone. - */ -class GenDoc extends BackEnd { - - private static final String docDir = "doc"; - - private static final String header1 = - "\n" + - "\n\n\n\n" + - "Java Platform, Standard Edition - TimeZone information based on "; - private static final String header3 = - "-->\n<TITLE>\n" + - "Java Platform, Standard Edition TimeZone - "; - private static final String header4 = - "\n" + - "\n\n"; - - private static final String body1 = - "\n"; - private static final String body2 = - "\n"; - - private static final String footer = - "\n"; - - - // list of time zone name and zonefile name/real time zone name - // e.g. - // key (String) : value (String) - // "America/Denver" : "America/Denver.html" (real time zone) - // "America/Shiprock" : "America/Denver" (alias) - TreeMap timezoneList = new TreeMap(); - - // list of time zone's display name and time zone name - // e.g. - // key (String) : value (String) - // "Tokyo, Asia" : "Asia/Tokyo" - // "Marengo, Indiana, America" : "America/Indiana/Marengo" - // (aliases included) - TreeMap displayNameList = new TreeMap(); - - // list of top level regions - // e.g. - // key (String) : value (String) - // "America" : "America.html" - // (including entries in America/Indiana/, America/Kentucky/, ...) - TreeMap regionList = new TreeMap(); - - // mapping list from zone name to latitude & longitude - // This list is generated from zone.tab. - // e.g. - // key (String) : value (LatitudeAndLongitude object) - // "Asia/Tokyo" : latitude=35.3916, longitude=13.9444 - // (aliases not included) - HashMap mapList = null; - - // SortedMap of zone IDs sorted by their GMT offsets. If zone's GMT - // offset will change in the future, its last known offset is - // used. - SortedMap> zonesByOffset = new TreeMap>(); - - /** - * Generates HTML document for each zone. - * @param Timezone - * @return 0 if no errors, or 1 if error occurred. - */ - int processZoneinfo(Timezone tz) { - try { - int size; - int index; - String outputDir = Main.getOutputDir(); - String zonename = tz.getName(); - String zonefile = ZoneInfoFile.getFileName(zonename) + ".html"; - List stz = tz.getLastRules(); - timezoneList.put(zonename, zonefile); - displayNameList.put(transform(zonename), zonename); - - // Populate zonesByOffset. (Zones that will change their - // GMT offsets are also added to zonesByOffset here.) - int lastKnownOffset = tz.getRawOffset(); - Set set = zonesByOffset.get(lastKnownOffset); - if (set == null) { - set = new TreeSet(); - zonesByOffset.put(lastKnownOffset, set); - } - set.add(zonename); - - /* If outputDir doesn't end with file-separator, adds it. */ - if (!outputDir.endsWith(File.separator)) { - outputDir += File.separatorChar; - } - outputDir += docDir + File.separatorChar; - - index = zonename.indexOf('/'); - if (index != -1) { - regionList.put(zonename.substring(0, index), - zonename.substring(0, index) + ".html"); - } - - /* If zonefile includes file-separator, it's treated as part of - * pathname. And make directory if necessary. - */ - index = zonefile.lastIndexOf('/'); - if (index != -1) { - zonefile.replace('/', File.separatorChar); - outputDir += zonefile.substring(0, index+1); - } - File outD = new File(outputDir); - outD.mkdirs(); - - /* If mapfile is available, add a link to the appropriate map */ - if ((mapList == null) && (Main.getMapFile() != null)) { - FileReader fr = new FileReader(Main.getMapFile()); - BufferedReader in = new BufferedReader(fr); - mapList = new HashMap(); - String line; - while ((line = in.readLine()) != null) { - // skip blank and comment lines - if (line.length() == 0 || line.charAt(0) == '#') { - continue; - } - StringTokenizer tokens = new StringTokenizer(line); - String token = tokens.nextToken(); /* We don't use the first token. */ - token = tokens.nextToken(); - LatitudeAndLongitude location = new LatitudeAndLongitude(token); - token = tokens.nextToken(); - mapList.put(token, location); - } - in.close(); - } - - /* Open zoneinfo file to write. */ - FileWriter fw = new FileWriter(outputDir + zonefile.substring(index+1)); - BufferedWriter out = new BufferedWriter(fw); - - out.write(header1 + new Date() + header3 + zonename + header4); - out.write(body1 + "" + zonename + ""); - LatitudeAndLongitude location = mapList.get(zonename); - if (location != null) { - int deg, min, sec; - - deg = location.getLatDeg(); - min = location.getLatMin(); - sec = location.getLatSec(); - if (deg < 0) { - min = -min; - sec = -sec; - } else if (min < 0) { - sec = -sec; - } - out.write("   " + - "[map]"); - } - out.write("\n

    \n"); - - List zone = tz.getZones(); - List rule = tz.getRules(); - if (rule != null && zone != null) { - out.write("\n" + - "\n" + - "\n" + - "\n" + - "\n

    " + - "Rules
    " + - "
    Zone
    \n"); - } - - /* Output Rule records. */ - if (rule != null) { - size = rule.size(); - out.write("

    \n" + - "Rules\n" + - "\n" + - "\n" + - "" + - "" + - "\n\n"); - for (int i = 0; i < size; i++) { - out.write("\n"); - StringTokenizer st = new StringTokenizer(rule.get(i).getLine()); - String s; - if (st.hasMoreTokens()) { /* RULE - truncated */ - st.nextToken(); - } - if (st.hasMoreTokens()) { /* NAME */ - out.write(""); - } - if (st.hasMoreTokens()) { /* FROM */ - out.write(""); - } - if (st.hasMoreTokens()) { /* TO */ - s = st.nextToken(); - if (s.equals("min") || s.equals("max")) { - out.write(""); - } else { - out.write(""); - } - } - if (st.hasMoreTokens()) { /* TYPE */ - out.write(""); - } - if (st.hasMoreTokens()) { /* IN */ - out.write(""); - } - if (st.hasMoreTokens()) { /* ON */ - out.write(""); - } - if (st.hasMoreTokens()) { /* AT */ - out.write(""); - } - if (st.hasMoreTokens()) { /* SAVE */ - out.write(""); - } - if (st.hasMoreTokens()) { /* LETTER/S */ - out.write(""); - } - if (st.hasMoreTokens()) { /* NOTES */ - s = st.nextToken(); - while (st.hasMoreTokens()) { - s += " " + st.nextToken(); - } - index = s.indexOf('#'); - out.write("\n"); - } else { - out.write("\n"); - } - out.write("\n"); - } - out.write("
    NAMEFROMTOTYPEINONATSAVELETTER/SNOTES
    " + st.nextToken() + "" + st.nextToken() + "" + s + "" + s + "" + st.nextToken() + "" + st.nextToken() + "" + st.nextToken() + "" + st.nextToken() + "" + st.nextToken() + "" + st.nextToken() + "" + s.substring(index+1) + " 
    \n

     

    \n"); - } - - /* Output Zone records. */ - if (zone != null) { - size = zone.size(); - out.write("

    \n" + - "Zone\n" + - "\n" + - "\n" + - "" + - "\n\n"); - for (int i = 0; i < size; i++) { - out.write("\n"); - StringTokenizer st = new StringTokenizer(zone.get(i).getLine()); - String s = st.nextToken(); - if (s.equals("Zone")) { /* NAME */ - s = st.nextToken(); - s = st.nextToken(); - } - out.write(""); /* GMTOFFSET */ - if (st.hasMoreTokens()) { /* RULES */ - out.write(""); - } - if (st.hasMoreTokens()) { /* FORMAT */ - s = st.nextToken(); - index = s.indexOf('#'); - if (index != -1) { - if (index != 0) { - out.write(""); /* FORMAT */ - s = s.substring(index+1); - } else { - out.write(""); /* FORMAT */ - } - while (st.hasMoreTokens()) { - s += " " + st.nextToken(); - } - out.write(""); /* UNTIL */ - out.write("\n\n"); /* NOTES */ - continue; - } else { - out.write(""); /* FORMAT */ - } - } - - if (st.hasMoreTokens()) { /* UNTIL */ - s = st.nextToken(); - while (st.hasMoreTokens()) { - s += " " + st.nextToken(); - } - index = s.indexOf('#'); - if (index != -1) { - if (index != 0) { - out.write(""); /* UNTIL */ - } else { - out.write(""); /* UNTIL */ - } - out.write("\n"); /* NOTES */ - } else { - out.write(""); /* UNTIL */ - out.write("\n"); /* NOTES */ - } - } else { - out.write(""); /* UNTIL */ - out.write("\n"); /* NOTES */ - } - out.write("\n"); - } - out.write("
    GMTOFFRULESFORMATUNTILNOTES
    " + s + "" + st.nextToken() + "" + s.substring(0, index-1) + - "  " + s + "
    " + s + "" + s.substring(0, index-1) + - " " + s.substring(index+1) + - "" + s + "   
    \n"); - } - out.write(body2 + footer); - - out.close(); - fw.close(); - } catch(IOException e) { - Main.panic("IO error: "+e.getMessage()); - return 1; - } - - return 0; - } - - /** - * Generates index.html and other top-level frame files. - * @param Mappings - * @return 0 if no errors, or 1 if error occurred. - */ - int generateSrc(Mappings map) { - try { - int len; - Object o[]; - String outputDir = Main.getOutputDir(); - FileWriter fw1, fw2; - BufferedWriter out1, out2; - - /* Whether alias list exists or not. */ - Map a = map.getAliases(); - if (a == null) { - Main.panic("Data not exist. (aliases)"); - return 1; - } - - timezoneList.putAll(a); - - /* If outputDir doesn't end with file-separator, adds it. */ - if (!outputDir.endsWith(File.separator)) { - outputDir += File.separatorChar; - } - outputDir += docDir + File.separatorChar; - - File outD = new File(outputDir); - outD.mkdirs(); - - /* Creates index.html */ - fw1 = new FileWriter(outputDir + "index.html", false); - out1 = new BufferedWriter(fw1); - - out1.write(header1 + new Date() + header2 + Main.getVersionName() + - header4 + - "\n" + - "\n" + - "\n" + - "\n" + - "" + - "\n" + - "\n" + - "\n" + - "<H2>\nFrame Alert\n</H2>\n\n" + - "<P>\n\n" + - "This document is designed to be viewed using the frames feature. If you see this\n" + - "message, you are using a non-frame-capable web client.\n" + - "<BR>\n" + - "Link to<A HREF=\"overview-summary.html\">Non-frame version.</A>\n" + - "\n" + footer); - - out1.close(); - fw1.close(); - - - /* Creates overview-frame.html */ - fw1 = new FileWriter(outputDir + "overview-frame.html", false); - out1 = new BufferedWriter(fw1); - - out1.write(header1 + new Date() + header2 + Main.getVersionName() + - header4 + body1 + - "\n\n" + - "\n" + - "\n
    \n" + - "JavaTM Platform
    Standard Ed.
    \n\n" + - "\n\n\n
    " + - "

    \n\nAll Time Zones Sorted By:\n
    \n" + - "  GMT offsets\n
    \n" + - "  Zone names\n
    " + - "  City names\n" + - "

    \n\nContinents and Oceans\n
    \n"); - - for (String regionKey : regionList.keySet()) { - out1.write("  " + regionKey + - "
    \n"); - - fw2 = new FileWriter(outputDir + regionList.get(regionKey), - false); - out2 = new BufferedWriter(fw2); - - out2.write(header1 + new Date() + header3 + regionKey + - header4 + body1 + "" + - regionKey + "\n
    \n\n\n\n\n
    "); - - boolean found = false; - for (String timezoneKey : timezoneList.keySet()) { - int regionIndex = timezoneKey.indexOf('/'); - if (regionIndex == -1 || - !regionKey.equals(timezoneKey.substring(0, regionIndex))) { - if (found) { - break; - } else { - continue; - } - } - - found = true; - if (a.containsKey(timezoneKey)) { - Object realName = a.get(timezoneKey); - while (a.containsKey(realName)) { - realName = a.get(realName); - } - out2.write(timezoneKey + - " (alias for " + "" + - realName + ")"); - } else { - out2.write("" + timezoneKey + - ""); - } - out2.write("
    \n"); - } - out2.write("
    \n" + body2 + footer); - - out2.close(); - fw2.close(); - } - out1.write("

    \n" + body2 + footer); - - out1.close(); - fw1.close(); - - - /* Creates allTimeZone-frame1.html (Sorted by GMT offsets) */ - fw1 = new FileWriter(outputDir + "allTimeZone-frame1.html", false); - out1 = new BufferedWriter(fw1); - - out1.write(header1 + new Date() + header2 + Main.getVersionName() + - header4 + body1 + - "Sorted by GMT offsets\n" + - "
    \n\n" + "\n" + - "\n\n\n\n\n"); - } - } - out1.write("\n\n
    \n"); - - List roi = map.getRawOffsetsIndex(); - List> roit = map.getRawOffsetsIndexTable(); - - int index = 0; - for (Integer offset : zonesByOffset.keySet()) { - int off = roi.get(index); - Set perRO = zonesByOffset.get(offset); - if (offset == off) { - // Merge aliases into zonesByOffset - perRO.addAll(roit.get(index)); - } - index++; - - for (String timezoneKey : perRO) { - out1.write("
    (" + - Time.toGMTFormat(offset.toString()) + - ")"); - - if (a.containsKey(timezoneKey)) { - Object realName = a.get(timezoneKey); - while (a.containsKey(realName)) { - realName = a.get(realName); - } - out1.write(timezoneKey + - " (alias for " + "" + realName + - ")"); - } else { - out1.write("" + timezoneKey + - ""); - } - out1.write("
    \n" + body2 + footer); - - out1.close(); - fw1.close(); - - - /* Creates allTimeZone-frame2.html (Sorted by zone names) */ - fw1 = new FileWriter(outputDir + "allTimeZone-frame2.html", false); - out1 = new BufferedWriter(fw1); - - out1.write(header1 + new Date() + header2 + Main.getVersionName() + - header4 + body1 + - "Sorted by zone names\n" + - "
    \n\n" + "\n" + - "\n\n\n
    \n"); - o = timezoneList.keySet().toArray(); - len = timezoneList.size(); - for (int i = 0; i < len; i++) { - Object timezoneKey = o[i]; - if (a.containsKey(timezoneKey)) { - Object realName = a.get(timezoneKey); - while (a.containsKey(realName)) { - realName = a.get(realName); - } - out1.write(timezoneKey + - " (alias for " + - "" + realName + - ")"); - } else { - out1.write("" + timezoneKey + - ""); - } - out1.write("
    \n"); - } - out1.write("
    \n" + body2 + footer); - - out1.close(); - fw1.close(); - - /* Creates allTimeZone-frame3.html (Sorted by city names) */ - fw1 = new FileWriter(outputDir + "allTimeZone-frame3.html", false); - out1 = new BufferedWriter(fw1); - - out1.write(header1 + new Date() + header2 + Main.getVersionName() + - header4 + body1 + - "Sorted by city names\n" + - "
    \n\n" + "\n" + - "\n\n\n
    \n"); - - Set aliasSet = a.keySet(); - len = aliasSet.size(); - String aliasNames[] = aliasSet.toArray(new String[0]); - for (int i = 0; i < len; i++) { - displayNameList.put(transform(aliasNames[i]), - aliasNames[i]); - } - - o = displayNameList.keySet().toArray(); - len = displayNameList.size(); - for (int i = 0; i < len; i++) { - Object displayName = o[i]; - Object timezoneKey = displayNameList.get(o[i]); - if (a.containsKey(timezoneKey)) { - Object realName = a.get(timezoneKey); - while (a.containsKey(realName)) { - realName = a.get(realName); - } - out1.write(displayName + - " (alias for " + - "" + realName + - ")"); - } else { - out1.write("" + displayName + - ""); - } - out1.write("
    \n"); - } - - out1.write("
    \n" + body2 + footer); - - out1.close(); - fw1.close(); - - /* Creates overview-summary.html */ - fw1 = new FileWriter(outputDir + "overview-summary.html", false); - out1 = new BufferedWriter(fw1); - - out1.write(header1 + new Date() + header2 + Main.getVersionName() + - header4 + body1 + - "

    This is the list of time zones generated from " + - Main.getVersionName() + " for Java Platform, " + - "Standard Edition. The source code can be obtained " + - "from ftp site " + - "ftp://elsie.nci.nih.gov/pub/. A total of " + - len + - " time zones and aliases are supported " + - "in this edition. For the " + - "format of rules and zones, refer to the zic " + - "(zoneinfo compiler) man page on " + - "Solaris or Linux.

    \n" + - "

    Note that the time zone data is not " + - "a public interface of the Java Platform. No " + - "applications should rely on the time zone data of " + - "this document. Time zone names and data " + - "may change without any prior notice.

    \n" + - body2 + footer); - - out1.close(); - fw1.close(); - } catch(IOException e) { - Main.panic("IO error: "+e.getMessage()); - return 1; - } - - return 0; - } - - String transform(String s) { - int index = s.lastIndexOf("/"); - - /* If the string doesn't include any delimiter, return */ - if (index == -1) { - return s; - } - - int lastIndex = index; - String str = s.substring(index+1); - do { - index = s.substring(0, lastIndex).lastIndexOf('/'); - str += ", " + s.substring(index+1, lastIndex); - lastIndex = index; - } while (index > -1); - - return str; - } - - static class LatitudeAndLongitude { - - private int latDeg, latMin, latSec, longDeg, longMin, longSec; - - LatitudeAndLongitude(String s) { - try { - // First of all, check the string has the correct format: - // either +-DDMM+-DDDMM or +-DDMMSS+-DDDMMSS - - if (!s.startsWith("+") && !s.startsWith("-")) { - Main.warning("Wrong latitude&longitude data: " + s); - return; - } - int index; - if (((index = s.lastIndexOf("+")) <= 0) && - ((index = s.lastIndexOf("-")) <= 0)) { - Main.warning("Wrong latitude&longitude data: " + s); - return; - } - - if (index == 5) { - latDeg = Integer.parseInt(s.substring(1, 3)); - latMin = Integer.parseInt(s.substring(3, 5)); - latSec = 0; - } else if (index == 7) { - latDeg = Integer.parseInt(s.substring(1, 3)); - latMin = Integer.parseInt(s.substring(3, 5)); - latSec = Integer.parseInt(s.substring(5, 7)); - } else { - Main.warning("Wrong latitude&longitude data: " + s); - return; - } - if (s.startsWith("-")){ - latDeg = -latDeg; - latMin = -latMin; - latSec = -latSec; - } - - int len = s.length(); - if (index == 5 && len == 11) { - longDeg = Integer.parseInt(s.substring(index+1, index+4)); - longMin = Integer.parseInt(s.substring(index+4, index+6)); - longSec = 0; - } else if (index == 7 && len == 15) { - longDeg = Integer.parseInt(s.substring(index+1, index+4)); - longMin = Integer.parseInt(s.substring(index+4, index+6)); - longSec = Integer.parseInt(s.substring(index+6, index+8)); - } else { - Main.warning("Wrong latitude&longitude data: " + s); - return; - } - if (s.charAt(index) == '-'){ - longDeg = -longDeg; - longMin = -longMin; - longSec = -longSec; - } - } catch(Exception e) { - Main.warning("LatitudeAndLongitude() Parse error: " + s); - } - } - - int getLatDeg() { - return latDeg; - } - - int getLatMin() { - return latMin; - } - - int getLatSec() { - return latSec; - } - - int getLongDeg() { - return longDeg; - } - - int getLongMin() { - return longMin; - } - - int getLongSec() { - return longSec; - } - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/Main.java b/jdk/make/tools/src/build/tools/javazic/Main.java deleted file mode 100644 index a91ab91fff8..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/Main.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -import java.util.ArrayList; -import java.util.List; - -/** - * Main class for the javazic time zone data compiler. - * - * @since 1.4 - */ -public class Main { - - private static boolean verbose = false; - static boolean outputDoc = false; - - private List ziFiles = new ArrayList(); - private static String zoneNamesFile = null; - private static String versionName = "unknown"; - private static String outputDir = "zoneinfo"; - private static String mapFile = null; - - /** - * Parses the specified arguments and sets up the variables. - * @param argv the arguments - */ - void processArgs(String[] argv) { - for (int i = 0; i < argv.length; i++) { - String arg = argv[i]; - if (arg.startsWith("-h")) { - usage(); - System.exit(0); - } else if (arg.equals("-d")) { - outputDir = argv[++i]; - } else if (arg.equals("-v")) { - verbose = true; - } else if (arg.equals("-V")) { - versionName = argv[++i]; - } else if (arg.equals("-doc")) { - outputDoc = true; - } else if (arg.equals("-map")) { - outputDoc = true; - mapFile = argv[++i]; - } else if (arg.equals("-f")) { - zoneNamesFile = argv[++i]; - } else if (arg.equals("-S")) { - try { - Zoneinfo.setYear(Integer.parseInt(argv[++i])); - } catch (Exception e) { - error("invalid year: " + argv[i]); - usage(); - System.exit(1); - } - } else { - boolean isStartYear = arg.equals("-s"); - if (isStartYear || arg.equals("-e")) { - try { - int year = Integer.parseInt(argv[++i]); - if (isStartYear) { - Zoneinfo.setStartYear(year); - } else { - Zoneinfo.setEndYear(year); - } - } catch (Exception e) { - error("invalid year: " + argv[i]); - usage(); - System.exit(1); - } - } else { - // the rest of args are zoneinfo source files - while (i < argv.length) { - ziFiles.add(argv[i++]); - } - } - } - } - } - - /** - * Parses zoneinfo source files - */ - int compile() { - int nFiles = ziFiles.size(); - int status = 0; - Mappings maps = new Mappings(); - BackEnd backend = BackEnd.getBackEnd(); - - for (int i = 0; i < nFiles; i++) { - Zoneinfo frontend = Zoneinfo.parse(ziFiles.get(i)); - - for (String key : frontend.getZones().keySet()) { - info(key); - - Timezone tz = frontend.phase2(key); - status |= backend.processZoneinfo(tz); - } - - maps.add(frontend); - } - - // special code for dealing with the conflicting name "MET" - Zone.addMET(); - - maps.resolve(); - - status |= backend.generateSrc(maps); - - return status; - } - - public static void main(String[] argv) { - Main zic = new Main(); - - /* - * Parse args - */ - zic.processArgs(argv); - - /* - * Read target zone names - */ - if (zoneNamesFile != null) { - Zone.readZoneNames(zoneNamesFile); - } - - int status = zic.compile(); - - System.exit(status); - } - - void usage() { - System.err.println("Usage: javazic [options] file...\n"+ - " -f namefile file containing zone names\n"+ - " to be generated (ie, generating subset)\n"+ - " -d dir output directory\n"+ - " -v verbose\n"+ - " -V datavers specifies the tzdata version string\n"+ - " (eg, \"tzdata2000g\")"+ - " -S year output only SimleTimeZone data of that year\n"+ - " -s year start year (default: 1900)\n"+ - " -e year end year (default: 2037)\n"+ - " -doc generates HTML documents\n"+ - " -map mapfile generates HTML documents with map information\n"+ - " file... zoneinfo source file(s)"); - } - - /** - * @return the output directory path name - */ - static String getOutputDir() { - return outputDir; - } - - /** - * @return the map file's path and name - */ - static String getMapFile() { - return mapFile; - } - - /** - * Returns the time zone data version string specified by the -V - * option. If it is not specified, "unknown" is returned. - * @return the time zone data version string - */ - static String getVersionName() { - return versionName; - } - - /** - * Prints out the specified fatal error message and calls {@link - * java.lang.System#exit System.exit(1)}. - * @param msg the fatal error message - */ - static void panic(String msg) { - printMessage("fatal error", msg); - System.exit(1); - } - - /** - * Prints out the specified error message. - * @param msg the error message - */ - static void error(String msg) { - printMessage("error", msg); - } - - /** - * Prints out the specified warning message. - * @param msg the warning message - */ - static void warning(String msg) { - printMessage("warning", msg); - } - - /** - * Prints out the informative message. - * @param msg the informative message - */ - static void info(String msg) { - if (verbose) { - printMessage(null, msg); - } - } - - private static void printMessage(String type, String msg) { - if (type != null) { - type += ": "; - } else { - type = ""; - } - System.err.println("javazic: " + type + msg); - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/Mappings.java b/jdk/make/tools/src/build/tools/javazic/Mappings.java deleted file mode 100644 index 885b9a091b6..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/Mappings.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2000, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; - -/** - * Mappings generates two Maps and a List which are used by - * javazic BackEnd. - * - * @since 1.4 - */ -class Mappings { - // All aliases specified by Link statements. It's alias name to - // real name mappings. - private Map aliases; - - private List rawOffsetsIndex; - - private List> rawOffsetsIndexTable; - - // Zone names to be excluded from rawOffset table. Those have GMT - // offsets to change some future time. - private List excludeList; - - /** - * Constructor creates some necessary instances. - */ - Mappings() { - aliases = new TreeMap(); - rawOffsetsIndex = new LinkedList(); - rawOffsetsIndexTable = new LinkedList>(); - } - - /** - * Generates aliases and rawOffsets tables. - * @param zi a Zoneinfo containing Zones - */ - void add(Zoneinfo zi) { - Map zones = zi.getZones(); - - for (String zoneName : zones.keySet()) { - Zone zone = zones.get(zoneName); - String zonename = zone.getName(); - int rawOffset = zone.get(zone.size()-1).getGmtOffset(); - - // If the GMT offset of this Zone will change in some - // future time, this Zone is added to the exclude list. - boolean isExcluded = false; - for (int i = 0; i < zone.size(); i++) { - ZoneRec zrec = zone.get(i); - if ((zrec.getGmtOffset() != rawOffset) - && (zrec.getUntilTime(0) > Time.getCurrentTime())) { - if (excludeList == null) { - excludeList = new ArrayList(); - } - excludeList.add(zone.getName()); - isExcluded = true; - break; - } - } - - if (!rawOffsetsIndex.contains(new Integer(rawOffset))) { - // Find the index to insert this raw offset zones - int n = rawOffsetsIndex.size(); - int i; - for (i = 0; i < n; i++) { - if (rawOffsetsIndex.get(i) > rawOffset) { - break; - } - } - rawOffsetsIndex.add(i, rawOffset); - - Set perRawOffset = new TreeSet(); - if (!isExcluded) { - perRawOffset.add(zonename); - } - rawOffsetsIndexTable.add(i, perRawOffset); - } else if (!isExcluded) { - int i = rawOffsetsIndex.indexOf(new Integer(rawOffset)); - Set perRawOffset = rawOffsetsIndexTable.get(i); - perRawOffset.add(zonename); - } - } - - Map a = zi.getAliases(); - // If there are time zone names which refer to any of the - // excluded zones, add those names to the excluded list. - if (excludeList != null) { - for (String zoneName : a.keySet()) { - String realname = a.get(zoneName); - if (excludeList.contains(realname)) { - excludeList.add(zoneName); - } - } - } - aliases.putAll(a); - } - - /** - * Adds valid aliases to one of per-RawOffset table and removes - * invalid aliases from aliases List. Aliases referring to - * excluded zones are not added to a per-RawOffset table. - */ - void resolve() { - int index = rawOffsetsIndexTable.size(); - List toBeRemoved = new ArrayList(); - for (String key : aliases.keySet()) { - boolean validname = false; - for (int j = 0; j < index; j++) { - Set perRO = rawOffsetsIndexTable.get(j); - boolean isExcluded = (excludeList == null) ? - false : excludeList.contains(key); - - if ((perRO.contains(aliases.get(key)) || isExcluded) - && Zone.isTargetZone(key)) { - validname = true; - if (!isExcluded) { - perRO.add(key); - Main.info("Alias <"+key+"> added to the list."); - } - break; - } - } - - if (!validname) { - Main.info("Alias <"+key+"> removed from the list."); - toBeRemoved.add(key); - } - } - - // Remove zones, if any, from the list. - for (String key : toBeRemoved) { - aliases.remove(key); - } - // Eliminate any alias-to-alias mappings. For example, if - // there are A->B and B->C, A->B is changed to A->C. - Map newMap = new HashMap(); - for (String key : aliases.keySet()) { - String realid = aliases.get(key); - String leaf = realid; - while (aliases.get(leaf) != null) { - leaf = aliases.get(leaf); - } - if (!realid.equals(leaf)) { - newMap.put(key, leaf); - } - } - aliases.putAll(newMap); - } - - Map getAliases() { - return(aliases); - } - - List getRawOffsetsIndex() { - return(rawOffsetsIndex); - } - - List> getRawOffsetsIndexTable() { - return(rawOffsetsIndexTable); - } - - List getExcludeList() { - return excludeList; - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/Month.java b/jdk/make/tools/src/build/tools/javazic/Month.java deleted file mode 100644 index 9e70808809f..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/Month.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2000, 2004, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Month enum handles month related manipulation. - * - * @since 1.4 - */ -enum Month { - JANUARY("Jan"), - FEBRUARY("Feb"), - MARCH("Mar"), - APRIL("Apr"), - MAY("May"), - JUNE("Jun"), - JULY("Jul"), - AUGUST("Aug"), - SEPTEMBER("Sep"), - OCTOBER("Oct"), - NOVEMBER("Nov"), - DECEMBER("Dec"); - - private final String abbr; - - private static final Map abbreviations - = new HashMap(12); - - static { - for (Month m : Month.values()) { - abbreviations.put(m.abbr, m); - } - } - - private Month(String abbr) { - this.abbr = abbr; - } - - int value() { - return ordinal() + 1; - } - - /** - * Parses the specified string as a month abbreviation. - * @param name the month abbreviation - * @return the Month value - */ - static Month parse(String name) { - Month m = abbreviations.get(name); - if (m != null) { - return m; - } - return null; - } - - /** - * @param month the nunmth number (1-based) - * @return the month name in uppercase of the specified month - */ - static String toString(int month) { - if (month >= JANUARY.value() && month <= DECEMBER.value()) { - return "Calendar." + Month.values()[month - 1]; - } - throw new IllegalArgumentException("wrong month number: " + month); - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/Rule.java b/jdk/make/tools/src/build/tools/javazic/Rule.java deleted file mode 100644 index c8e97fccae2..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/Rule.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2000, 2004, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.StringTokenizer; - -/** - * Rule manipulates Rule records. - * - * @since 1.4 - */ -class Rule { - - private List list; - private String name; - - /** - * Constructs a Rule which consists of a Rule record list. The - * specified name is given to this Rule. - * @param name the Rule name - */ - Rule(String name) { - this.name = name; - list = new ArrayList(); - } - - /** - * Added a RuleRec to the Rule record list. - */ - void add(RuleRec rec) { - list.add(rec); - } - - /** - * @return the Rule name - */ - String getName() { - return name; - } - - /** - * Gets all rule records that cover the given year. - * - * @param year the year number for which the rule is applicable. - * @return rules in List that are collated in time. If no rule is found, an empty - * List is returned. - */ - List getRules(int year) { - List rules = new ArrayList(3); - for (RuleRec rec : list) { - if (year >= rec.getFromYear() && year <= rec.getToYear()) { - if ((rec.isOdd() && year % 2 == 0) || (rec.isEven() && year % 2 == 1)) - continue; - rules.add(rec); - } - } - int n = rules.size(); - if (n <= 1) { - return rules; - } - if (n == 2) { - RuleRec rec1 = rules.get(0); - RuleRec rec2 = rules.get(1); - if (rec1.getMonthNum() > rec2.getMonthNum()) { - rules.set(0, rec2); - rules.set(1, rec1); - } else if (rec1.getMonthNum() == rec2.getMonthNum()) { - // TODO: it's not accurate to ignore time types (STD, WALL, UTC) - long t1 = Time.getLocalTime(year, rec1.getMonth(), - rec1.getDay(), rec1.getTime().getTime()); - long t2 = Time.getLocalTime(year, rec2.getMonth(), - rec2.getDay(), rec2.getTime().getTime()); - if (t1 > t2) { - rules.set(0, rec2); - rules.set(1, rec1); - } - } - return rules; - } - - final int y = year; - RuleRec[] recs = new RuleRec[rules.size()]; - rules.toArray(recs); - Arrays.sort(recs, new Comparator() { - public int compare(RuleRec r1, RuleRec r2) { - int n = r1.getMonthNum() - r2.getMonthNum(); - if (n != 0) { - return n; - } - // TODO: it's not accurate to ignore time types (STD, WALL, UTC) - long t1 = Time.getLocalTime(y, r1.getMonth(), - r1.getDay(), r1.getTime().getTime()); - long t2 = Time.getLocalTime(y, r2.getMonth(), - r2.getDay(), r2.getTime().getTime()); - return (int)(t1 - t2); - } - public boolean equals(Object o) { - return this == o; - } - }); - rules.clear(); - for (int i = 0; i < n; i++) { - rules.add(recs[i]); - } - return rules; - } - - /** - * Gets rule records that have either "max" or cover the endYear - * value in its DST schedule. - * - * @return rules that contain last DST schedule. An empty - * ArrayList is returned if no last rules are found. - */ - List getLastRules() { - RuleRec start = null; - RuleRec end = null; - - for (int i = 0; i < list.size(); i++) { - RuleRec rec = list.get(i); - if (rec.isLastRule()) { - if (rec.getSave() > 0) { - start = rec; - } else { - end = rec; - } - } - } - if (start == null || end == null) { - int endYear = Zoneinfo.getEndYear(); - for (int i = 0; i < list.size(); i++) { - RuleRec rec = list.get(i); - if (endYear >= rec.getFromYear() && endYear <= rec.getToYear()) { - if (start == null && rec.getSave() > 0) { - start = rec; - } else { - if (end == null && rec.getSave() == 0) { - end = rec; - } - } - } - } - } - - List r = new ArrayList(2); - if (start == null || end == null) { - if (start != null || end != null) { - Main.warning("found last rules for "+name+" inconsistent."); - } - return r; - } - - r.add(start); - r.add(end); - return r; - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/RuleDay.java b/jdk/make/tools/src/build/tools/javazic/RuleDay.java deleted file mode 100644 index 5ce43f19fce..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/RuleDay.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2000, 2010, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * RuleDay class represents the value of the "ON" field. The day of - * week values start from 1 following the {@link java.util.Calendar} - * convention. - * - * @since 1.4 - */ -class RuleDay { - private static final Map abbreviations = new HashMap(7); - static { - for (DayOfWeek day : DayOfWeek.values()) { - abbreviations.put(day.getAbbr(), day); - } - } - - private String dayName = null; - private DayOfWeek dow; - private boolean lastOne = false; - private int soonerOrLater = 0; - private int thanDayOfMonth; // day of month (e.g., 8 for "Sun>=8") - - RuleDay() { - } - - RuleDay(int day) { - thanDayOfMonth = day; - } - - int getDay() { - return thanDayOfMonth; - } - - /** - * @return the day of week value (1-based) - */ - int getDayOfWeekNum() { - return dow.value(); - } - - /** - * @return true if this rule day represents the last day of - * week. (e.g., lastSun). - */ - boolean isLast() { - return lastOne; - } - - /** - * @return true if this rule day represents the day of week on or - * later than (after) the {@link #getDay}. (e.g., Sun>=1) - */ - boolean isLater() { - return soonerOrLater > 0; - } - - /** - * @return true if this rule day represents the day of week on or - * earlier than (before) the {@link #getDay}. (e.g., Sun<=15) - */ - boolean isEarlier() { - return soonerOrLater < 0; - } - - /** - * @return true if this rule day represents an exact day. - */ - boolean isExact() { - return soonerOrLater == 0; - } - - /** - * Parses the "ON" field and constructs a RuleDay. - * @param day an "ON" field string (e.g., "Sun>=1") - * @return a RuleDay representing the given "ON" field - */ - static RuleDay parse(String day) { - RuleDay d = new RuleDay(); - if (day.startsWith("last")) { - d.lastOne = true; - d.dayName = day.substring(4); - d.dow = getDOW(d.dayName); - } else { - int index; - if ((index = day.indexOf(">=")) != -1) { - d.dayName = day.substring(0, index); - d.dow = getDOW(d.dayName); - d.soonerOrLater = 1; // greater or equal - d.thanDayOfMonth = Integer.parseInt(day.substring(index+2)); - } else if ((index = day.indexOf("<=")) != -1) { - d.dayName = day.substring(0, index); - d.dow = getDOW(d.dayName); - d.soonerOrLater = -1; // less or equal - d.thanDayOfMonth = Integer.parseInt(day.substring(index+2)); - } else { - // it should be an integer value. - d.thanDayOfMonth = Integer.parseInt(day); - } - } - return d; - } - - /** - * Converts this RuleDay to the SimpleTimeZone day rule. - * @return the converted SimpleTimeZone day rule - */ - int getDayForSimpleTimeZone() { - if (isLast()) { - return -1; - } - return isEarlier() ? -getDay() : getDay(); - } - - /** - * Converts this RuleDay to the SimpleTimeZone day-of-week rule. - * @return the SimpleTimeZone day-of-week rule value - */ - int getDayOfWeekForSimpleTimeZoneInt() { - if (isEarlier() || isLater()) { - return -getDayOfWeekNum(); - } - return isLast() ? getDayOfWeekNum() : 0; - } - - /** - * @return the string representation of the {@link - * #getDayOfWeekForSimpleTimeZoneInt} value - */ - String getDayOfWeekForSimpleTimeZone() { - int d = getDayOfWeekForSimpleTimeZoneInt(); - if (d == 0) { - return "0"; - } - String sign = ""; - if (d < 0) { - sign = "-"; - d = -d; - } - return sign + toString(d); - } - - private static DayOfWeek getDOW(String abbr) { - return abbreviations.get(abbr); - } - - /** - * Converts the specified day of week value to the day-of-week - * name defined in {@link java.util.Calenda}. - * @param dow 1-based day of week value - * @return the Calendar day of week name with "Calendar." prefix. - * @throws IllegalArgumentException if the specified dow value is out of range. - */ - static String toString(int dow) { - if (dow >= DayOfWeek.SUNDAY.value() && dow <= DayOfWeek.SATURDAY.value()) { - return "Calendar." + DayOfWeek.values()[dow - 1]; - } - throw new IllegalArgumentException("wrong Day_of_Week number: " + dow); - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/RuleRec.java b/jdk/make/tools/src/build/tools/javazic/RuleRec.java deleted file mode 100644 index 37743725729..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/RuleRec.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) 2000, 2004, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -import java.util.StringTokenizer; - -/** - * RuleRec class represents one record of the Rule set. - * - * @since 1.4 - */ -class RuleRec { - private int fromYear; - private int toYear; - private String type; - private Month inMonth; - private RuleDay onDay; - private Time atTime; - private int save; - private String letters; - private String line; - private boolean isLastRule; - - int getFromYear() { - return fromYear; - } - - int getToYear() { - return toYear; - } - - Month getMonth() { - return inMonth; - } - - int getMonthNum() { - return inMonth.value(); - } - - RuleDay getDay() { - return onDay; - } - - Time getTime() { - return atTime; - } - - int getSave() { - return save; - } - - String getLine() { - return line; - } - - /** - * Sets the line from the text file. - * @param line the text of the line - */ - void setLine(String line) { - this.line = line; - } - - /** - * @return true if the rule type is "odd". - */ - boolean isOdd() { - return "odd".equals(type); - } - - /** - * @return true if the rule type is "even". - */ - boolean isEven() { - return "even".equals(type); - } - - /** - * Determines if this rule record is the last DST schedule rule. - * - * @return true if this rule record has "max" as TO (year). - */ - boolean isLastRule() { - return isLastRule; - } - - /** - * Determines if the unadjusted until time of the specified ZoneRec - * is the same as the transition time of this rule in the same - * year as the ZoneRec until year. - * - * @param zrec ZoneRec to compare to - * @param save the amount of daylight saving in milliseconds - * @param gmtOffset the GMT offset value in milliseconds - * @return true if the unadjusted until time is the same as rule's - * transition time. - */ - boolean isSameTransition(ZoneRec zrec, int save, int gmtOffset) { - long until, transition; - - if (zrec.getUntilTime().getType() != atTime.getType()) { - until = zrec.getLocalUntilTime(save, gmtOffset); - transition = Time.getLocalTime(zrec.getUntilYear(), - getMonth(), - getDay(), - save, - gmtOffset, - atTime); - } else { - until = zrec.getLocalUntilTime(); - transition = Time.getLocalTime(zrec.getUntilYear(), - getMonth(), - getDay(), - atTime.getTime()); - } - - return until == transition; - } - - /** - * Parses a Rule line and returns a RuleRec object. - * - * @param tokens a StringTokenizer object that should contain a - * token for the "FROM" field and the rest. - * @return a RuleRec object. - */ - static RuleRec parse(StringTokenizer tokens) { - RuleRec rec = new RuleRec(); - try { - // FROM - String token = tokens.nextToken(); - try { - rec.fromYear = Integer.parseInt(token); - } catch (NumberFormatException e) { - // it's not integer - if ("min".equals(token) || "minimum".equals(token)) { - rec.fromYear = Zoneinfo.getMinYear(); - } else if ("max".equals(token) || "maximum".equals(token)) { - rec.fromYear = Zoneinfo.getMaxYear(); - } else { - Main.panic("invalid year value: "+token); - } - } - - // TO - token = tokens.nextToken(); - rec.isLastRule = false; - try { - rec.toYear = Integer.parseInt(token); - } catch (NumberFormatException e) { - // it's not integer - if ("min".equals(token) || "minimum".equals(token)) { - rec.fromYear = Zoneinfo.getMinYear(); - } else if ("max".equals(token) || "maximum".equals(token)) { - rec.toYear = Integer.MAX_VALUE; - rec.isLastRule = true; - } else if ("only".equals(token)) { - rec.toYear = rec.fromYear; - } else { - Main.panic("invalid year value: "+token); - } - } - - // TYPE - rec.type = tokens.nextToken(); - - // IN - rec.inMonth = Month.parse(tokens.nextToken()); - - // ON - rec.onDay = RuleDay.parse(tokens.nextToken()); - - // AT - rec.atTime = Time.parse(tokens.nextToken()); - - // SAVE - rec.save = (int) Time.parse(tokens.nextToken()).getTime(); - - // LETTER/S - rec.letters = tokens.nextToken(); - } catch (Exception e) { - e.printStackTrace(); - } - return rec; - } - - /** - * Calculates the transition time of the given year under this rule. - * @param year the year value - * @param gmtOffset the GMT offset value in milliseconds - * @param save the amount of daylight save time - * @return the transition time in milliseconds of the given year in UTC. - */ - long getTransitionTime(int year, int gmtOffset, int save) { - long time = Time.getLocalTime(year, getMonth(), - getDay(), atTime.getTime()); - if (atTime.isSTD()) { - time -= gmtOffset; - } else if (atTime.isWall()) { - time -= gmtOffset + save; - } - return time; - } - - private static int getInt(StringTokenizer tokens) { - String token = tokens.nextToken(); - return Integer.parseInt(token); - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/Simple.java b/jdk/make/tools/src/build/tools/javazic/Simple.java deleted file mode 100644 index 69c7fe783f5..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/Simple.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; -import java.util.TreeSet; - -/** - * Simple generates TimeZoneData, which had been used as internal - * data of TimeZone before J2SDK1.3. - * Since J2SDK1.4 doesn't need TimeZoneData, this class is for maintenance - * of old JDK release. - */ -class Simple extends BackEnd { - - /** - * Zone records which are applied for given year. - */ - private static Map lastZoneRecs = new HashMap<>(); - - /** - * Rule records which are applied for given year. - */ - private static Map> lastRules = new TreeMap<>(); - - /** - * zone IDs sorted by their GMT offsets. If zone's GMT - * offset will change in the future, its last known offset is - * used. - */ - private SortedMap> zonesByOffset = new TreeMap<>(); - - /** - * Sets last Rule records and Zone records for given timezone to - * each Map. - * - * @param tz Timezone object for each zone - * @return always 0 - */ - int processZoneinfo(Timezone tz) { - String zonename = tz.getName(); - - lastRules.put(zonename, tz.getLastRules()); - lastZoneRecs.put(zonename, tz.getLastZoneRec()); - - // Populate zonesByOffset. (Zones that will change their - // GMT offsets are also added to zonesByOffset here.) - int lastKnownOffset = tz.getRawOffset(); - Set set = zonesByOffset.get(lastKnownOffset); - if (set == null) { - set = new TreeSet<>(); - zonesByOffset.put(lastKnownOffset, set); - } - set.add(zonename); - - return 0; - } - - /** - * Generates TimeZoneData to output SimpleTimeZone data. - * @param map Mappings object which is generated by {@link Main#compile}. - * @return 0 if no error occurred, otherwise 1. - */ - int generateSrc(Mappings map) { - try { - File outD = new File(Main.getOutputDir()); - outD.mkdirs(); - - FileWriter fw = - new FileWriter(new File(outD, "TimeZoneData.java"), false); - BufferedWriter out = new BufferedWriter(fw); - - out.write("import java.util.SimpleTimeZone;\n\n"); - out.write(" static SimpleTimeZone zones[] = {\n"); - - Map a = map.getAliases(); - List roi = map.getRawOffsetsIndex(); - List> roit = map.getRawOffsetsIndexTable(); - - int index = 0; - for (int offset : zonesByOffset.keySet()) { - int o = roi.get(index); - Set set = zonesByOffset.get(offset); - if (offset == o) { - // Merge aliases into zonesByOffset - set.addAll(roit.get(index)); - } - index++; - - for (String key : set) { - ZoneRec zrec; - String realname; - List stz; - if ((realname = a.get(key)) != null) { - // if this alias is not targeted, ignore it. - if (!Zone.isTargetZone(key)) { - continue; - } - stz = lastRules.get(realname); - zrec = lastZoneRecs.get(realname); - } else { - stz = lastRules.get(key); - zrec = lastZoneRecs.get(key); - } - - out.write("\t//--------------------------------------------------------------------\n"); - String s = Time.toFormedString(offset); - out.write("\tnew SimpleTimeZone(" + - Time.toFormedString(offset) + ", \"" + key + "\""); - if (realname != null) { - out.write(" /* " + realname + " */"); - } - - if (stz == null) { - out.write("),\n"); - } else { - RuleRec rr0 = stz.get(0); - RuleRec rr1 = stz.get(1); - - out.write(",\n\t " + Month.toString(rr0.getMonthNum()) + - ", " + rr0.getDay().getDayForSimpleTimeZone() + ", " + - rr0.getDay().getDayOfWeekForSimpleTimeZone() + ", " + - Time.toFormedString((int)rr0.getTime().getTime()) + ", " + - rr0.getTime().getTypeForSimpleTimeZone() + ",\n" + - - "\t " + Month.toString(rr1.getMonthNum()) + ", " + - rr1.getDay().getDayForSimpleTimeZone() + ", " + - rr1.getDay().getDayOfWeekForSimpleTimeZone() + ", " + - Time.toFormedString((int)rr1.getTime().getTime())+ ", " + - rr1.getTime().getTypeForSimpleTimeZone() + ",\n" + - - "\t " + Time.toFormedString(rr0.getSave()) + "),\n"); - - out.write("\t// " + rr0.getLine() + "\n"); - out.write("\t// " + rr1.getLine() + "\n"); - } - - String zline = zrec.getLine(); - if (zline.indexOf("Zone") == -1) { - zline = "Zone " + key + "\t" + zline.trim(); - } - out.write("\t// " + zline + "\n"); - } - } - out.write(" };\n"); - - out.close(); - fw.close(); - } catch(IOException e) { - Main.panic("IO error: "+e.getMessage()); - return 1; - } - - return 0; - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/Time.java b/jdk/make/tools/src/build/tools/javazic/Time.java deleted file mode 100644 index 66458a0020d..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/Time.java +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -import java.util.Locale; -import sun.util.calendar.CalendarDate; -import sun.util.calendar.CalendarSystem; -import sun.util.calendar.Gregorian; - -/** - * Time class represents the "AT" field and other time related information. - * - * @since 1.4 - */ -class Time { - - static final Gregorian gcal = CalendarSystem.getGregorianCalendar(); - - // type is wall clock time - private static final int WALL = 1; - - // type is standard time - private static final int STD = 2; - - // type is UTC - private static final int UTC = 3; - - // type of representing time - private int type; - - /** - * Time from the EPOCH in milliseconds - */ - private long time; - - /** - * Current time in milliseconds - */ - private static final long currentTime = System.currentTimeMillis(); - - Time() { - time = 0L; - } - - Time(long time) { - this.time = time; - } - - void setType(int type) { - this.type = type; - } - - long getTime() { - return time; - } - - int getType() { - return type; - } - - static long getCurrentTime() { - return currentTime; - } - - /** - * @return true if the time is represented in wall-clock time. - */ - boolean isWall() { - return type == WALL; - } - - /** - * @return true if the time is represented in standard time. - */ - boolean isSTD() { - return type == STD; - } - - /** - * @return true if the time is represented in UTC time. - */ - boolean isUTC() { - return type == UTC; - } - - /** - * Converts the type to a string that represents the type in the - * SimpleTimeZone time mode. (e.g., "SimpleTimeZone.WALL_TIME"). - * @return the converted string or null if the type is undefined. - */ - String getTypeForSimpleTimeZone() { - String stz = "SimpleTimeZone."; - if (isWall()) { - return stz+"WALL_TIME"; - } - else if (isSTD()) { - return stz+"STANDARD_TIME"; - } - else if (isUTC()) { - return stz+"UTC_TIME"; - } - else { - return null; - } - } - - /** - * Converts the given Gregorian calendar field values to local time. - * Local time is represented by the amount of milliseconds from - * January 1, 1970 0:00 GMT. - * @param year the year value - * @param month the Month value - * @param day the day represented by {@link RuleDay} - * @param save the amount of daylight time in milliseconds - * @param gmtOffset the GMT offset in milliseconds - * @param time the time of the day represented by {@link Time} - * @return local time - */ - static long getLocalTime(int year, Month month, RuleDay day, int save, - int gmtOffset, Time time) { - long t = time.getTime(); - - if (time.isSTD()) - t = time.getTime() + save; - else if (time.isUTC()) - t = time.getTime() + save + gmtOffset; - - return getLocalTime(year, month, day, t); - } - - /** - * Converts the given Gregorian calendar field values to local time. - * Local time is represented by the amount of milliseconds from - * January 1, 1970 0:00 GMT. - * @param year the year value - * @param month the Month value - * @param day the day value - * @param time the time of the day in milliseconds - * @return local time - */ - static long getLocalTime(int year, Month month, int day, long time) { - CalendarDate date = gcal.newCalendarDate(null); - date.setDate(year, month.value(), day); - long millis = gcal.getTime(date); - return millis + time; - } - - /** - * Equivalent to getLocalTime(year, month, day, (long)time). - * @param year the year value - * @param month the Month value - * @param day the day value - * @param time the time of the day in milliseconds - * @return local time - */ - static long getLocalTime(int year, Month month, int day, int time) { - return getLocalTime(year, month, day, (long)time); - } - - /** - * Equivalent to {@link #getLocalTime(int, Month, RuleDay, int) - * getLocalTime(year, month, day, (int) time)}. - * @param year the year value - * @param month the Month value - * @param day the day represented by {@link RuleDay} - * @param time the time of the day represented by {@link Time} - * @return local time - */ - static long getLocalTime(int year, Month month, RuleDay day, long time) { - return getLocalTime(year, month, day, (int) time); - } - - /** - * Converts the given Gregorian calendar field values to local time. - * Local time is represented by the amount of milliseconds from - * January 1, 1970 0:00 GMT. - * @param year the year value - * @param month the Month value - * @param day the day represented by {@link RuleDay} - * @param time the time of the day represented by {@link Time} - * @return local time - */ - static long getLocalTime(int year, Month month, RuleDay day, int time) { - CalendarDate cdate = gcal.newCalendarDate(null); - int monthValue = month.value(); - - if (day.isLast()) { // e.g., "lastSun" - cdate.setDate(year, monthValue, 1); - cdate.setDayOfMonth(gcal.getMonthLength(cdate)); - cdate = gcal.getNthDayOfWeek(-1, day.getDayOfWeekNum(), cdate); - } else if (day.isLater()) { // e.g., "Sun>=1" - cdate.setDate(year, monthValue, day.getDay()); - cdate = gcal.getNthDayOfWeek(1, day.getDayOfWeekNum(), cdate); - } else if (day.isExact()) { - cdate.setDate(year, monthValue, day.getDay()); - } else if (day.isEarlier()) { // e.g., "Sun<=15" - cdate.setDate(year, monthValue, day.getDay()); - cdate = gcal.getNthDayOfWeek(-1, day.getDayOfWeekNum(), cdate); - } else { - Main.panic("invalid day type: " + day); - } - return gcal.getTime(cdate) + time; - } - - /** - * Parses the given "AT" field and constructs a Time object. - * @param the "AT" field string - * @return the Time object - */ - static Time parse(String time) { - int sign; - int index = 0; - Time tm; - - if (time.charAt(0) == '-') { - sign = -1; - index++; - } else { - sign = 1; - } - int val = 0; - int num = 0; - int countDelim = 0; - while (index < time.length()) { - char c = time.charAt(index++); - if (c == ':') { - val = val * 60 + num; - countDelim++; - num = 0; - continue; - } - int d = Character.digit(c, 10); - if (d == -1) { - --index; - break; - } - num = num * 10 + d; - } - val = val * 60 + num; - // convert val to second - for (; countDelim < 2; countDelim++) { - val *= 60; - } - tm = new Time((long)val * 1000 * sign); - if (index < time.length()) { - char c = time.charAt(index++); - if (c == 's') { - tm.setType(Time.STD); - } else if (c == 'u' || c == 'g' || c == 'z') { - tm.setType(Time.UTC); - } else if (c == 'w') { - tm.setType(Time.WALL); - } else { - Main.panic("unknown time mode: "+c); - } - } else { - tm.setType(Time.WALL); - } - return tm; - } - - /** - * Converts the given milliseconds string to a "[+-]hh:mm" string. - * @param ms the milliseconds string - */ - static String toGMTFormat(String ms) { - long sec = Long.parseLong(ms) / 1000; - char sign; - if (sec < 0) { - sign = '-'; - sec = -sec; - } else { - sign = '+'; - } - return String.format((Locale)null, "%c%02d:%02d", - sign, sec/3600, (sec%3600)/60); - } - - /** - * Converts the given millisecond value to a string for a - * SimpleTimeZone parameter. - * @param ms the millisecond value - * @return the string in a human readable form - */ - static String toFormedString(int ms) { - StringBuilder s = new StringBuilder(); - boolean minus = false; - - if (ms < 0) { - s.append("-"); - minus = true; - ms = -ms; - } else if (ms == 0) { - return "0"; - } - - int hour = ms / (60 * 60 * 1000); - ms %= (60 * 60 * 1000); - int minute = ms / (60 * 1000); - - if (hour != 0) { - if (minus && minute != 0) { - s.append("("); - } - s.append(Integer.toString(hour) + "*ONE_HOUR"); - } - - if (minute != 0) { - if (hour != 0) { - s.append("+"); - } - s.append(Integer.toString(minute) + "*ONE_MINUTE"); - if (minus && hour != 0) { - s.append(")"); - } - } - - return s.toString(); - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/Timezone.java b/jdk/make/tools/src/build/tools/javazic/Timezone.java deleted file mode 100644 index 941ea454563..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/Timezone.java +++ /dev/null @@ -1,454 +0,0 @@ -/* - * Copyright (c) 2000, 2004, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -import java.util.ArrayList; -import java.util.List; - -/** - * Timezone represents all information of a single point of time to - * generate its time zone database. - * - * @since 1.4 - */ -class Timezone { - /** - * zone name of this time zone - */ - private String name; - - /** - * transition time values in UTC (millisecond) - */ - private List transitions; - - /** - * All offset values in millisecond - * @see sun.util.calendar.ZoneInfo - */ - private List offsets; - - /** - * Indices of GMT offset values (both raw and raw+saving) - * at transitions - */ - private List gmtOffsets; - - /** - * Indices of regular or "direct" saving time values - * at transitions - */ - private List dstOffsets; - - /** - * Zone records of this time zone - */ - private List usedZoneRecs; - - /** - * Rule records referred to by this time zone - */ - private List usedRuleRecs; - - /** - * Type of DST rules in this time zone - */ - private int dstType; - static final int UNDEF_DST = 0; // DST type not set yet - static final int NO_DST = 1; // never observed DST - static final int LAST_DST = 2; // last rule ends in DST (all year round DST-only) - static final int X_DST = 3; // used to observe DST - static final int DST = 4; // observing DST regularly - - /** - * Raw GMT offset of this time zone in the last rule - */ - private int rawOffset; - - /** - * The CRC32 value of the transitions data - */ - private int crc32; - - /** - * The last ZoneRec - */ - private ZoneRec lastZoneRec; - - /** - * The last DST rules. lastRules[0] is the DST start - * rule. lastRules[1] is the DST end rules. - */ - private List lastRules; - - /** - * The amount of DST saving value (millisecond) in the last DST - * rule. - */ - private int lastSaving; - - /** - * true if the raw offset will change in the future time. - */ - private boolean willRawOffsetChange = false; - - - /** - * Constracts a Timezone object with the given zone name. - * @param name the zone name - */ - Timezone(String name) { - this.name = name; - } - - /** - * @return the number of transitions - */ - int getNTransitions() { - if (transitions == null) { - return 0; - } - return transitions.size(); - } - - /** - * @return the zone name - */ - String getName() { - return name; - } - - /** - * Returns the list of all rule records that have been referred to - * by this time zone. - * @return the rule records list - */ - List getRules() { - return usedRuleRecs; - } - - /** - * Returns the list of all zone records that have been referred to - * by this time zone. - * @return the zone records list - */ - List getZones() { - return usedZoneRecs; - } - - /** - * @return the transition table (list) - */ - List getTransitions() { - return transitions; - } - - /** - * @return the offsets list - */ - List getOffsets() { - return offsets; - } - - /** - * @return the DST saving offsets list - */ - List getDstOffsets() { - return dstOffsets; - } - - /** - * @return the GMT offsets list - */ - List getGmtOffsets() { - return gmtOffsets; - } - - /** - * @return the checksum (crc32) value of the trasition table - */ - int getCRC32() { - return crc32; - } - - /** - * @return true if the GMT offset of this time zone would change - * after the time zone database has been generated, false, otherwise. - */ - boolean willGMTOffsetChange() { - return willRawOffsetChange; - } - - /** - * @return the last known GMT offset value in milliseconds - */ - int getRawOffset() { - return rawOffset; - } - - /** - * Sets time zone's GMT offset to offset. - * @param offset the GMT offset value in milliseconds - */ - void setRawOffset(int offset) { - rawOffset = offset; - } - - /** - * Sets time zone's GMT offset value to offset. If - * startTime is future time, then the {@link - * #willRawOffsetChange} value is set to true. - * @param offset the GMT offset value in milliseconds - * @param startTime the UTC time at which the GMT offset is in effective - */ - void setRawOffset(int offset, long startTime) { - // if this rawOffset is for the future time, let the run-time - // look for the current GMT offset. - if (startTime > Time.getCurrentTime()) { - willRawOffsetChange = true; - } - setRawOffset(offset); - } - - /** - * Adds the specified transition information to the end of the transition table. - * @param time the UTC time at which this transition happens - * @param offset the total amount of the offset from GMT in milliseconds - * @param dstOffset the amount of time in milliseconds saved at this transition - */ - void addTransition(long time, int offset, int dstOffset) { - if (transitions == null) { - transitions = new ArrayList(); - offsets = new ArrayList(); - dstOffsets = new ArrayList(); - } - transitions.add(time); - offsets.add(offset); - dstOffsets.add(dstOffset); - } - - /** - * Sets the type of historical daylight saving time - * observation. For example, China used to observed daylight - * saving time, but it no longer does. Then, X_DST is set to the - * China time zone. - * @param type the type of daylight saving time - */ - void setDSTType(int type) { - dstType = type; - } - - /** - * @return the type of historical daylight saving time - * observation. - */ - int getDSTType() { - return dstType; - } - - /** - * Adds the specified zone record to the zone records list. - * @param rec the zone record - */ - void addUsedRec(ZoneRec rec) { - if (usedZoneRecs == null) { - usedZoneRecs = new ArrayList(); - } - usedZoneRecs.add(rec); - } - - /** - * Adds the specified rule record to the rule records list. - * @param rec the rule record - */ - void addUsedRec(RuleRec rec) { - if (usedRuleRecs == null) { - usedRuleRecs = new ArrayList(); - } - // if the last used rec is the same as the given rec, avoid - // putting the same rule. - int n = usedRuleRecs.size(); - for (int i = 0; i < n; i++) { - if (usedRuleRecs.get(i).equals(rec)) { - return; - } - } - usedRuleRecs.add(rec); - } - - /** - * Sets the last zone record for this time zone. - * @param the last zone record - */ - void setLastZoneRec(ZoneRec zrec) { - lastZoneRec = zrec; - } - - /** - * @return the last zone record for this time zone. - */ - ZoneRec getLastZoneRec() { - return lastZoneRec; - } - - /** - * Sets the last rule records for this time zone. Those are used - * for generating SimpleTimeZone parameters. - * @param rules the last rule records - */ - void setLastRules(List rules) { - int n = rules.size(); - if (n > 0) { - lastRules = rules; - RuleRec rec = rules.get(0); - int offset = rec.getSave(); - if (offset > 0) { - setLastDSTSaving(offset); - } else { - System.err.println("\t No DST starting rule in the last rules."); - } - } - } - - /** - * @return the last rule records for this time zone. - */ - List getLastRules() { - return lastRules; - } - - /** - * Sets the last daylight saving amount. - * @param the daylight saving amount - */ - void setLastDSTSaving(int offset) { - lastSaving = offset; - } - - /** - * @return the last daylight saving amount. - */ - int getLastDSTSaving() { - return lastSaving; - } - - /** - * Calculates the CRC32 value from the transition table and sets - * the value to crc32. - */ - void checksum() { - if (transitions == null) { - crc32 = 0; - return; - } - Checksum sum = new Checksum(); - for (int i = 0; i < transitions.size(); i++) { - int offset = offsets.get(i); - // adjust back to make the transition in local time - sum.update(transitions.get(i) + offset); - sum.update(offset); - sum.update(dstOffsets.get(i)); - } - crc32 = (int)sum.getValue(); - } - - /** - * Removes unnecessary transitions for Java time zone support. - */ - void optimize() { - // if there is only one offset, delete all transitions. This - // could happen if only time zone abbreviations changed. - if (gmtOffsets.size() == 1) { - transitions = null; - usedRuleRecs = null; - setDSTType(NO_DST); - return; - } - for (int i = 0; i < (transitions.size() - 2); i++) { // don't remove the last one - if (transitions.get(i) == transitions.get(i+1)) { - transitions.remove(i); - offsets.remove(i); - dstOffsets.remove(i); - i--; - } - } - - for (int i = 0; i < (transitions.size() - 2); i++) { // don't remove the last one - if (offsets.get(i) == offsets.get(i+1) - && dstOffsets.get(i) == dstOffsets.get(i+1)) { - transitions.remove(i+1); - offsets.remove(i+1); - dstOffsets.remove(i+1); - i--; - } - } - } - - /** - * Stores the specified offset value from GMT in the GMT offsets - * table and returns its index. The offset value includes the base - * GMT offset and any additional daylight saving if applicable. If - * the same value as the specified offset is already in the table, - * its index is returned. - * @param offset the offset value in milliseconds - * @return the index to the offset value in the GMT offsets table. - */ - int getOffsetIndex(int offset) { - return getOffsetIndex(offset, 0); - } - - /** - * Stores the specified daylight saving value in the GMT offsets - * table and returns its index. If the same value as the specified - * offset is already in the table, its index is returned. If 0 is - * specified, it's not stored in the table and -1 is returned. - * @param offset the offset value in milliseconds - * @return the index to the specified offset value in the GMT - * offsets table, or -1 if 0 is specified. - */ - int getDstOffsetIndex(int offset) { - if (offset == 0) { - return -1; - } - return getOffsetIndex(offset, 1); - } - - private int getOffsetIndex(int offset, int index) { - if (gmtOffsets == null) { - gmtOffsets = new ArrayList(); - } - for (int i = index; i < gmtOffsets.size(); i++) { - if (offset == gmtOffsets.get(i)) { - return i; - } - } - if (gmtOffsets.size() < index) { - gmtOffsets.add(0); - } - gmtOffsets.add(offset); - return gmtOffsets.size() - 1; - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/Zone.java b/jdk/make/tools/src/build/tools/javazic/Zone.java deleted file mode 100644 index 1f4e7029c15..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/Zone.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2000, 2004, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; - -/** - * Zone holds information corresponding to a "Zone" part of a time - * zone definition file. - * - * @since 1.4 - */ -class Zone { - // zone name (e.g., "America/Los_Angeles") - private String name; - - // zone records - private List list; - - // target zone names for this compilation - private static Set targetZones; - - /** - * Constructs a Zone with the specified zone name. - * @param name the zone name - */ - Zone(String name) { - this.name = name; - list = new ArrayList(); - } - - /** - * Reads time zone names to be generated, called "target zone - * name", from the specified text file and creats an internal hash - * table to keep those names. It's assumed that one text line - * contains a zone name or comments if it starts with - * '#'. Comments can't follow a zone name in a single line. - * @param fileName the text file name - */ - static void readZoneNames(String fileName) { - if (fileName == null) { - return; - } - BufferedReader in = null; - try { - FileReader fr = new FileReader(fileName); - in = new BufferedReader(fr); - } catch (FileNotFoundException e) { - Main.panic("can't open file: " + fileName); - } - targetZones = new HashSet(); - String line; - - try { - while ((line = in.readLine()) != null) { - line = line.trim(); - if (line.length() == 0 || line.charAt(0) == '#') { - continue; - } - if (!targetZones.add(line)) { - Main.warning("duplicated target zone name: " + line); - } - } - in.close(); - } catch (IOException e) { - Main.panic("IO error: "+e.getMessage()); - } - } - - /** - * Determines whether the specified zone is one of the target zones. - * If no target zones are specified, this method always returns - * true for any zone name. - * @param zoneName the zone name - * @return true if the specified name is a target zone. - */ - static boolean isTargetZone(String zoneName) { - if (targetZones == null) { - return true; - } - return targetZones.contains(zoneName); - } - - /** - * Forces to add "MET" to the target zone table. This is because - * there is a conflict between Java zone name "WET" and Olson zone - * name. - */ - static void addMET() { - if (targetZones != null) { - targetZones.add("MET"); - } - } - - /** - * @return the zone name - */ - String getName() { - return name; - } - - /** - * Adds the specified zone record to the zone record list. - */ - void add(ZoneRec rec) { - list.add(rec); - } - - /** - * @param index the index at which the zone record in the list is returned. - * @return the zone record specified by the index. - */ - ZoneRec get(int index) { - return list.get(index); - } - - /** - * @return the size of the zone record list - */ - int size() { - return list.size(); - } - - /** - * Resolves the reference to a rule in each zone record. - * @param zi the Zoneinfo object with which the rule reference is - * resolved. - */ - void resolve(Zoneinfo zi) { - for (int i = 0; i < list.size(); i++) { - ZoneRec rec = list.get(i); - rec.resolve(zi); - } - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/ZoneRec.java b/jdk/make/tools/src/build/tools/javazic/ZoneRec.java deleted file mode 100644 index b175e0e93d4..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/ZoneRec.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2000, 2004, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; - -/** - * ZoneRec hold information of time zone corresponding to each text - * line of the "Zone" part. - * - * @since 1.4 - */ -class ZoneRec { - private int gmtOffset; - private String ruleName; - private int directSave; - private Rule ruleRef; - private String format; - private boolean hasUntil; - private int untilYear; - private Month untilMonth; - private RuleDay untilDay; - private Time untilTime; - private long untilInMillis; - private String line; - - /** - * @return the "UNTIL" value in milliseconds - */ - Time getUntilTime() { - return untilTime; - } - - /** - * @return the GMT offset value in milliseconds - */ - int getGmtOffset() { - return gmtOffset; - } - - /** - * @return the rule name to which this zone record refers - */ - String getRuleName() { - return ruleName; - } - - /** - * @return the amount of saving time directly defined in the - * "RULES/SAVE" field. - */ - int getDirectSave() { - return directSave; - } - - /** - * @return true if this zone record has a reference to a rule - */ - boolean hasRuleReference() { - return ruleRef != null; - } - - /** - * Returns the "FORMAT" field string of this zone record. This - * @return the "FORMAT" field - */ - String getFormat() { - return format; - } - - /** - * @return the year in the "UNTIL" field - */ - int getUntilYear() { - return untilYear; - } - - /** - * Returns the "UNTIL" field value in milliseconds from Janurary - * 1, 1970 0:00 GMT. - * @param currentSave the amount of daylight saving in - * milliseconds that is used to adjust wall-clock time. - * @return the milliseconds value of the "UNTIL" field - */ - long getUntilTime(int currentSave) { - if (untilTime.isWall()) { - return untilInMillis - currentSave; - } - return untilInMillis; - } - - /** - * Returns the "UNTIL" time in milliseconds without adjusting GMT - * offsets or daylight saving. - * @return local "UNTIL" time in milliseconds - */ - long getLocalUntilTime() { - return Time.getLocalTime(untilYear, - untilMonth, - untilDay, - untilTime.getTime()); - } - - /** - * Returns the "UNTIL" time in milliseconds with adjusting GMT offsets and daylight saving. - * @return the "UNTIL" time after the adjustment - */ - long getLocalUntilTime(int save, int gmtOffset) { - return Time.getLocalTime(untilYear, - untilMonth, - untilDay, - save, - gmtOffset, - untilTime); - } - - /** - * @return the text line of this zone record - */ - String getLine() { - return line; - } - - /** - * Sets the specified text line to this zone record - */ - void setLine(String line) { - this.line = line; - } - - /** - * @return true if this zone record has the "UNTIL" field - */ - boolean hasUntil() { - return this.hasUntil; - } - - /** - * Adjusts the "UNTIL" time to GMT offset if this zone record has - * it. untilTime is not adjusted to daylight saving - * in this method. - */ - void adjustTime() { - if (!hasUntil()) { - return; - } - if (untilTime.isSTD() || untilTime.isWall()) { - // adjust to gmt offset only here. adjust to real - // wall-clock time when tracking rules - untilInMillis -= gmtOffset; - } - } - - /** - * @return the reference to the Rule object - */ - Rule getRuleRef() { - return ruleRef; - } - - /** - * Resolves the reference to a Rule and adjusts its "UNTIL" time - * to GMT offset. - */ - void resolve(Zoneinfo zi) { - if (ruleName != null && (!"-".equals(ruleName))) { - ruleRef = zi.getRule(ruleName); - } - adjustTime(); - } - - /** - * Parses a Zone text line that is described by a StringTokenizer. - * @param tokens represents tokens of a Zone text line - * @return the zone record produced by parsing the text - */ - static ZoneRec parse(StringTokenizer tokens) { - ZoneRec rec = new ZoneRec(); - try { - rec.gmtOffset = (int) Time.parse(tokens.nextToken()).getTime(); - String token = tokens.nextToken(); - char c = token.charAt(0); - if (c >= '0' && c <= '9') { - rec.directSave = (int) Time.parse(token).getTime(); - } else { - rec.ruleName = token; - } - rec.format = tokens.nextToken(); - if (tokens.hasMoreTokens()) { - rec.hasUntil = true; - rec.untilYear = Integer.parseInt(tokens.nextToken()); - if (tokens.hasMoreTokens()) { - rec.untilMonth = Month.parse(tokens.nextToken()); - } else { - rec.untilMonth = Month.JANUARY; - } - if (tokens.hasMoreTokens()) { - rec.untilDay = RuleDay.parse(tokens.nextToken()); - } else { - rec.untilDay = new RuleDay(1); - } - if (tokens.hasMoreTokens()) { - rec.untilTime = Time.parse(tokens.nextToken()); - } else { - rec.untilTime = Time.parse("0:00"); - } - rec.untilInMillis = rec.getLocalUntilTime(); - } - } catch (Exception e) { - // TODO: error reporting - e.printStackTrace(); - } - return rec; - } - - private static void panic(String msg) { - Main.panic(msg); - } -} diff --git a/jdk/make/tools/src/build/tools/javazic/Zoneinfo.java b/jdk/make/tools/src/build/tools/javazic/Zoneinfo.java deleted file mode 100644 index 129f87c57d2..00000000000 --- a/jdk/make/tools/src/build/tools/javazic/Zoneinfo.java +++ /dev/null @@ -1,569 +0,0 @@ -/* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.javazic; - -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; - -/** - * Zoneinfo provides javazic compiler front-end functionality. - * @since 1.4 - */ -class Zoneinfo { - - private static final int minYear = 1900; - private static final int maxYear = 2037; - private static final long minTime = Time.getLocalTime(minYear, Month.JANUARY, 1, 0); - private static int startYear = minYear; - private static int endYear = maxYear; - - /** - * True if javazic should generate a list of SimpleTimeZone - * instances for the SimpleTimeZone-based time zone support. - */ - static boolean isYearForTimeZoneDataSpecified = false; - - /** - * Zone name to Zone mappings - */ - private Map zones; - - /** - * Rule name to Rule mappings - */ - private Map rules; - - /** - * Alias name to real name mappings - */ - private Map aliases; - - /** - * Constracts a Zoneinfo. - */ - Zoneinfo() { - zones = new HashMap(); - rules = new HashMap(); - aliases = new HashMap(); - } - - /** - * Adds the given zone to the list of Zones. - * @param zone Zone to be added to the list. - */ - void add(Zone zone) { - String name = zone.getName(); - zones.put(name, zone); - } - - /** - * Adds the given rule to the list of Rules. - * @param rule Rule to be added to the list. - */ - void add(Rule rule) { - String name = rule.getName(); - rules.put(name, rule); - } - - /** - * Puts the specifid name pair to the alias table. - * @param name1 an alias time zone name - * @param name2 the real time zone of the alias name - */ - void putAlias(String name1, String name2) { - aliases.put(name1, name2); - } - - /** - * Sets the given year for SimpleTimeZone list output. - * This method is called when the -S option is specified. - * @param year the year for which SimpleTimeZone list should be generated - */ - static void setYear(int year) { - setStartYear(year); - setEndYear(year); - isYearForTimeZoneDataSpecified = true; - } - - /** - * Sets the start year. - * @param year the start year value - * @throws IllegalArgumentException if the specified year value is - * smaller than the minimum year or greater than the end year. - */ - static void setStartYear(int year) { - if (year < minYear || year > endYear) { - throw new IllegalArgumentException("invalid start year specified: " + year); - } - startYear = year; - } - - /** - * @return the start year value - */ - static int getStartYear() { - return startYear; - } - - /** - * Sets the end year. - * @param year the end year value - * @throws IllegalArgumentException if the specified year value is - * smaller than the start year or greater than the maximum year. - */ - static void setEndYear(int year) { - if (year < startYear || year > maxYear) { - throw new IllegalArgumentException(); - } - endYear = year; - } - - /** - * @return the end year value - */ - static int getEndYear() { - return endYear; - } - - /** - * @return the minimum year value - */ - static int getMinYear() { - return minYear; - } - - /** - * @return the maximum year value - */ - static int getMaxYear() { - return maxYear; - } - - /** - * @return the alias table - */ - Map getAliases() { - return aliases; - } - - /** - * @return the Zone list - */ - Map getZones() { - return zones; - } - - /** - * @return a Zone specified by name. - * @param name a zone name - */ - Zone getZone(String name) { - return zones.get(name); - } - - /** - * @return a Rule specified by name. - * @param name a rule name - */ - Rule getRule(String name) { - return rules.get(name); - } - - private static String line; - - private static int lineNum; - - /** - * Parses the specified time zone data file and creates a Zoneinfo - * that has all Rules, Zones and Links (aliases) information. - * @param fname the time zone data file name - * @return a Zoneinfo object - */ - static Zoneinfo parse(String fname) { - BufferedReader in = null; - try { - FileReader fr = new FileReader(fname); - in = new BufferedReader(fr); - } catch (FileNotFoundException e) { - panic("can't open file: "+fname); - } - Zoneinfo zi = new Zoneinfo(); - boolean continued = false; - Zone zone = null; - String l; - lineNum = 0; - - try { - while ((line = in.readLine()) != null) { - lineNum++; - // skip blank and comment lines - if (line.length() == 0 || line.charAt(0) == '#') { - continue; - } - - // trim trailing comments - int rindex = line.lastIndexOf('#'); - if (rindex != -1) { - // take the data part of the line - l = line.substring(0, rindex); - } else { - l = line; - } - - StringTokenizer tokens = new StringTokenizer(l); - if (!tokens.hasMoreTokens()) { - continue; - } - String token = tokens.nextToken(); - - if (continued || "Zone".equals(token)) { - if (zone == null) { - if (!tokens.hasMoreTokens()) { - panic("syntax error: zone no more token"); - } - token = tokens.nextToken(); - // if the zone name is in "GMT+hh" or "GMT-hh" - // format, ignore it due to spec conflict. - if (token.startsWith("GMT+") || token.startsWith("GMT-")) { - continue; - } - zone = new Zone(token); - } else { - // no way to push the current token back... - tokens = new StringTokenizer(l); - } - - ZoneRec zrec = ZoneRec.parse(tokens); - zrec.setLine(line); - zone.add(zrec); - if ((continued = zrec.hasUntil()) == false) { - if (Zone.isTargetZone(zone.getName())) { - // zone.resolve(zi); - zi.add(zone); - } - zone = null; - } - } else if ("Rule".equals(token)) { - if (!tokens.hasMoreTokens()) { - panic("syntax error: rule no more token"); - } - token = tokens.nextToken(); - Rule rule = zi.getRule(token); - if (rule == null) { - rule = new Rule(token); - zi.add(rule); - } - RuleRec rrec = RuleRec.parse(tokens); - rrec.setLine(line); - rule.add(rrec); - } else if ("Link".equals(token)) { - // Link - try { - String name1 = tokens.nextToken(); - String name2 = tokens.nextToken(); - - // if the zone name is in "GMT+hh" or "GMT-hh" - // format, ignore it due to spec conflict with - // custom time zones. Also, ignore "ROC" for - // PC-ness. - if (name2.startsWith("GMT+") || name2.startsWith("GMT-") - || "ROC".equals(name2)) { - continue; - } - zi.putAlias(name2, name1); - } catch (Exception e) { - panic("syntax error: no more token for Link"); - } - } - } - in.close(); - } catch (IOException ex) { - panic("IO error: " + ex.getMessage()); - } - - return zi; - } - - /** - * Interprets a zone and constructs a Timezone object that - * contains enough information on GMT offsets and DST schedules to - * generate a zone info database. - * - * @param zoneName the zone name for which a Timezone object is - * constructed. - * - * @return a Timezone object that contains all GMT offsets and DST - * rules information. - */ - Timezone phase2(String zoneName) { - Timezone tz = new Timezone(zoneName); - Zone zone = getZone(zoneName); - zone.resolve(this); - - // TODO: merge phase2's for the regular and SimpleTimeZone ones. - if (isYearForTimeZoneDataSpecified) { - ZoneRec zrec = zone.get(zone.size()-1); - tz.setLastZoneRec(zrec); - tz.setRawOffset(zrec.getGmtOffset()); - if (zrec.hasRuleReference()) { - /* - * This part assumes that the specified year is covered by - * the rules referred to by the last zone record. - */ - List rrecs = zrec.getRuleRef().getRules(startYear); - - if (rrecs.size() == 2) { - // make sure that one is a start rule and the other is - // an end rule. - RuleRec r0 = rrecs.get(0); - RuleRec r1 = rrecs.get(1); - if (r0.getSave() == 0 && r1.getSave() > 0) { - rrecs.set(0, r1); - rrecs.set(1, r0); - } else if (!(r0.getSave() > 0 && r1.getSave() == 0)) { - rrecs = null; - Main.error(zoneName + ": rules for " + startYear + " not found."); - } - } else { - rrecs = null; - } - if (rrecs != null) { - tz.setLastRules(rrecs); - } - } - return tz; - } - - int gmtOffset; - int year = minYear; - int fromYear = year; - long fromTime = Time.getLocalTime(startYear, - Month.JANUARY, - 1, 0); - - // take the index 0 for the GMT offset of the last zone record - ZoneRec zrec = zone.get(zone.size()-1); - tz.getOffsetIndex(zrec.getGmtOffset()); - - int currentSave = 0; - boolean usedZone; - for (int zindex = 0; zindex < zone.size(); zindex++) { - zrec = zone.get(zindex); - usedZone = false; - gmtOffset = zrec.getGmtOffset(); - int stdOffset = zrec.getDirectSave(); - - // If this is the last zone record, take the last rule info. - if (!zrec.hasUntil()) { - tz.setRawOffset(gmtOffset, fromTime); - if (zrec.hasRuleReference()) { - tz.setLastRules(zrec.getRuleRef().getLastRules()); - } else if (stdOffset != 0) { - // in case the last rule is all year round DST-only - // (Asia/Amman once announced this rule.) - tz.setLastDSTSaving(stdOffset); - } - } - if (!zrec.hasRuleReference()) { - if (!zrec.hasUntil() || zrec.getUntilTime(stdOffset) >= fromTime) { - tz.addTransition(fromTime, - tz.getOffsetIndex(gmtOffset+stdOffset), - tz.getDstOffsetIndex(stdOffset)); - usedZone = true; - } - currentSave = stdOffset; - // optimization in case the last rule is fixed. - if (!zrec.hasUntil()) { - if (tz.getNTransitions() > 0) { - if (stdOffset == 0) { - tz.setDSTType(Timezone.X_DST); - } else { - tz.setDSTType(Timezone.LAST_DST); - } - long time = Time.getLocalTime(maxYear, - Month.JANUARY, 1, 0); - time -= zrec.getGmtOffset(); - tz.addTransition(time, - tz.getOffsetIndex(gmtOffset+stdOffset), - tz.getDstOffsetIndex(stdOffset)); - tz.addUsedRec(zrec); - } else { - tz.setDSTType(Timezone.NO_DST); - } - break; - } - } else { - Rule rule = zrec.getRuleRef(); - boolean fromTimeUsed = false; - currentSave = 0; - year_loop: - for (year = getMinYear(); year <= endYear; year++) { - if (zrec.hasUntil() && year > zrec.getUntilYear()) { - break; - } - List rules = rule.getRules(year); - if (rules.size() > 0) { - for (int i = 0; i < rules.size(); i++) { - RuleRec rrec = rules.get(i); - long transition = rrec.getTransitionTime(year, - gmtOffset, - currentSave); - if (zrec.hasUntil()) { - if (transition >= zrec.getUntilTime(currentSave)) { - break year_loop; - } - } - - if (fromTimeUsed == false) { - if (fromTime <= transition) { - fromTimeUsed = true; - - if (fromTime != minTime) { - int prevsave; - - ZoneRec prevzrec = zone.get(zindex - 1); - - // See if until time in the previous - // ZoneRec is the same thing as the - // local time in the next rule. - // (examples are Asia/Ashkhabad in 1991, - // Europe/Riga in 1989) - - if (i > 0) { - prevsave = rules.get(i-1).getSave(); - } else { - List prevrules = rule.getRules(year-1); - - if (prevrules.size() > 0) { - prevsave = prevrules.get(prevrules.size()-1).getSave(); - } else { - prevsave = 0; - } - } - - if (rrec.isSameTransition(prevzrec, prevsave, gmtOffset)) { - currentSave = rrec.getSave(); - tz.addTransition(fromTime, - tz.getOffsetIndex(gmtOffset+currentSave), - tz.getDstOffsetIndex(currentSave)); - tz.addUsedRec(rrec); - usedZone = true; - continue; - } - if (!prevzrec.hasRuleReference() - || rule != prevzrec.getRuleRef() - || (rule == prevzrec.getRuleRef() - && gmtOffset != prevzrec.getGmtOffset())) { - int save = (fromTime == transition) ? rrec.getSave() : currentSave; - tz.addTransition(fromTime, - tz.getOffsetIndex(gmtOffset+save), - tz.getDstOffsetIndex(save)); - tz.addUsedRec(rrec); - usedZone = true; - } - } else { // fromTime == minTime - int save = rrec.getSave(); - tz.addTransition(minTime, - tz.getOffsetIndex(gmtOffset), - tz.getDstOffsetIndex(0)); - - tz.addTransition(transition, - tz.getOffsetIndex(gmtOffset+save), - tz.getDstOffsetIndex(save)); - - tz.addUsedRec(rrec); - usedZone = true; - } - } else if (year == fromYear && i == rules.size()-1) { - int save = rrec.getSave(); - tz.addTransition(fromTime, - tz.getOffsetIndex(gmtOffset+save), - tz.getDstOffsetIndex(save)); - } - } - - currentSave = rrec.getSave(); - if (fromTime < transition) { - tz.addTransition(transition, - tz.getOffsetIndex(gmtOffset+currentSave), - tz.getDstOffsetIndex(currentSave)); - tz.addUsedRec(rrec); - usedZone = true; - } - } - } else { - if (year == fromYear) { - tz.addTransition(fromTime, - tz.getOffsetIndex(gmtOffset+currentSave), - tz.getDstOffsetIndex(currentSave)); - fromTimeUsed = true; - } - if (year == endYear && !zrec.hasUntil()) { - if (tz.getNTransitions() > 0) { - // Assume that this Zone stopped DST - tz.setDSTType(Timezone.X_DST); - long time = Time.getLocalTime(maxYear, Month.JANUARY, - 1, 0); - time -= zrec.getGmtOffset(); - tz.addTransition(time, - tz.getOffsetIndex(gmtOffset), - tz.getDstOffsetIndex(0)); - usedZone = true; - } else { - tz.setDSTType(Timezone.NO_DST); - } - } - } - } - } - if (usedZone) { - tz.addUsedRec(zrec); - } - if (zrec.hasUntil() && zrec.getUntilTime(currentSave) > fromTime) { - fromTime = zrec.getUntilTime(currentSave); - fromYear = zrec.getUntilYear(); - year = zrec.getUntilYear(); - } - } - - if (tz.getDSTType() == Timezone.UNDEF_DST) { - tz.setDSTType(Timezone.DST); - } - tz.optimize(); - tz.checksum(); - return tz; - } - - private static void panic(String msg) { - Main.panic(msg); - } -} From bf26c0a143801c1ae7f53e47dc2960dbb5c35892 Mon Sep 17 00:00:00 2001 From: Yong Jeffrey Huang Date: Sat, 16 Feb 2013 21:22:11 -0800 Subject: [PATCH 068/180] 8006748: getISO3Country() returns wrong value Reviewed-by: naoto --- jdk/src/share/classes/java/util/LocaleISOData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/share/classes/java/util/LocaleISOData.java b/jdk/src/share/classes/java/util/LocaleISOData.java index c49abb06eaf..170fef69193 100644 --- a/jdk/src/share/classes/java/util/LocaleISOData.java +++ b/jdk/src/share/classes/java/util/LocaleISOData.java @@ -473,7 +473,7 @@ class LocaleISOData { + "YE" + "YEM" // Yemen + "YT" + "MYT" // Mayotte + "ZA" + "ZAF" // South Africa, Republic of - + "ZM" + "ZMW" // Zambia, Republic of + + "ZM" + "ZMB" // Zambia, Republic of + "ZW" + "ZWE" // Zimbabwe ; From 7886b3e26b17b3759e68d691a9c8112c8eaae86f Mon Sep 17 00:00:00 2001 From: Frank Ding Date: Mon, 18 Feb 2013 08:14:18 +0000 Subject: [PATCH 069/180] 6429204: (se) Concurrent Selector.register and SelectionKey.interestOps can ignore interestOps Reviewed-by: alanb --- .../sun/nio/ch/WindowsSelectorImpl.java | 25 +-- .../nio/channels/Selector/RacyDeregister.java | 148 ++++++++++++++++++ 2 files changed, 164 insertions(+), 9 deletions(-) create mode 100644 jdk/test/java/nio/channels/Selector/RacyDeregister.java diff --git a/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java b/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java index beb3e861f83..1034bb7d82f 100644 --- a/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, 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 @@ -35,6 +35,7 @@ import java.nio.channels.ClosedSelectorException; import java.nio.channels.Pipe; import java.nio.channels.SelectableChannel; import java.io.IOException; +import java.nio.channels.CancelledKeyException; import java.util.List; import java.util.ArrayList; import java.util.HashMap; @@ -561,17 +562,19 @@ final class WindowsSelectorImpl extends SelectorImpl { protected void implDereg(SelectionKeyImpl ski) throws IOException{ int i = ski.getIndex(); assert (i >= 0); - if (i != totalChannels - 1) { - // Copy end one over it - SelectionKeyImpl endChannel = channelArray[totalChannels-1]; - channelArray[i] = endChannel; - endChannel.setIndex(i); - pollWrapper.replaceEntry(pollWrapper, totalChannels - 1, + synchronized (closeLock) { + if (i != totalChannels - 1) { + // Copy end one over it + SelectionKeyImpl endChannel = channelArray[totalChannels-1]; + channelArray[i] = endChannel; + endChannel.setIndex(i); + pollWrapper.replaceEntry(pollWrapper, totalChannels - 1, pollWrapper, i); + } + ski.setIndex(-1); } channelArray[totalChannels - 1] = null; totalChannels--; - ski.setIndex(-1); if ( totalChannels != 1 && totalChannels % MAX_SELECTABLE_FDS == 1) { totalChannels--; threadsCount--; // The last thread has become redundant. @@ -589,7 +592,11 @@ final class WindowsSelectorImpl extends SelectorImpl { synchronized (closeLock) { if (pollWrapper == null) throw new ClosedSelectorException(); - pollWrapper.putEventOps(sk.getIndex(), ops); + // make sure this sk has not been removed yet + int index = sk.getIndex(); + if (index == -1) + throw new CancelledKeyException(); + pollWrapper.putEventOps(index, ops); } } diff --git a/jdk/test/java/nio/channels/Selector/RacyDeregister.java b/jdk/test/java/nio/channels/Selector/RacyDeregister.java new file mode 100644 index 00000000000..5a72df18107 --- /dev/null +++ b/jdk/test/java/nio/channels/Selector/RacyDeregister.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2013, 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. + */ + +/* + * Portions Copyright (c) 2012 IBM Corporation + */ + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; + +/* + * @test + * @bug 6429204 + * @summary SelectionKey.interestOps does not update interest set on Windows. + * @author Frank Ding + */ +public class RacyDeregister { + + static boolean notified; + static final Object selectorLock = new Object(); + static final Object notifyLock = new Object(); + /** + * null: not terminated + * true: passed + * false: failed + */ + static volatile Boolean succTermination = null; + + public static void main(String[] args) throws Exception { + InetAddress addr = InetAddress.getByName(null); + ServerSocketChannel sc = ServerSocketChannel.open(); + sc.socket().bind(new InetSocketAddress(addr, 0)); + + SocketChannel.open(new InetSocketAddress(addr, + sc.socket().getLocalPort())); + + SocketChannel accepted = sc.accept(); + accepted.configureBlocking(false); + + SocketChannel.open(new InetSocketAddress(addr, + sc.socket().getLocalPort())); + SocketChannel accepted2 = sc.accept(); + accepted2.configureBlocking(false); + + final Selector sel = Selector.open(); + SelectionKey key2 = accepted2.register(sel, SelectionKey.OP_READ); + final SelectionKey[] key = new SelectionKey[]{ + accepted.register(sel, SelectionKey.OP_READ)}; + + + // thread that will be changing key[0].interestOps to OP_READ | OP_WRITE + new Thread() { + + public void run() { + try { + for (int k = 0; k < 15; k++) { + for (int i = 0; i < 10000; i++) { + synchronized (notifyLock) { + synchronized (selectorLock) { + sel.wakeup(); + key[0].interestOps(SelectionKey.OP_READ + | SelectionKey.OP_WRITE); + } + notified = false; + long beginTime = System.currentTimeMillis(); + while (true) { + notifyLock.wait(5000); + if (notified) { + break; + } + long endTime = System.currentTimeMillis(); + if (endTime - beginTime > 5000) { + succTermination = false; + // wake up main thread doing select() + sel.wakeup(); + return; + } + } + } + } + } + succTermination = true; + // wake up main thread doing select() + sel.wakeup(); + } catch (Exception e) { + System.out.println(e); + succTermination = true; + // wake up main thread doing select() + sel.wakeup(); + } + } + }.start(); + + // main thread will be doing registering/deregistering with the sel + while (true) { + sel.select(); + if (Boolean.TRUE.equals(succTermination)) { + System.out.println("Test passed"); + sel.close(); + sc.close(); + break; + } else if (Boolean.FALSE.equals(succTermination)) { + System.out.println("Failed to pass the test"); + sel.close(); + sc.close(); + throw new RuntimeException("Failed to pass the test"); + } + synchronized (selectorLock) { + } + if (sel.selectedKeys().contains(key[0]) && key[0].isWritable()) { + synchronized (notifyLock) { + notified = true; + notifyLock.notify(); + key[0].cancel(); + sel.selectNow(); + key2 = accepted2.register(sel, SelectionKey.OP_READ); + key[0] = accepted.register(sel, SelectionKey.OP_READ); + } + } + key2.cancel(); + sel.selectedKeys().clear(); + } + } +} From 80da999bf3267060b1a38a4f022df6ed0cbc1aab Mon Sep 17 00:00:00 2001 From: Jia-Hong Chen Date: Mon, 18 Feb 2013 14:04:00 -0800 Subject: [PATCH 070/180] 8005191: [parfait] #384 sun/font/layout/LookupProcessor.cpp Null pointer dereference Reviewed-by: prr, vadim --- jdk/src/share/native/sun/font/layout/LookupProcessor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp b/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp index 60727aa3f3a..88e9f25ddeb 100644 --- a/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp +++ b/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp @@ -125,6 +125,10 @@ le_uint32 LookupProcessor::applySingleLookup(le_uint16 lookupTableIndex, GlyphIt } const LookupTable *lookupTable = lookupListTable->getLookupTable(lookupTableIndex); + if (lookupTable == NULL) { + success = LE_INTERNAL_ERROR; + return 0; + } le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags); GlyphIterator tempIterator(*glyphIterator, lookupFlags); le_uint32 delta = applyLookupTable(lookupTable, &tempIterator, fontInstance, success); From 66b344c616ffc9e47019d491f15789c81ab6333d Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 19 Feb 2013 00:19:15 -0800 Subject: [PATCH 071/180] 8008434: Misc javadoc warning fixes in DateTimeFormatterBuilder and TimeZone Reviewed-by: mduigou, okutsu --- .../classes/java/time/format/DateTimeFormatterBuilder.java | 2 +- jdk/src/share/classes/java/util/TimeZone.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/java/time/format/DateTimeFormatterBuilder.java b/jdk/src/share/classes/java/time/format/DateTimeFormatterBuilder.java index f2ed2317865..e413d4b1e64 100644 --- a/jdk/src/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/jdk/src/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -1007,7 +1007,7 @@ public final class DateTimeFormatterBuilder { * is used, with {@code IsoChronology} as the fallback. *

    * Note that this method provides similar functionality to methods on - * {@code DateFormat} such as {@link DateFormat#getDateTimeInstance(int, int)}. + * {@code DateFormat} such as {@link java.text.DateFormat#getDateTimeInstance(int, int)}. * * @param dateStyle the date style to use, null means no date required * @param timeStyle the time style to use, null means no time required diff --git a/jdk/src/share/classes/java/util/TimeZone.java b/jdk/src/share/classes/java/util/TimeZone.java index 66297c015b9..cc8fe5dc356 100644 --- a/jdk/src/share/classes/java/util/TimeZone.java +++ b/jdk/src/share/classes/java/util/TimeZone.java @@ -534,7 +534,7 @@ abstract public class TimeZone implements Serializable, Cloneable { /** * Gets the {@code TimeZone} for the given {@code zoneId}. * - * @param zoneid a {@link ZoneId} from which the time zone ID is obtained + * @param zoneId a {@link ZoneId} from which the time zone ID is obtained * @return the specified {@code TimeZone}, or the GMT zone if the given ID * cannot be understood. * @throws NullPointerException if {@code zoneId} is {@code null} From d6a99026903001d71b13c29dfd49c7d9910fbafe Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 19 Feb 2013 00:24:55 -0800 Subject: [PATCH 072/180] 8008435: Fix new build to include jdk.Supported in ct.sym Reviewed-by: erikj --- common/makefiles/javadoc/NON_CORE_PKGS.gmk | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/common/makefiles/javadoc/NON_CORE_PKGS.gmk b/common/makefiles/javadoc/NON_CORE_PKGS.gmk index 1d944d3dd19..c2e481119eb 100644 --- a/common/makefiles/javadoc/NON_CORE_PKGS.gmk +++ b/common/makefiles/javadoc/NON_CORE_PKGS.gmk @@ -80,7 +80,8 @@ JCONSOLE_PKGS = com.sun.tools.jconsole TREEAPI_PKGS = com.sun.source.doctree \ com.sun.source.tree \ - com.sun.source.util + com.sun.source.util \ + jdk SMARTCARDIO_PKGS = javax.smartcardio @@ -93,6 +94,8 @@ APPLE_EXT_PKGS = com.apple.concurrent \ com.apple.eio endif +JDK_PKGS = jdk + # non-core packages in rt.jar NON_CORE_PKGS = $(DOMAPI_PKGS) \ $(MGMT_PKGS) \ @@ -103,5 +106,5 @@ NON_CORE_PKGS = $(DOMAPI_PKGS) \ $(HTTPSERVER_PKGS) \ $(SMARTCARDIO_PKGS) \ $(SCTPAPI_PKGS) \ - $(APPLE_EXT_PKGS) - + $(APPLE_EXT_PKGS) \ + $(JDK_PKGS) From 49ba72c4637cae1971144040db6cf5a6d85e8cfa Mon Sep 17 00:00:00 2001 From: Petr Pchelko Date: Tue, 19 Feb 2013 11:26:43 +0000 Subject: [PATCH 073/180] 8008374: Build failure (NEWBUILD=false) on Mac Fixed an old build system failure Reviewed-by: art, anthony --- jdk/make/sun/lwawt/FILES_export_macosx.gmk | 1 - 1 file changed, 1 deletion(-) diff --git a/jdk/make/sun/lwawt/FILES_export_macosx.gmk b/jdk/make/sun/lwawt/FILES_export_macosx.gmk index 2101fd8ac39..6a2e2f9e93b 100644 --- a/jdk/make/sun/lwawt/FILES_export_macosx.gmk +++ b/jdk/make/sun/lwawt/FILES_export_macosx.gmk @@ -122,7 +122,6 @@ FILES_export = \ sun/lwawt/macosx/CTextPipe.java \ sun/lwawt/macosx/CDesktopPeer.java \ sun/java2d/CRenderer.java \ - sun/lwawt/macosx/EventDispatchAccess.java \ sun/lwawt/macosx/NSPrintInfo.java \ sun/lwawt/macosx/CAccessibility.java \ sun/lwawt/macosx/CAccessible.java \ From 88eea092fb2de66a9c547464fef118231b673f12 Mon Sep 17 00:00:00 2001 From: Konstantin Shefov Date: Tue, 19 Feb 2013 17:26:40 +0400 Subject: [PATCH 074/180] 8008379: TEST_BUG: Fail automatically with java.lang.NullPointerException Reviewed-by: serb, anthony --- .../ModalDialogMultiscreenTest.java | 441 ++++++++++++++++++ 1 file changed, 441 insertions(+) create mode 100644 jdk/test/java/awt/Modal/ModalDialogMultiscreenTest/ModalDialogMultiscreenTest.java diff --git a/jdk/test/java/awt/Modal/ModalDialogMultiscreenTest/ModalDialogMultiscreenTest.java b/jdk/test/java/awt/Modal/ModalDialogMultiscreenTest/ModalDialogMultiscreenTest.java new file mode 100644 index 00000000000..156bfe5df0e --- /dev/null +++ b/jdk/test/java/awt/Modal/ModalDialogMultiscreenTest/ModalDialogMultiscreenTest.java @@ -0,0 +1,441 @@ +/* + * Copyright (c) 2013, 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 6430802 8008379 + @summary WM should not hang after show()/close() + @author anthony.petrov@sun.com: area=awt.modal + @run main/manual ModalDialogMultiscreenTest +*/ + + +/** + * ModalDialogMultiscreenTest.java + * + * summary: Tests whether a WM will hang on show()/close() a modal dialog in multiscreen mode + */ + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; + + +public class ModalDialogMultiscreenTest +{ + + private static class ButtonActionListener implements ActionListener { + JFrame frame; + JDialog dialog; + public ButtonActionListener(JFrame frame, JDialog dialog) { + this.frame = frame; + this.dialog = dialog; + } + public void actionPerformed(ActionEvent e) { + dialog.setLocationRelativeTo(frame); + dialog.setVisible(true); + } + } + public static class TestDialog extends JDialog { + public TestDialog(Frame owner, String title, boolean modal, GraphicsConfiguration gc) { + super(owner, title, modal, gc); + setSize(200, 100); + JButton button = new JButton("Close"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + getContentPane().add(button); + } + } + + private static void init() + { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice[] gs = ge.getScreenDevices(); + + Sysout.createDialog( ); + + if (gs.length < 2) { + System.out.println("Not multi-head environment, test not valid!"); + ModalDialogMultiscreenTest.pass( ); + } + + String[] instructions = + { + "The test should be run on a multi-head X (non-xinerama) systems.", + "Otherwise click the Pass button right now.", + "You will see an open Frame on each screen your system has.", + "The frame has an 'Open dialog' button.", + "Clicking the button opens a modal dialog with a Close button.", + "The test procedure:", + "1. Open a dialog and close it with appropriate buttons.", + "2. Switch to another screen ($ DISPLAY=X.Y xprop)", + "3. Repeat steps 1-2 several times (about 3*)", + "If the test doesn't cause the window manager to hang, it's passed." + }; + Sysout.printInstructions( instructions ); + + + for (int i = 0; i < gs.length; i++) { + JFrame frame = new JFrame("Frame "+i,gs[i].getDefaultConfiguration()); + JButton button = new JButton("Open Dialog"); + button.setMinimumSize(new Dimension(200, 100)); + button.setPreferredSize(new Dimension(200, 100)); + button.setSize(new Dimension(200, 100)); + button.addActionListener(new ButtonActionListener(frame, new TestDialog(frame, "Dialog #"+i, true, gs[i].getDefaultConfiguration()))); + frame.getContentPane().add(button); + frame.pack(); + frame.setVisible(true); + } + + }//End init() + + + //ap203012: NO MORE CHANGES BELOW THIS LINE + + + + /***************************************************** + * Standard Test Machinery Section + * DO NOT modify anything in this section -- it's a + * standard chunk of code which has all of the + * synchronisation necessary for the test harness. + * By keeping it the same in all tests, it is easier + * to read and understand someone else's test, as + * well as insuring that all tests behave correctly + * with the test harness. + * There is a section following this for test-defined + * classes + ******************************************************/ + private static boolean theTestPassed = false; + private static boolean testGeneratedInterrupt = false; + private static String failureMessage = ""; + + private static Thread mainThread = null; + + private static int sleepTime = 300000; + + public static void main( String args[] ) throws InterruptedException + { + mainThread = Thread.currentThread(); + try + { + init(); + } + catch( TestPassedException e ) + { + //The test passed, so just return from main and harness will + // interepret this return as a pass + return; + } + //At this point, neither test passed nor test failed has been + // called -- either would have thrown an exception and ended the + // test, so we know we have multiple threads. + + //Test involves other threads, so sleep and wait for them to + // called pass() or fail() + try + { + Thread.sleep( sleepTime ); + //Timed out, so fail the test + throw new RuntimeException( "Timed out after " + sleepTime/1000 + " seconds" ); + } + catch (InterruptedException e) + { + if( ! testGeneratedInterrupt ) throw e; + + //reset flag in case hit this code more than once for some reason (just safety) + testGeneratedInterrupt = false; + if ( theTestPassed == false ) + { + throw new RuntimeException( failureMessage ); + } + } + + }//main + + public static synchronized void setTimeoutTo( int seconds ) + { + sleepTime = seconds * 1000; + } + + public static synchronized void pass() + { + Sysout.println( "The test passed." ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //first check if this is executing in main thread + if ( mainThread == Thread.currentThread() ) + { + //Still in the main thread, so set the flag just for kicks, + // and throw a test passed exception which will be caught + // and end the test. + theTestPassed = true; + throw new TestPassedException(); + } + //pass was called from a different thread, so set the flag and interrupt + // the main thead. + theTestPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + }//pass() + + public static synchronized void fail() + { + //test writer didn't specify why test failed, so give generic + fail( "it just plain failed! :-)" ); + } + + public static synchronized void fail( String whyFailed ) + { + Sysout.println( "The test failed: " + whyFailed ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //check if this called from main thread + if ( mainThread == Thread.currentThread() ) + { + //If main thread, fail now 'cause not sleeping + throw new RuntimeException( whyFailed ); + } + theTestPassed = false; + testGeneratedInterrupt = true; + failureMessage = whyFailed; + mainThread.interrupt(); + }//fail() + +}// class ModalDialogMultiscreenTest + +//This exception is used to exit from any level of call nesting +// when it's determined that the test has passed, and immediately +// end the test. +class TestPassedException extends RuntimeException +{ +} + +//*********** End Standard Test Machinery Section ********** + + +//************ Begin classes defined for the test **************** + +// make listeners in a class defined here, and instantiate them in init() + +/* Example of a class which may be written as part of a test +class NewClass implements anInterface + { + static int newVar = 0; + + public void eventDispatched(AWTEvent e) + { + //Counting events to see if we get enough + eventCount++; + + if( eventCount == 20 ) + { + //got enough events, so pass + + ModalDialogMultiscreenTest.pass(); + } + else if( tries == 20 ) + { + //tried too many times without getting enough events so fail + + ModalDialogMultiscreenTest.fail(); + } + + }// eventDispatched() + + }// NewClass class + +*/ + + +//************** End classes defined for the test ******************* + + + + +/**************************************************** + Standard Test Machinery + DO NOT modify anything below -- it's a standard + chunk of code whose purpose is to make user + interaction uniform, and thereby make it simpler + to read and understand someone else's test. + ****************************************************/ + +/** + This is part of the standard test machinery. + It creates a dialog (with the instructions), and is the interface + for sending text messages to the user. + To print the instructions, send an array of strings to Sysout.createDialog + WithInstructions method. Put one line of instructions per array entry. + To display a message for the tester to see, simply call Sysout.println + with the string to be displayed. + This mimics System.out.println but works within the test harness as well + as standalone. + */ + +class Sysout +{ + private static TestDialog dialog; + + public static void createDialogWithInstructions( String[] instructions ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + dialog.printInstructions( instructions ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + public static void createDialog( ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + String[] defInstr = { "Instructions will appear here. ", "" } ; + dialog.printInstructions( defInstr ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + + public static void printInstructions( String[] instructions ) + { + dialog.printInstructions( instructions ); + } + + + public static void println( String messageIn ) + { + dialog.displayMessage( messageIn ); + } + +}// Sysout class + +/** + This is part of the standard test machinery. It provides a place for the + test instructions to be displayed, and a place for interactive messages + to the user to be displayed. + To have the test instructions displayed, see Sysout. + To have a message to the user be displayed, see Sysout. + Do not call anything in this dialog directly. + */ +class TestDialog extends Dialog implements ActionListener +{ + + TextArea instructionsText; + TextArea messageText; + int maxStringLength = 80; + Panel buttonP = new Panel(); + Button passB = new Button( "pass" ); + Button failB = new Button( "fail" ); + + //DO NOT call this directly, go through Sysout + public TestDialog( Frame frame, String name ) + { + super( frame, name ); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); + add( "North", instructionsText ); + + messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); + add("Center", messageText); + + passB = new Button( "pass" ); + passB.setActionCommand( "pass" ); + passB.addActionListener( this ); + buttonP.add( "East", passB ); + + failB = new Button( "fail" ); + failB.setActionCommand( "fail" ); + failB.addActionListener( this ); + buttonP.add( "West", failB ); + + add( "South", buttonP ); + pack(); + + setVisible(true); + }// TestDialog() + + //DO NOT call this directly, go through Sysout + public void printInstructions( String[] instructions ) + { + //Clear out any current instructions + instructionsText.setText( "" ); + + //Go down array of instruction strings + + String printStr, remainingStr; + for( int i=0; i < instructions.length; i++ ) + { + //chop up each into pieces maxSringLength long + remainingStr = instructions[ i ]; + while( remainingStr.length() > 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + //else just print + else + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn ) + { + messageText.append( messageIn + "\n" ); + System.out.println(messageIn); + } + + //catch presses of the passed and failed buttons. + //simply call the standard pass() or fail() static methods of + //ModalDialogMultiscreenTest + public void actionPerformed( ActionEvent e ) + { + if( e.getActionCommand() == "pass" ) + { + ModalDialogMultiscreenTest.pass(); + } + else + { + ModalDialogMultiscreenTest.fail(); + } + } + +}// TestDialog class From 05a3bdceae77867dac24a6a4a3272a9e09d16ede Mon Sep 17 00:00:00 2001 From: Sean Coffey Date: Tue, 19 Feb 2013 14:07:25 +0000 Subject: [PATCH 075/180] 7197187: Currency.isPastCutoverDate should be made more robust Reviewed-by: alanb --- jdk/src/share/classes/java/util/Currency.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/jdk/src/share/classes/java/util/Currency.java b/jdk/src/share/classes/java/util/Currency.java index f201dae410a..aa792ea3175 100644 --- a/jdk/src/share/classes/java/util/Currency.java +++ b/jdk/src/share/classes/java/util/Currency.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, 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 @@ -702,7 +702,7 @@ public final class Currency implements Serializable { " ignored since cutover date has not passed :" + curdata, null); return; } - } catch (IndexOutOfBoundsException | NullPointerException | ParseException ex) { + } catch (ParseException ex) { info("currency.properties entry for " + ctry + " ignored since exception encountered :" + ex.getMessage(), null); return; @@ -732,8 +732,7 @@ public final class Currency implements Serializable { setMainTableEntry(ctry.charAt(0), ctry.charAt(1), entry); } - private static boolean isPastCutoverDate(String s) - throws IndexOutOfBoundsException, NullPointerException, ParseException { + private static boolean isPastCutoverDate(String s) throws ParseException { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ROOT); format.setTimeZone(TimeZone.getTimeZone("UTC")); format.setLenient(false); From 117010c6ec3bf38059f43a08787755ce888a6d3e Mon Sep 17 00:00:00 2001 From: Sean Coffey Date: Tue, 19 Feb 2013 14:12:09 +0000 Subject: [PATCH 076/180] 8007315: HttpURLConnection.filterHeaderField method returns null where empty string is expected Reviewed-by: chegar --- .../www/protocol/http/HttpURLConnection.java | 4 +-- .../sun/net/www/protocol/http/HttpOnly.java | 36 +++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index 8003b5a5433..711a1b15a84 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2013, 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 @@ -2637,7 +2637,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection { multipleCookies = true; } - return retValue.length() == 0 ? null : retValue.toString(); + return retValue.length() == 0 ? "" : retValue.toString(); } return value; diff --git a/jdk/test/sun/net/www/protocol/http/HttpOnly.java b/jdk/test/sun/net/www/protocol/http/HttpOnly.java index 60596bad219..6a2ce8256d9 100644 --- a/jdk/test/sun/net/www/protocol/http/HttpOnly.java +++ b/jdk/test/sun/net/www/protocol/http/HttpOnly.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -22,7 +22,7 @@ */ /** * @test - * @bug 7095980 + * @bug 7095980 8007315 * @summary Ensure HttpURLConnection (and supporting APIs) don't expose * HttpOnly cookies */ @@ -52,6 +52,8 @@ import com.sun.net.httpserver.HttpServer; * 4) check HttpOnly cookies received by server * 5) server reply with Set-Cookie containing HttpOnly cookie * 6) check HttpOnly cookies are not accessible from Http client + * 7) check that non-null (empty string) values are returned for + scenario where all values are stripped from original key values */ public class HttpOnly { @@ -177,6 +179,36 @@ public class HttpOnly { " value " + val); } } + + // TEST 7 : check that header keys containing empty key values don't return null + int i = 1; + String key = ""; + String value = ""; + + while (true) { + key = uc.getHeaderFieldKey(i); + value = uc.getHeaderField(i++); + if (key == null && value == null) + break; + + if (key != null) + check(value != null, + "Encountered a null value for key value : " + key); + } + + // TEST 7.5 similar test but use getHeaderFields + respHeaders = uc.getHeaderFields(); + respEntries = respHeaders.entrySet(); + for (Map.Entry> entry : respEntries) { + String header = entry.getKey(); + if (header != null) { + List listValues = entry.getValue(); + for (String value1 : listValues) + check(value1 != null, + "getHeaderFields returned null values for header:, " + + header); + } + } } // HTTP Server From a97003cb2242d44f567200b78cb0604878c2e677 Mon Sep 17 00:00:00 2001 From: Konstantin Shefov Date: Tue, 19 Feb 2013 20:00:02 +0400 Subject: [PATCH 077/180] 8006070: TEST_BUG: Up and down the Y coordinate of the mouse position, the selected item doesn't change for the single list Reviewed-by: serb, anthony --- .../MouseDraggedOutCauseScrollingTest.html | 43 +++ .../MouseDraggedOutCauseScrollingTest.java | 246 ++++++++++++++++++ 2 files changed, 289 insertions(+) create mode 100644 jdk/test/java/awt/List/MouseDraggedOutCauseScrollingTest/MouseDraggedOutCauseScrollingTest.html create mode 100644 jdk/test/java/awt/List/MouseDraggedOutCauseScrollingTest/MouseDraggedOutCauseScrollingTest.java diff --git a/jdk/test/java/awt/List/MouseDraggedOutCauseScrollingTest/MouseDraggedOutCauseScrollingTest.html b/jdk/test/java/awt/List/MouseDraggedOutCauseScrollingTest/MouseDraggedOutCauseScrollingTest.html new file mode 100644 index 00000000000..7049e827033 --- /dev/null +++ b/jdk/test/java/awt/List/MouseDraggedOutCauseScrollingTest/MouseDraggedOutCauseScrollingTest.html @@ -0,0 +1,43 @@ + + + + + + ManualYesNoTest + + + +

    ManualYesNoTest
    Bug ID:

    + +

    See the dialog box (usually in upper left corner) for instructions

    + + + + diff --git a/jdk/test/java/awt/List/MouseDraggedOutCauseScrollingTest/MouseDraggedOutCauseScrollingTest.java b/jdk/test/java/awt/List/MouseDraggedOutCauseScrollingTest/MouseDraggedOutCauseScrollingTest.java new file mode 100644 index 00000000000..8b509a12311 --- /dev/null +++ b/jdk/test/java/awt/List/MouseDraggedOutCauseScrollingTest/MouseDraggedOutCauseScrollingTest.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2013, 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 6243382 8006070 + @summary Dragging of mouse outside of a List and Choice area don't work properly on XAWT + @author Dmitry.Cherepanov@SUN.COM area=awt.list + @run applet/manual=yesno MouseDraggedOutCauseScrollingTest.html +*/ + +import java.applet.Applet; +import java.awt.*; + +public class MouseDraggedOutCauseScrollingTest extends Applet +{ + Choice choice; + List singleList; + List multipleList; + + public void init() + { + this.setLayout (new GridLayout (1, 3)); + + choice = new Choice(); + singleList = new List(3, false); + multipleList = new List(3, true); + + choice.add("Choice"); + for (int i = 1; i < 100; i++){ + choice.add(""+i); + } + + singleList.add("Single list"); + for (int i = 1; i < 100; i++) + singleList.add(""+i); + + multipleList.add("Multiple list"); + for (int i = 1; i < 100; i++) + multipleList.add(""+i); + + this.add(choice); + this.add(singleList); + this.add(multipleList); + + String toolkitName = Toolkit.getDefaultToolkit().getClass().getName(); + if (!toolkitName.equals("sun.awt.X11.XToolkit")) { + String[] instructions = + { + "This test is not applicable to the current platform. Press PASS" + }; + Sysout.createDialogWithInstructions( instructions ); + } else { + String[] instructions = + { + "0) Please note, that this is only Motif/XAWT test. At first, make the applet active", + "1.1) Click on the choice", + "1.2) Press the left button of the mouse and keep on any item of the choice, for example 5", + "1.3) Drag mouse out of the area of the unfurled list, at the same time hold the X coordinate of the mouse position about the same", + "1.4) To make sure, that when the Y coordinate of the mouse position higher of the upper bound of the list then scrolling UP of the list and selected item changes on the upper. If not, the test failed", + "1.5) To make sure, that when the Y coordinate of the mouse position under of the lower bound of the list then scrolling DOWN of the list and selected item changes on the lower. If not, the test failed", + "-----------------------------------", + "2.1) Click on the single list", + "2.2) Press the left button of the mouse and keep on any item of the list, for example 5", + "2.3) Drag mouse out of the area of the unfurled list, at the same time hold the X coordinate of the mouse position about the same", + "2.4) To make sure, that when the Y coordinate of the mouse position higher of the upper bound of the list then scrolling UP of the list and selected item changes on the upper. If not, the test failed", + "2.5) To make sure, that when the Y coordinate of the mouse position under of the lower bound of the list then scrolling DOWN of the list and selected item changes on the lower. If not, the test failed", + "-----------------------------------", + "3.1) Click on the multiple list", + "3.2) Press the left button of the mouse and keep on any item of the list, for example 5", + "3.3) Drag mouse out of the area of the unfurled list, at the same time hold the X coordinate of the mouse position about the same", + "3.4) To make sure, that when the Y coordinate of the mouse position higher of the upper bound of the list then scrolling of the list NO OCCURED and selected item NO CHANGES on the upper. If not, the test failed", + "3.5) To make sure, that when the Y coordinate of the mouse position under of the lower bound of the list then scrolling of the list NO OCCURED and selected item NO CHANGES on the lower. If not, the test failed", + "4) Test passed." + }; + Sysout.createDialogWithInstructions( instructions ); + } + + }//End init() + + public void start () + { + setSize (400,100); + setVisible(true); + validate(); + + }// start() + +}// class ManualYesNoTest + +/**************************************************** + Standard Test Machinery + DO NOT modify anything below -- it's a standard + chunk of code whose purpose is to make user + interaction uniform, and thereby make it simpler + to read and understand someone else's test. + ****************************************************/ + +/** + This is part of the standard test machinery. + It creates a dialog (with the instructions), and is the interface + for sending text messages to the user. + To print the instructions, send an array of strings to Sysout.createDialog + WithInstructions method. Put one line of instructions per array entry. + To display a message for the tester to see, simply call Sysout.println + with the string to be displayed. + This mimics System.out.println but works within the test harness as well + as standalone. + */ + +class Sysout +{ + private static TestDialog dialog; + + public static void createDialogWithInstructions( String[] instructions ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + dialog.printInstructions( instructions ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + public static void createDialog( ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + String[] defInstr = { "Instructions will appear here. ", "" } ; + dialog.printInstructions( defInstr ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + + public static void printInstructions( String[] instructions ) + { + dialog.printInstructions( instructions ); + } + + + public static void println( String messageIn ) + { + dialog.displayMessage( messageIn ); + } + +}// Sysout class + +/** + This is part of the standard test machinery. It provides a place for the + test instructions to be displayed, and a place for interactive messages + to the user to be displayed. + To have the test instructions displayed, see Sysout. + To have a message to the user be displayed, see Sysout. + Do not call anything in this dialog directly. + */ +class TestDialog extends Dialog +{ + + TextArea instructionsText; + TextArea messageText; + int maxStringLength = 80; + + //DO NOT call this directly, go through Sysout + public TestDialog( Frame frame, String name ) + { + super( frame, name ); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); + add( "North", instructionsText ); + + messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); + add("Center", messageText); + + pack(); + + setVisible(true); + }// TestDialog() + + //DO NOT call this directly, go through Sysout + public void printInstructions( String[] instructions ) + { + //Clear out any current instructions + instructionsText.setText( "" ); + + //Go down array of instruction strings + + String printStr, remainingStr; + for( int i=0; i < instructions.length; i++ ) + { + //chop up each into pieces maxSringLength long + remainingStr = instructions[ i ]; + while( remainingStr.length() > 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + //else just print + else + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn ) + { + messageText.append( messageIn + "\n" ); + System.out.println(messageIn); + } + +}// TestDialog class From 8d2a55d5b7185e88dd46420dce4eec477b41a37c Mon Sep 17 00:00:00 2001 From: John Zavgren Date: Tue, 19 Feb 2013 16:19:09 +0000 Subject: [PATCH 078/180] 8007609: WinNTFileSystem_md.c should correctly check value returned from realloc Reviewed-by: alanb, chegar, dholmes --- jdk/src/windows/native/java/io/WinNTFileSystem_md.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jdk/src/windows/native/java/io/WinNTFileSystem_md.c b/jdk/src/windows/native/java/io/WinNTFileSystem_md.c index f1eb449275e..60cc71e0aeb 100644 --- a/jdk/src/windows/native/java/io/WinNTFileSystem_md.c +++ b/jdk/src/windows/native/java/io/WinNTFileSystem_md.c @@ -36,9 +36,7 @@ #include #include -#include "jvm.h" #include "jni.h" -#include "jni_util.h" #include "io_util.h" #include "jlong.h" #include "io_util_md.h" @@ -115,13 +113,15 @@ static WCHAR* getFinalPath(const WCHAR *path) DWORD len = (*GetFinalPathNameByHandle_func)(h, result, MAX_PATH, 0); if (len >= MAX_PATH) { /* retry with a buffer of the right size */ - result = (WCHAR*)realloc(result, (len+1) * sizeof(WCHAR)); - if (result != NULL) { + WCHAR* newResult = (WCHAR*)realloc(result, (len+1) * sizeof(WCHAR)); + if (newResult != NULL) { + result = newResult; len = (*GetFinalPathNameByHandle_func)(h, result, len, 0); } else { len = 0; } } + if (len > 0) { /** * Strip prefix (should be \\?\ or \\?\UNC) From 78fe727c6d75fdb4de25144dbaaa25cbc9b43e81 Mon Sep 17 00:00:00 2001 From: Eric McCorkle Date: Tue, 19 Feb 2013 17:09:25 +0000 Subject: [PATCH 079/180] 8008312: Re-enable MethodParameter tests in JDK Reviewed-by: darcy --- .../classes/java/lang/reflect/Parameter.java | 4 ++- .../reflect/Parameter/WithParameters.java | 25 +++++++++---------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/jdk/src/share/classes/java/lang/reflect/Parameter.java b/jdk/src/share/classes/java/lang/reflect/Parameter.java index 9c808310c0c..e479bfd9326 100644 --- a/jdk/src/share/classes/java/lang/reflect/Parameter.java +++ b/jdk/src/share/classes/java/lang/reflect/Parameter.java @@ -115,7 +115,9 @@ public final class Parameter implements AnnotatedElement { (type.toString()); sb.append(Modifier.toString(getModifiers())); - sb.append(" "); + + if(0 != modifiers) + sb.append(" "); if(isVarArgs()) sb.append(typename.replaceFirst("\\[\\]$", "...")); diff --git a/jdk/test/java/lang/reflect/Parameter/WithParameters.java b/jdk/test/java/lang/reflect/Parameter/WithParameters.java index c4ffec6de30..bddebf1c782 100644 --- a/jdk/test/java/lang/reflect/Parameter/WithParameters.java +++ b/jdk/test/java/lang/reflect/Parameter/WithParameters.java @@ -22,7 +22,6 @@ */ /* - * @ignore * @test * @compile -parameters WithParameters.java * @run main WithParameters @@ -85,8 +84,8 @@ public class WithParameters { error++; } } - if(parameters[0].toString().equals("int quux")) { - System.err.println("toString for quux is wrong"); + if(!parameters[0].toString().equals("final int quux")) { + System.err.println("toString for quux is wrong, expected \"final int quux\", got \"" + parameters[0] + "\""); error++; } if(parameters[0].getModifiers() != Modifier.FINAL) { @@ -101,8 +100,8 @@ public class WithParameters { System.err.println("getParameterizedType for quux is wrong"); error++; } - if(parameters[1].toString().equals("WithParameters$Foo quuux")) { - System.err.println("toString for quuux is wrong"); + if(!parameters[1].toString().equals("WithParameters$Foo quuux")) { + System.err.println("toString for quuux is wrong, expected \"WithParameters$Foo quuux\", got \"" + parameters[1] + "\""); error++; } if(parameters[1].isVarArgs()) { @@ -121,8 +120,8 @@ public class WithParameters { System.err.println("getAnnotations has the wrong annotation"); error++; } - if(parameters[2].toString().equals("java.util.List quuux")) { - System.err.println("toString for l is wrong"); + if(!parameters[2].toString().equals("java.util.List l")) { + System.err.println("toString for l is wrong, expected \"java.util.List l\", got \"" + parameters[2] + "\""); error++; } if(parameters[2].isVarArgs()) { @@ -149,8 +148,8 @@ public class WithParameters { error++; } } - if(parameters[3].toString().equals("java.util.List l")) { - System.err.println("toString for l2 is wrong"); + if(!parameters[3].toString().equals("java.util.List l2")) { + System.err.println("toString for l2 is wrong, expected \"java.util.List l2\", got \"" + parameters[3] + "\""); error++; } if(parameters[3].isVarArgs()) { @@ -177,8 +176,8 @@ public class WithParameters { error++; } } - if(parameters[4].toString().equals("java.util.List l")) { - System.err.println("toString for l3 is wrong"); + if(!parameters[4].toString().equals("java.util.List l3")) { + System.err.println("toString for l3 is wrong, expected \"java.util.List l3\", got \"" + parameters[3] + "\""); error++; } if(parameters[4].isVarArgs()) { @@ -212,8 +211,8 @@ public class WithParameters { } } } - if(parameters[5].toString().equals("java.lang.String... rest")) { - System.err.println("toString for l is wrong"); + if(!parameters[5].toString().equals("java.lang.String... rest")) { + System.err.println("toString for rest is wrong, expected \"java.lang.String... rest\", got \"" + parameters[5] + "\""); error++; } if(!parameters[5].isVarArgs()) { From 872cd491a72ff586ad960d40f1c7760d62a4a500 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 19 Feb 2013 10:34:26 -0800 Subject: [PATCH 080/180] 7092447: Clarify the default locale used in each locale sensitive operation Reviewed-by: okutsu --- .../share/classes/java/text/DateFormat.java | 42 ++++++++++++--- .../classes/java/text/DateFormatSymbols.java | 13 ++++- .../classes/java/text/DecimalFormat.java | 6 ++- .../java/text/DecimalFormatSymbols.java | 13 ++++- .../classes/java/text/MessageFormat.java | 3 +- .../share/classes/java/text/NumberFormat.java | 37 ++++++++++++-- .../classes/java/text/SimpleDateFormat.java | 11 +++- .../time/format/DateTimeFormatSymbols.java | 8 ++- jdk/src/share/classes/java/util/Calendar.java | 9 ++-- jdk/src/share/classes/java/util/Currency.java | 20 ++++++-- .../share/classes/java/util/Formatter.java | 51 ++++++++++++------- .../classes/java/util/GregorianCalendar.java | 6 ++- jdk/src/share/classes/java/util/Locale.java | 42 ++++++++++----- jdk/src/share/classes/java/util/Scanner.java | 5 +- 14 files changed, 204 insertions(+), 62 deletions(-) diff --git a/jdk/src/share/classes/java/text/DateFormat.java b/jdk/src/share/classes/java/text/DateFormat.java index d1bb6e682dd..fcb21e6928c 100644 --- a/jdk/src/share/classes/java/text/DateFormat.java +++ b/jdk/src/share/classes/java/text/DateFormat.java @@ -439,7 +439,12 @@ public abstract class DateFormat extends Format { /** * Gets the time formatter with the default formatting style - * for the default locale. + * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. + *

    This is equivalent to calling + * {@link #getTimeInstance(int, Locale) getTimeInstance(DEFAULT, + * Locale.getDefault(Locale.Category.FORMAT))}. + * @see java.util.Locale#getDefault(java.util.Locale.Category) + * @see java.util.Locale.Category#FORMAT * @return a time formatter. */ public final static DateFormat getTimeInstance() @@ -449,7 +454,12 @@ public abstract class DateFormat extends Format { /** * Gets the time formatter with the given formatting style - * for the default locale. + * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. + *

    This is equivalent to calling + * {@link #getTimeInstance(int, Locale) getTimeInstance(style, + * Locale.getDefault(Locale.Category.FORMAT))}. + * @see java.util.Locale#getDefault(java.util.Locale.Category) + * @see java.util.Locale.Category#FORMAT * @param style the given formatting style. For example, * SHORT for "h:mm a" in the US locale. * @return a time formatter. @@ -475,7 +485,12 @@ public abstract class DateFormat extends Format { /** * Gets the date formatter with the default formatting style - * for the default locale. + * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. + *

    This is equivalent to calling + * {@link #getDateInstance(int, Locale) getDateInstance(DEFAULT, + * Locale.getDefault(Locale.Category.FORMAT))}. + * @see java.util.Locale#getDefault(java.util.Locale.Category) + * @see java.util.Locale.Category#FORMAT * @return a date formatter. */ public final static DateFormat getDateInstance() @@ -485,7 +500,12 @@ public abstract class DateFormat extends Format { /** * Gets the date formatter with the given formatting style - * for the default locale. + * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. + *

    This is equivalent to calling + * {@link #getDateInstance(int, Locale) getDateInstance(style, + * Locale.getDefault(Locale.Category.FORMAT))}. + * @see java.util.Locale#getDefault(java.util.Locale.Category) + * @see java.util.Locale.Category#FORMAT * @param style the given formatting style. For example, * SHORT for "M/d/yy" in the US locale. * @return a date formatter. @@ -511,7 +531,12 @@ public abstract class DateFormat extends Format { /** * Gets the date/time formatter with the default formatting style - * for the default locale. + * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. + *

    This is equivalent to calling + * {@link #getDateTimeInstance(int, int, Locale) getDateTimeInstance(DEFAULT, + * DEFAULT, Locale.getDefault(Locale.Category.FORMAT))}. + * @see java.util.Locale#getDefault(java.util.Locale.Category) + * @see java.util.Locale.Category#FORMAT * @return a date/time formatter. */ public final static DateFormat getDateTimeInstance() @@ -521,7 +546,12 @@ public abstract class DateFormat extends Format { /** * Gets the date/time formatter with the given date and time - * formatting styles for the default locale. + * formatting styles for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. + *

    This is equivalent to calling + * {@link #getDateTimeInstance(int, int, Locale) getDateTimeInstance(dateStyle, + * timeStyle, Locale.getDefault(Locale.Category.FORMAT))}. + * @see java.util.Locale#getDefault(java.util.Locale.Category) + * @see java.util.Locale.Category#FORMAT * @param dateStyle the given date formatting style. For example, * SHORT for "M/d/yy" in the US locale. * @param timeStyle the given time formatting style. For example, diff --git a/jdk/src/share/classes/java/text/DateFormatSymbols.java b/jdk/src/share/classes/java/text/DateFormatSymbols.java index b4c380d2c05..80e4f03a38a 100644 --- a/jdk/src/share/classes/java/text/DateFormatSymbols.java +++ b/jdk/src/share/classes/java/text/DateFormatSymbols.java @@ -104,14 +104,19 @@ public class DateFormatSymbols implements Serializable, Cloneable { /** * Construct a DateFormatSymbols object by loading format data from - * resources for the default locale. This constructor can only + * resources for the default {@link java.util.Locale.Category#FORMAT FORMAT} + * locale. This constructor can only * construct instances for the locales supported by the Java * runtime environment, not for those supported by installed * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider} * implementations. For full locale coverage, use the * {@link #getInstance(Locale) getInstance} method. - * + *

    This is equivalent to calling + * {@link #DateFormatSymbols(Locale) + * DateFormatSymbols(Locale.getDefault(Locale.Category.FORMAT))}. * @see #getInstance() + * @see java.util.Locale#getDefault(java.util.Locale.Category) + * @see java.util.Locale.Category#FORMAT * @exception java.util.MissingResourceException * if the resources for the default locale cannot be * found or cannot be loaded. @@ -302,6 +307,10 @@ public class DateFormatSymbols implements Serializable, Cloneable { * as for those supported by installed * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider} * implementations. + *

    This is equivalent to calling {@link #getInstance(Locale) + * getInstance(Locale.getDefault(Locale.Category.FORMAT))}. + * @see java.util.Locale#getDefault(java.util.Locale.Category) + * @see java.util.Locale.Category#FORMAT * @return a DateFormatSymbols instance. * @since 1.6 */ diff --git a/jdk/src/share/classes/java/text/DecimalFormat.java b/jdk/src/share/classes/java/text/DecimalFormat.java index 38c930372c1..bd37b2ed471 100644 --- a/jdk/src/share/classes/java/text/DecimalFormat.java +++ b/jdk/src/share/classes/java/text/DecimalFormat.java @@ -381,7 +381,8 @@ public class DecimalFormat extends NumberFormat { /** * Creates a DecimalFormat using the default pattern and symbols - * for the default locale. This is a convenient way to obtain a + * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. + * This is a convenient way to obtain a * DecimalFormat when internationalization is not the main concern. *

    * To obtain standard formats for a given locale, use the factory methods @@ -411,7 +412,8 @@ public class DecimalFormat extends NumberFormat { /** * Creates a DecimalFormat using the given pattern and the symbols - * for the default locale. This is a convenient way to obtain a + * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. + * This is a convenient way to obtain a * DecimalFormat when internationalization is not the main concern. *

    * To obtain standard formats for a given locale, use the factory methods diff --git a/jdk/src/share/classes/java/text/DecimalFormatSymbols.java b/jdk/src/share/classes/java/text/DecimalFormatSymbols.java index 9274208fe8f..f0b2212eaf5 100644 --- a/jdk/src/share/classes/java/text/DecimalFormatSymbols.java +++ b/jdk/src/share/classes/java/text/DecimalFormatSymbols.java @@ -71,13 +71,19 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter; public class DecimalFormatSymbols implements Cloneable, Serializable { /** - * Create a DecimalFormatSymbols object for the default locale. + * Create a DecimalFormatSymbols object for the default + * {@link java.util.Locale.Category#FORMAT FORMAT} locale. * This constructor can only construct instances for the locales * supported by the Java runtime environment, not for those * supported by installed * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider} * implementations. For full locale coverage, use the * {@link #getInstance(Locale) getInstance} method. + *

    This is equivalent to calling + * {@link #DecimalFormatSymbols(Locale) + * DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMAT))}. + * @see java.util.Locale#getDefault(java.util.Locale.Category) + * @see java.util.Locale.Category#FORMAT */ public DecimalFormatSymbols() { initialize( Locale.getDefault(Locale.Category.FORMAT) ); @@ -133,6 +139,11 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { * as for those supported by installed * {@link java.text.spi.DecimalFormatSymbolsProvider * DecimalFormatSymbolsProvider} implementations. + *

    This is equivalent to calling + * {@link #getInstance(Locale) + * getInstance(Locale.getDefault(Locale.Category.FORMAT))}. + * @see java.util.Locale#getDefault(java.util.Locale.Category) + * @see java.util.Locale.Category#FORMAT * @return a DecimalFormatSymbols instance. * @since 1.6 */ diff --git a/jdk/src/share/classes/java/text/MessageFormat.java b/jdk/src/share/classes/java/text/MessageFormat.java index e695b37a679..e5c8c811f04 100644 --- a/jdk/src/share/classes/java/text/MessageFormat.java +++ b/jdk/src/share/classes/java/text/MessageFormat.java @@ -348,7 +348,8 @@ public class MessageFormat extends Format { private static final long serialVersionUID = 6479157306784022952L; /** - * Constructs a MessageFormat for the default locale and the + * Constructs a MessageFormat for the default + * {@link java.util.Locale.Category#FORMAT FORMAT} locale and the * specified pattern. * The constructor first sets the locale, then parses the pattern and * creates a list of subformats for the format elements contained in it. diff --git a/jdk/src/share/classes/java/text/NumberFormat.java b/jdk/src/share/classes/java/text/NumberFormat.java index eaed665e54c..c1b8310096b 100644 --- a/jdk/src/share/classes/java/text/NumberFormat.java +++ b/jdk/src/share/classes/java/text/NumberFormat.java @@ -389,7 +389,8 @@ public abstract class NumberFormat extends Format { //============== Locale Stuff ===================== /** - * Returns a general-purpose number format for the current default locale. + * Returns a general-purpose number format for the current default + * {@link java.util.Locale.Category#FORMAT FORMAT} locale. * This is the same as calling * {@link #getNumberInstance() getNumberInstance()}. */ @@ -407,7 +408,13 @@ public abstract class NumberFormat extends Format { } /** - * Returns a general-purpose number format for the current default locale. + * Returns a general-purpose number format for the current default + * {@link java.util.Locale.Category#FORMAT FORMAT} locale. + *

    This is equivalent to calling + * {@link #getNumberInstance(Locale) + * getNumberInstance(Locale.getDefault(Locale.Category.FORMAT))}. + * @see java.util.Locale#getDefault(java.util.Locale.Category) + * @see java.util.Locale.Category#FORMAT */ public final static NumberFormat getNumberInstance() { return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE); @@ -421,14 +428,20 @@ public abstract class NumberFormat extends Format { } /** - * Returns an integer number format for the current default locale. The + * Returns an integer number format for the current default + * {@link java.util.Locale.Category#FORMAT FORMAT} locale. The * returned number format is configured to round floating point numbers * to the nearest integer using half-even rounding (see {@link * java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}) for formatting, * and to parse only the integer part of an input string (see {@link * #isParseIntegerOnly isParseIntegerOnly}). + *

    This is equivalent to calling + * {@link #getIntegerInstance(Locale) + * getIntegerInstance(Locale.getDefault(Locale.Category.FORMAT))}. * * @see #getRoundingMode() + * @see java.util.Locale#getDefault(java.util.Locale.Category) + * @see java.util.Locale.Category#FORMAT * @return a number format for integer values * @since 1.4 */ @@ -453,7 +466,14 @@ public abstract class NumberFormat extends Format { } /** - * Returns a currency format for the current default locale. + * Returns a currency format for the current default + * {@link java.util.Locale.Category#FORMAT FORMAT} locale. + *

    This is equivalent to calling + * {@link #getCurrencyInstance(Locale) + * getCurrencyInstance(Locale.getDefault(Locale.Category.FORMAT))}. + * + * @see java.util.Locale#getDefault(java.util.Locale.Category) + * @see java.util.Locale.Category#FORMAT */ public final static NumberFormat getCurrencyInstance() { return getInstance(Locale.getDefault(Locale.Category.FORMAT), CURRENCYSTYLE); @@ -467,7 +487,14 @@ public abstract class NumberFormat extends Format { } /** - * Returns a percentage format for the current default locale. + * Returns a percentage format for the current default + * {@link java.util.Locale.Category#FORMAT FORMAT} locale. + *

    This is equivalent to calling + * {@link #getPercentInstance(Locale) + * getPercentInstance(Locale.getDefault(Locale.Category.FORMAT))}. + * + * @see java.util.Locale#getDefault(java.util.Locale.Category) + * @see java.util.Locale.Category#FORMAT */ public final static NumberFormat getPercentInstance() { return getInstance(Locale.getDefault(Locale.Category.FORMAT), PERCENTSTYLE); diff --git a/jdk/src/share/classes/java/text/SimpleDateFormat.java b/jdk/src/share/classes/java/text/SimpleDateFormat.java index 0c1f4aa6a61..82b48964eea 100644 --- a/jdk/src/share/classes/java/text/SimpleDateFormat.java +++ b/jdk/src/share/classes/java/text/SimpleDateFormat.java @@ -547,7 +547,8 @@ public class SimpleDateFormat extends DateFormat { /** * Constructs a SimpleDateFormat using the default pattern and - * date format symbols for the default locale. + * date format symbols for the default + * {@link java.util.Locale.Category#FORMAT FORMAT} locale. * Note: This constructor may not support all locales. * For full coverage, use the factory methods in the {@link DateFormat} * class. @@ -560,11 +561,17 @@ public class SimpleDateFormat extends DateFormat { /** * Constructs a SimpleDateFormat using the given pattern and - * the default date format symbols for the default locale. + * the default date format symbols for the default + * {@link java.util.Locale.Category#FORMAT FORMAT} locale. * Note: This constructor may not support all locales. * For full coverage, use the factory methods in the {@link DateFormat} * class. + *

    This is equivalent to calling + * {@link #SimpleDateFormat(String, Locale) + * SimpleDateFormat(pattern, Locale.getDefault(Locale.Category.FORMAT))}. * + * @see java.util.Locale#getDefault(java.util.Locale.Category) + * @see java.util.Locale.Category#FORMAT * @param pattern the pattern describing the date and time format * @exception NullPointerException if the given pattern is null * @exception IllegalArgumentException if the given pattern is invalid diff --git a/jdk/src/share/classes/java/time/format/DateTimeFormatSymbols.java b/jdk/src/share/classes/java/time/format/DateTimeFormatSymbols.java index 14a116760f1..0bfe8441020 100644 --- a/jdk/src/share/classes/java/time/format/DateTimeFormatSymbols.java +++ b/jdk/src/share/classes/java/time/format/DateTimeFormatSymbols.java @@ -121,10 +121,16 @@ public final class DateTimeFormatSymbols { } /** - * Obtains symbols for the default locale. + * Obtains symbols for the default + * {@link java.util.Locale.Category#FORMAT FORMAT} locale. *

    * This method provides access to locale sensitive symbols. + *

    + * This is equivalent to calling + * {@link #of(Locale) + * of(Locale.getDefault(Locale.Category.FORMAT))}. * + * @see java.util.Locale.Category#FORMAT * @return the info, not null */ public static DateTimeFormatSymbols ofDefaultLocale() { diff --git a/jdk/src/share/classes/java/util/Calendar.java b/jdk/src/share/classes/java/util/Calendar.java index f14ee6d6ef4..c57f50c59b3 100644 --- a/jdk/src/share/classes/java/util/Calendar.java +++ b/jdk/src/share/classes/java/util/Calendar.java @@ -1572,7 +1572,8 @@ public abstract class Calendar implements Serializable, Cloneable, ComparableCalendar returned is based on the current time - * in the default time zone with the default locale. + * in the default time zone with the default + * {@link Locale.Category#FORMAT FORMAT} locale. * * @return a Calendar. */ @@ -1614,7 +1616,8 @@ public abstract class Calendar implements Serializable, Cloneable, ComparableCalendar returned is based on the current time - * in the given time zone with the default locale. + * in the given time zone with the default + * {@link Locale.Category#FORMAT FORMAT} locale. * * @param zone the time zone to use * @return a Calendar. diff --git a/jdk/src/share/classes/java/util/Currency.java b/jdk/src/share/classes/java/util/Currency.java index aa792ea3175..09e7046849b 100644 --- a/jdk/src/share/classes/java/util/Currency.java +++ b/jdk/src/share/classes/java/util/Currency.java @@ -472,12 +472,18 @@ public final class Currency implements Serializable { } /** - * Gets the symbol of this currency for the default locale. + * Gets the symbol of this currency for the default + * {@link Locale.Category#DISPLAY DISPLAY} locale. * For example, for the US Dollar, the symbol is "$" if the default * locale is the US, while for other locales it may be "US$". If no * symbol can be determined, the ISO 4217 currency code is returned. + *

    + * This is equivalent to calling + * {@link #getSymbol(Locale) + * getSymbol(Locale.getDefault(Locale.Category.DISPLAY))}. * - * @return the symbol of this currency for the default locale + * @return the symbol of this currency for the default + * {@link Locale.Category#DISPLAY DISPLAY} locale */ public String getSymbol() { return getSymbol(Locale.getDefault(Locale.Category.DISPLAY)); @@ -533,10 +539,16 @@ public final class Currency implements Serializable { /** * Gets the name that is suitable for displaying this currency for - * the default locale. If there is no suitable display name found + * the default {@link Locale.Category#DISPLAY DISPLAY} locale. + * If there is no suitable display name found * for the default locale, the ISO 4217 currency code is returned. + *

    + * This is equivalent to calling + * {@link #getDisplayName(Locale) + * getDisplayName(Locale.getDefault(Locale.Category.DISPLAY))}. * - * @return the display name of this currency for the default locale + * @return the display name of this currency for the default + * {@link Locale.Category#DISPLAY DISPLAY} locale * @since 1.7 */ public String getDisplayName() { diff --git a/jdk/src/share/classes/java/util/Formatter.java b/jdk/src/share/classes/java/util/Formatter.java index c645861521c..65a6f0b3634 100644 --- a/jdk/src/share/classes/java/util/Formatter.java +++ b/jdk/src/share/classes/java/util/Formatter.java @@ -1900,7 +1900,8 @@ public final class Formatter implements Closeable, Flushable { * which may be retrieved by invoking {@link #out out()} and whose * current content may be converted into a string by invoking {@link * #toString toString()}. The locale used is the {@linkplain - * Locale#getDefault() default locale} for this instance of the Java + * Locale#getDefault(Locale.Category) default locale} for + * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java * virtual machine. */ public Formatter() { @@ -1910,8 +1911,10 @@ public final class Formatter implements Closeable, Flushable { /** * Constructs a new formatter with the specified destination. * - *

    The locale used is the {@linkplain Locale#getDefault() default - * locale} for this instance of the Java virtual machine. + *

    The locale used is the {@linkplain + * Locale#getDefault(Locale.Category) default locale} for + * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java + * virtual machine. * * @param a * Destination for the formatted output. If {@code a} is @@ -1961,8 +1964,10 @@ public final class Formatter implements Closeable, Flushable { * java.nio.charset.Charset#defaultCharset() default charset} for this * instance of the Java virtual machine. * - *

    The locale used is the {@linkplain Locale#getDefault() default - * locale} for this instance of the Java virtual machine. + *

    The locale used is the {@linkplain + * Locale#getDefault(Locale.Category) default locale} for + * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java + * virtual machine. * * @param fileName * The name of the file to use as the destination of this @@ -1989,8 +1994,10 @@ public final class Formatter implements Closeable, Flushable { /** * Constructs a new formatter with the specified file name and charset. * - *

    The locale used is the {@linkplain Locale#getDefault default - * locale} for this instance of the Java virtual machine. + *

    The locale used is the {@linkplain + * Locale#getDefault(Locale.Category) default locale} for + * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java + * virtual machine. * * @param fileName * The name of the file to use as the destination of this @@ -2068,8 +2075,10 @@ public final class Formatter implements Closeable, Flushable { * java.nio.charset.Charset#defaultCharset() default charset} for this * instance of the Java virtual machine. * - *

    The locale used is the {@linkplain Locale#getDefault() default - * locale} for this instance of the Java virtual machine. + *

    The locale used is the {@linkplain + * Locale#getDefault(Locale.Category) default locale} for + * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java + * virtual machine. * * @param file * The file to use as the destination of this formatter. If the @@ -2096,8 +2105,10 @@ public final class Formatter implements Closeable, Flushable { /** * Constructs a new formatter with the specified file and charset. * - *

    The locale used is the {@linkplain Locale#getDefault default - * locale} for this instance of the Java virtual machine. + *

    The locale used is the {@linkplain + * Locale#getDefault(Locale.Category) default locale} for + * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java + * virtual machine. * * @param file * The file to use as the destination of this formatter. If the @@ -2171,8 +2182,10 @@ public final class Formatter implements Closeable, Flushable { /** * Constructs a new formatter with the specified print stream. * - *

    The locale used is the {@linkplain Locale#getDefault() default - * locale} for this instance of the Java virtual machine. + *

    The locale used is the {@linkplain + * Locale#getDefault(Locale.Category) default locale} for + * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java + * virtual machine. * *

    Characters are written to the given {@link java.io.PrintStream * PrintStream} object and are therefore encoded using that object's @@ -2193,8 +2206,10 @@ public final class Formatter implements Closeable, Flushable { * java.nio.charset.Charset#defaultCharset() default charset} for this * instance of the Java virtual machine. * - *

    The locale used is the {@linkplain Locale#getDefault() default - * locale} for this instance of the Java virtual machine. + *

    The locale used is the {@linkplain + * Locale#getDefault(Locale.Category) default locale} for + * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java + * virtual machine. * * @param os * The output stream to use as the destination of this formatter. @@ -2209,8 +2224,10 @@ public final class Formatter implements Closeable, Flushable { * Constructs a new formatter with the specified output stream and * charset. * - *

    The locale used is the {@linkplain Locale#getDefault default - * locale} for this instance of the Java virtual machine. + *

    The locale used is the {@linkplain + * Locale#getDefault(Locale.Category) default locale} for + * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java + * virtual machine. * * @param os * The output stream to use as the destination of this formatter. diff --git a/jdk/src/share/classes/java/util/GregorianCalendar.java b/jdk/src/share/classes/java/util/GregorianCalendar.java index 4e063ee70ba..96501286e75 100644 --- a/jdk/src/share/classes/java/util/GregorianCalendar.java +++ b/jdk/src/share/classes/java/util/GregorianCalendar.java @@ -587,7 +587,8 @@ public class GregorianCalendar extends Calendar { /** * Constructs a default GregorianCalendar using the current time - * in the default time zone with the default locale. + * in the default time zone with the default + * {@link Locale.Category#FORMAT FORMAT} locale. */ public GregorianCalendar() { this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT)); @@ -596,7 +597,8 @@ public class GregorianCalendar extends Calendar { /** * Constructs a GregorianCalendar based on the current time - * in the given time zone with the default locale. + * in the given time zone with the default + * {@link Locale.Category#FORMAT FORMAT} locale. * * @param zone the given time zone. */ diff --git a/jdk/src/share/classes/java/util/Locale.java b/jdk/src/share/classes/java/util/Locale.java index 198148206d1..69f277659ab 100644 --- a/jdk/src/share/classes/java/util/Locale.java +++ b/jdk/src/share/classes/java/util/Locale.java @@ -351,7 +351,8 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter; * you can use getDisplayLanguage to get the name of * the language suitable for displaying to the user. Interestingly, * the getDisplayXXX methods are themselves locale-sensitive - * and have two versions: one that uses the default locale and one + * and have two versions: one that uses the default + * {@link Locale.Category#DISPLAY DISPLAY} locale and one * that uses the locale specified as an argument. * *

    The Java Platform provides a number of classes that perform locale-sensitive @@ -369,7 +370,8 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter; * * * Each of these methods has two variants; one with an explicit locale - * and one without; the latter uses the default locale: + * and one without; the latter uses the default + * {@link Locale.Category#FORMAT FORMAT} locale: *

    *
      *     NumberFormat.getInstance(myLocale)
    @@ -1645,11 +1647,15 @@ public final class Locale implements Cloneable, Serializable {
         /**
          * Returns a name for the locale's language that is appropriate for display to the
          * user.
    -     * If possible, the name returned will be localized for the default locale.
    -     * For example, if the locale is fr_FR and the default locale
    +     * If possible, the name returned will be localized for the default
    +     * {@link Locale.Category#DISPLAY DISPLAY} locale.
    +     * For example, if the locale is fr_FR and the default
    +     * {@link Locale.Category#DISPLAY DISPLAY} locale
          * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
    -     * the default locale is fr_FR, getDisplayLanguage() will return "anglais".
    -     * If the name returned cannot be localized for the default locale,
    +     * the default {@link Locale.Category#DISPLAY DISPLAY} locale is fr_FR,
    +     * getDisplayLanguage() will return "anglais".
    +     * If the name returned cannot be localized for the default
    +     * {@link Locale.Category#DISPLAY DISPLAY} locale,
          * (say, we don't have a Japanese name for Croatian),
          * this function falls back on the English name, and uses the ISO code as a last-resort
          * value.  If the locale doesn't specify a language, this function returns the empty string.
    @@ -1679,10 +1685,12 @@ public final class Locale implements Cloneable, Serializable {
     
         /**
          * Returns a name for the the locale's script that is appropriate for display to
    -     * the user. If possible, the name will be localized for the default locale.  Returns
    +     * the user. If possible, the name will be localized for the default
    +     * {@link Locale.Category#DISPLAY DISPLAY} locale.  Returns
          * the empty string if this locale doesn't specify a script code.
          *
    -     * @return the display name of the script code for the current default locale
    +     * @return the display name of the script code for the current default
    +     *     {@link Locale.Category#DISPLAY DISPLAY} locale
          * @since 1.7
          */
         public String getDisplayScript() {
    @@ -1695,7 +1703,8 @@ public final class Locale implements Cloneable, Serializable {
          * localized for the given locale. Returns the empty string if
          * this locale doesn't specify a script code.
          *
    -     * @return the display name of the script code for the current default locale
    +     * @return the display name of the script code for the current default
    +     * {@link Locale.Category#DISPLAY DISPLAY} locale
          * @throws NullPointerException if inLocale is null
          * @since 1.7
          */
    @@ -1706,11 +1715,15 @@ public final class Locale implements Cloneable, Serializable {
         /**
          * Returns a name for the locale's country that is appropriate for display to the
          * user.
    -     * If possible, the name returned will be localized for the default locale.
    -     * For example, if the locale is fr_FR and the default locale
    +     * If possible, the name returned will be localized for the default
    +     * {@link Locale.Category#DISPLAY DISPLAY} locale.
    +     * For example, if the locale is fr_FR and the default
    +     * {@link Locale.Category#DISPLAY DISPLAY} locale
          * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
    -     * the default locale is fr_FR, getDisplayCountry() will return "Etats-Unis".
    -     * If the name returned cannot be localized for the default locale,
    +     * the default {@link Locale.Category#DISPLAY DISPLAY} locale is fr_FR,
    +     * getDisplayCountry() will return "Etats-Unis".
    +     * If the name returned cannot be localized for the default
    +     * {@link Locale.Category#DISPLAY DISPLAY} locale,
          * (say, we don't have a Japanese name for Croatia),
          * this function falls back on the English name, and uses the ISO code as a last-resort
          * value.  If the locale doesn't specify a country, this function returns the empty string.
    @@ -1762,7 +1775,8 @@ public final class Locale implements Cloneable, Serializable {
     
         /**
          * Returns a name for the locale's variant code that is appropriate for display to the
    -     * user.  If possible, the name will be localized for the default locale.  If the locale
    +     * user.  If possible, the name will be localized for the default
    +     * {@link Locale.Category#DISPLAY DISPLAY} locale.  If the locale
          * doesn't specify a variant code, this function returns the empty string.
          */
         public final String getDisplayVariant() {
    diff --git a/jdk/src/share/classes/java/util/Scanner.java b/jdk/src/share/classes/java/util/Scanner.java
    index 3c558114ac7..cc19b0d1257 100644
    --- a/jdk/src/share/classes/java/util/Scanner.java
    +++ b/jdk/src/share/classes/java/util/Scanner.java
    @@ -151,7 +151,8 @@ import sun.misc.LRUCache;
      * 

    An instance of this class is capable of scanning numbers in the standard * formats as well as in the formats of the scanner's locale. A scanner's * initial locale is the value returned by the {@link - * java.util.Locale#getDefault} method; it may be changed via the {@link + * java.util.Locale#getDefault(Locale.Category) + * Locale.getDefault(Locale.Category.FORMAT)} method; it may be changed via the {@link * #useLocale} method. The {@link #reset} method will reset the value of the * scanner's locale to the initial locale regardless of whether it was * previously changed. @@ -2641,7 +2642,7 @@ public final class Scanner implements Iterator, Closeable { * *

          *   scanner.useDelimiter("\\p{javaWhitespace}+")
    -     *          .useLocale(Locale.getDefault())
    +     *          .useLocale(Locale.getDefault(Locale.Category.FORMAT))
          *          .useRadix(10);
          * 
    * From 29658bd3b437d93701610a25551b0c7f6c46a4e9 Mon Sep 17 00:00:00 2001 From: Alexey Utkin Date: Wed, 20 Feb 2013 16:39:35 +0400 Subject: [PATCH 081/180] 8007454: (process) SetHandleInformation parameters DWORD (not BOOLEAN) The SetHandleInformation arguments list was fixed. Reviewed-by: alanb --- .../windows/native/java/lang/ProcessImpl_md.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/jdk/src/windows/native/java/lang/ProcessImpl_md.c b/jdk/src/windows/native/java/lang/ProcessImpl_md.c index dfa59f99efd..5b45f8f24f2 100644 --- a/jdk/src/windows/native/java/lang/ProcessImpl_md.c +++ b/jdk/src/windows/native/java/lang/ProcessImpl_md.c @@ -120,10 +120,12 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, goto Catch; } si.hStdInput = inRead; - SetHandleInformation(inWrite, HANDLE_FLAG_INHERIT, FALSE); + SetHandleInformation(inWrite, HANDLE_FLAG_INHERIT, 0); handles[0] = (jlong) inWrite; } - SetHandleInformation(si.hStdInput, HANDLE_FLAG_INHERIT, TRUE); + SetHandleInformation(si.hStdInput, + HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT); if (handles[1] != (jlong) -1) { si.hStdOutput = (HANDLE) handles[1]; @@ -134,10 +136,12 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, goto Catch; } si.hStdOutput = outWrite; - SetHandleInformation(outRead, HANDLE_FLAG_INHERIT, FALSE); + SetHandleInformation(outRead, HANDLE_FLAG_INHERIT, 0); handles[1] = (jlong) outRead; } - SetHandleInformation(si.hStdOutput, HANDLE_FLAG_INHERIT, TRUE); + SetHandleInformation(si.hStdOutput, + HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT); if (redirectErrorStream) { si.hStdError = si.hStdOutput; @@ -151,10 +155,12 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, goto Catch; } si.hStdError = errWrite; - SetHandleInformation(errRead, HANDLE_FLAG_INHERIT, FALSE); + SetHandleInformation(errRead, HANDLE_FLAG_INHERIT, 0); handles[2] = (jlong) errRead; } - SetHandleInformation(si.hStdError, HANDLE_FLAG_INHERIT, TRUE); + SetHandleInformation(si.hStdError, + HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT); processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT; ret = CreateProcessW(0, /* executable name */ From 5eb01d191d98da090682a3f85842e01b357ca7d9 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Wed, 20 Feb 2013 13:23:56 -0800 Subject: [PATCH 082/180] 8008352: java/lang/instrument/RedefineSubclassWithTwoInterfaces.sh fails on MKS Use more portable pattern counting constructs in test driver. Reviewed-by: sspitsyn, sla, coleenp --- .../RedefineSubclassWithTwoInterfaces.sh | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfaces.sh b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfaces.sh index 6deb7ce6e44..850fac252a1 100644 --- a/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfaces.sh +++ b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfaces.sh @@ -141,32 +141,30 @@ else fi PASS1_MESG="before any redefines" -cnt=`grep "$PASS1_MESG" output.log | grep 'version-0' | wc -l | sed 's/^ *//'` -case "$cnt" in -2) +cnt=`grep "$PASS1_MESG" output.log | grep 'version-0' | wc -l` +# no quotes around $cnt so any whitespace from 'wc -l' is ignored +if [ $cnt = 2 ]; then echo "INFO: found 2 version-0 '$PASS1_MESG' mesgs." - ;; -*) +else echo "FAIL: did NOT find 2 version-0 '$PASS1_MESG' mesgs." + echo "INFO: cnt='$cnt'" echo "INFO: grep '$PASS1_MESG' output:" grep "$PASS1_MESG" output.log result=1 - ;; -esac +fi PASS2_MESG="after redefine" -cnt=`grep "$PASS2_MESG" output.log | grep 'version-1' | wc -l | sed 's/^ *//'` -case "$cnt" in -2) +cnt=`grep "$PASS2_MESG" output.log | grep 'version-1' | wc -l` +# no quotes around $cnt so any whitespace from 'wc -l' is ignored +if [ $cnt = 2 ]; then echo "INFO: found 2 version-1 '$PASS2_MESG' mesgs." - ;; -*) +else echo "FAIL: did NOT find 2 version-1 '$PASS2_MESG' mesgs." + echo "INFO: cnt='$cnt'" echo "INFO: grep '$PASS2_MESG' output:" grep "$PASS2_MESG" output.log result=1 - ;; -esac +fi if [ "$result" = 0 ]; then echo "PASS: test passed both positive and negative output checks." From debd718fc141e223cbd829041cdd463cba225b7b Mon Sep 17 00:00:00 2001 From: Mike Duigou Date: Wed, 20 Feb 2013 17:56:16 -0800 Subject: [PATCH 083/180] 8008629: webrev.ksh needs to quote bug title it gets back from scraping bugs.sun.com Reviewed-by: darcy --- make/scripts/webrev.ksh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/scripts/webrev.ksh b/make/scripts/webrev.ksh index 527b5d45003..cfb14f37ca3 100644 --- a/make/scripts/webrev.ksh +++ b/make/scripts/webrev.ksh @@ -3023,7 +3023,7 @@ if [[ -n $CRID ]]; then cleanup='s|\[#\(JDK-[0-9]\{5,\}\)\] \(.*\)|\1 : \2|' fi if [[ -n $WGET ]]; then - msg=`$WGET --timeout=10 --tries=1 -q $url -O - | grep '' | sed 's/<title>\(.*\)<\/title>/\1/' | sed "$cleanup"` + msg=`$WGET --timeout=10 --tries=1 -q $url -O - | grep '<title>' | sed 's/<title>\(.*\)<\/title>/\1/' | sed "$cleanup" | html_quote` fi if [[ -z $msg ]]; then msg="${id}" From 56baa11720fa000e773edb8873a8e2b2bb9c6842 Mon Sep 17 00:00:00 2001 From: Robert Field <rfield@openjdk.org> Date: Thu, 21 Feb 2013 15:46:37 -0800 Subject: [PATCH 084/180] 8008356: Test LambdaSerialization.java failing Run in /othervm mode Reviewed-by: ksrini --- jdk/test/java/lang/invoke/lambda/LambdaSerialization.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/test/java/lang/invoke/lambda/LambdaSerialization.java b/jdk/test/java/lang/invoke/lambda/LambdaSerialization.java index 1e7ba6dbe5b..ebe846b173e 100644 --- a/jdk/test/java/lang/invoke/lambda/LambdaSerialization.java +++ b/jdk/test/java/lang/invoke/lambda/LambdaSerialization.java @@ -25,7 +25,7 @@ @test @bug 8004970 @summary Lambda serialization - +@run main/othervm LambdaSerialization */ import java.io.*; From ec9e303630158405d0faaabb74f466f0a376c1fc Mon Sep 17 00:00:00 2001 From: Mark Sheppard <msheppar@openjdk.org> Date: Thu, 21 Feb 2013 20:01:22 +0000 Subject: [PATCH 085/180] 8006182: cleanup to use java.util.Base64 in java security component, providers, and regression tests Refactored code to use java.util.Base64 Mime Encoder and Decoder as a replacement for sun.misc.BASE64Encoder and sun.misc.BASE64Decoder Reviewed-by: vinnie, chegar, sherman --- .../classes/sun/security/pkcs10/PKCS10.java | 5 +-- .../sun/security/provider/X509Factory.java | 7 ++-- .../sun/security/tools/jarsigner/Main.java | 41 +++++-------------- .../sun/security/tools/keytool/Main.java | 22 +++++----- .../security/util/ManifestEntryVerifier.java | 6 +-- .../security/util/SignatureFileVerifier.java | 22 ++++------ .../sun/security/x509/X509CertImpl.java | 5 +-- .../share/classes/sun/tools/jar/Manifest.java | 6 +-- .../classes/sun/tools/jar/SignatureFile.java | 7 ++-- .../auth/kerberos/KerberosTixDateTest.java | 4 +- .../krb5/auto/HttpNegotiateServer.java | 8 ++-- .../ssl/SSLContextImpl/MD2InTrustAnchor.java | 5 +-- .../ssl/SSLContextImpl/TrustTrustedCert.java | 4 +- .../BasicConstraints.java | 6 +-- .../X509TrustManagerImpl/SelfIssuedCert.java | 4 +- .../https/HttpsClient/ProxyTunnelServer.java | 9 ++-- .../ssl/ServerName/SSLSocketSNISensitive.java | 4 +- .../net/ssl/TLSv12/DisabledShortRSAKeys.java | 4 +- .../javax/net/ssl/TLSv12/ShortRSAKey512.java | 4 +- .../HttpsURLConnection/ProxyTunnelServer.java | 8 ++-- 20 files changed, 75 insertions(+), 106 deletions(-) diff --git a/jdk/src/share/classes/sun/security/pkcs10/PKCS10.java b/jdk/src/share/classes/sun/security/pkcs10/PKCS10.java index c5418c67d07..3caf6ca1941 100644 --- a/jdk/src/share/classes/sun/security/pkcs10/PKCS10.java +++ b/jdk/src/share/classes/sun/security/pkcs10/PKCS10.java @@ -37,7 +37,7 @@ import java.security.Signature; import java.security.SignatureException; import java.security.PublicKey; -import sun.misc.BASE64Encoder; +import java.util.Base64; import sun.security.util.*; import sun.security.x509.AlgorithmId; @@ -289,10 +289,9 @@ public class PKCS10 { if (encoded == null) throw new SignatureException("Cert request was not signed"); - BASE64Encoder encoder = new BASE64Encoder(); out.println("-----BEGIN NEW CERTIFICATE REQUEST-----"); - encoder.encodeBuffer(encoded, out); + out.println(Base64.getMimeEncoder().encodeToString(encoded)); out.println("-----END NEW CERTIFICATE REQUEST-----"); } diff --git a/jdk/src/share/classes/sun/security/provider/X509Factory.java b/jdk/src/share/classes/sun/security/provider/X509Factory.java index 28b7aa55666..3a491a1c080 100644 --- a/jdk/src/share/classes/sun/security/provider/X509Factory.java +++ b/jdk/src/share/classes/sun/security/provider/X509Factory.java @@ -35,7 +35,7 @@ import sun.security.provider.certpath.X509CertPath; import sun.security.provider.certpath.X509CertificatePair; import sun.security.util.DerValue; import sun.security.util.Cache; -import sun.misc.BASE64Decoder; +import java.util.Base64; import sun.security.pkcs.ParsingException; /** @@ -512,7 +512,7 @@ public class X509Factory extends CertificateFactorySpi { hyphen = 0; last = next; } - if (hyphen == 5 && (last==-1 || last=='\r' || last=='\n')) { + if (hyphen == 5 && (last == -1 || last == '\r' || last == '\n')) { break; } } @@ -575,8 +575,7 @@ public class X509Factory extends CertificateFactorySpi { checkHeaderFooter(header.toString(), footer.toString()); - BASE64Decoder decoder = new BASE64Decoder(); - return decoder.decodeBuffer(new String(data, 0, pos)); + return Base64.getMimeDecoder().decode(new String(data, 0, pos)); } } diff --git a/jdk/src/share/classes/sun/security/tools/jarsigner/Main.java b/jdk/src/share/classes/sun/security/tools/jarsigner/Main.java index 159de08695a..9828a1a9a1d 100644 --- a/jdk/src/share/classes/sun/security/tools/jarsigner/Main.java +++ b/jdk/src/share/classes/sun/security/tools/jarsigner/Main.java @@ -57,7 +57,7 @@ import sun.security.tools.KeyStoreUtil; import sun.security.tools.PathList; import sun.security.x509.*; import sun.security.util.*; -import sun.misc.BASE64Encoder; +import java.util.Base64; /** @@ -1120,7 +1120,6 @@ public class Main { * different, replace the hash in the manifest with the newly * generated one. (This may invalidate existing signatures!) */ - BASE64Encoder encoder = new JarBASE64Encoder(); Vector<ZipEntry> mfFiles = new Vector<>(); boolean wasSigned = false; @@ -1148,15 +1147,14 @@ public class Main { if (manifest.getAttributes(ze.getName()) != null) { // jar entry is contained in manifest, check and // possibly update its digest attributes - if (updateDigests(ze, zipFile, digests, encoder, + if (updateDigests(ze, zipFile, digests, manifest) == true) { mfModified = true; } } else if (!ze.isDirectory()) { // Add entry to manifest Attributes attrs = getDigestAttributes(ze, zipFile, - digests, - encoder); + digests); mfEntries.put(ze.getName(), attrs); mfModified = true; } @@ -1955,8 +1953,7 @@ public class Main { * of base64-encoded strings. */ private synchronized String[] getDigests(ZipEntry ze, ZipFile zf, - MessageDigest[] digests, - BASE64Encoder encoder) + MessageDigest[] digests) throws IOException { int n, i; @@ -1980,7 +1977,7 @@ public class Main { // complete the digests String[] base64Digests = new String[digests.length]; for (i=0; i<digests.length; i++) { - base64Digests[i] = encoder.encode(digests[i].digest()); + base64Digests[i] = Base64.getEncoder().encodeToString(digests[i].digest()); } return base64Digests; } @@ -1990,11 +1987,10 @@ public class Main { * attributes */ private Attributes getDigestAttributes(ZipEntry ze, ZipFile zf, - MessageDigest[] digests, - BASE64Encoder encoder) + MessageDigest[] digests) throws IOException { - String[] base64Digests = getDigests(ze, zf, digests, encoder); + String[] base64Digests = getDigests(ze, zf, digests); Attributes attrs = new Attributes(); for (int i=0; i<digests.length; i++) { @@ -2016,12 +2012,11 @@ public class Main { */ private boolean updateDigests(ZipEntry ze, ZipFile zf, MessageDigest[] digests, - BASE64Encoder encoder, Manifest mf) throws IOException { boolean update = false; Attributes attrs = mf.getAttributes(ze.getName()); - String[] base64Digests = getDigests(ze, zf, digests, encoder); + String[] base64Digests = getDigests(ze, zf, digests); for (int i=0; i<digests.length; i++) { // The entry name to be written into attrs @@ -2094,19 +2089,6 @@ public class Main { } } -/** - * This is a BASE64Encoder that does not insert a default newline at the end of - * every output line. This is necessary because java.util.jar does its own - * line management (see Manifest.make72Safe()). Inserting additional new lines - * can cause line-wrapping problems (see CR 6219522). - */ -class JarBASE64Encoder extends BASE64Encoder { - /** - * Encode the suffix that ends every output line. - */ - protected void encodeLineSuffix(OutputStream aStream) throws IOException { } -} - class SignatureFile { /** SignatureFile */ @@ -2129,7 +2111,6 @@ class SignatureFile { sf = new Manifest(); Attributes mattr = sf.getMainAttributes(); - BASE64Encoder encoder = new JarBASE64Encoder(); mattr.putValue(Attributes.Name.SIGNATURE_VERSION.toString(), "1.0"); mattr.putValue("Created-By", version + " (" + javaVendor + ")"); @@ -2138,7 +2119,7 @@ class SignatureFile { // sign the whole manifest for (int i=0; i < digests.length; i++) { mattr.putValue(digests[i].getAlgorithm()+"-Digest-Manifest", - encoder.encode(md.manifestDigest(digests[i]))); + Base64.getEncoder().encodeToString(md.manifestDigest(digests[i]))); } } @@ -2149,7 +2130,7 @@ class SignatureFile { for (int i=0; i < digests.length; i++) { mattr.putValue(digests[i].getAlgorithm() + "-Digest-" + ManifestDigester.MF_MAIN_ATTRS, - encoder.encode(mde.digest(digests[i]))); + Base64.getEncoder().encodeToString(mde.digest(digests[i]))); } } else { throw new IllegalStateException @@ -2170,7 +2151,7 @@ class SignatureFile { Attributes attr = new Attributes(); for (int i=0; i < digests.length; i++) { attr.putValue(digests[i].getAlgorithm()+"-Digest", - encoder.encode(mde.digest(digests[i]))); + Base64.getEncoder().encodeToString(mde.digest(digests[i]))); } entries.put(name, attr); } diff --git a/jdk/src/share/classes/sun/security/tools/keytool/Main.java b/jdk/src/share/classes/sun/security/tools/keytool/Main.java index d0a6d6b53c4..a33e00a0c46 100644 --- a/jdk/src/share/classes/sun/security/tools/keytool/Main.java +++ b/jdk/src/share/classes/sun/security/tools/keytool/Main.java @@ -63,7 +63,7 @@ import java.security.cert.X509CRL; import java.security.cert.X509CRLEntry; import java.security.cert.X509CRLSelector; import javax.security.auth.x500.X500Principal; -import sun.misc.BASE64Encoder; +import java.util.Base64; import sun.security.util.ObjectIdentifier; import sun.security.pkcs10.PKCS10; import sun.security.pkcs10.PKCS10Attribute; @@ -73,7 +73,6 @@ import sun.security.util.Password; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; -import sun.misc.BASE64Decoder; import sun.security.pkcs.PKCS9Attribute; import sun.security.tools.KeyStoreUtil; import sun.security.tools.PathList; @@ -555,11 +554,11 @@ public final class Main { return cmd != PRINTCERT && cmd != PRINTCERTREQ; } + /** * Execute the commands. */ void doCommands(PrintStream out) throws Exception { - if (storetype == null) { storetype = KeyStore.getDefaultType(); } @@ -1189,7 +1188,7 @@ public final class Main { sb.append(s); } } - byte[] rawReq = new BASE64Decoder().decodeBuffer(new String(sb)); + byte[] rawReq = Base64.getMimeDecoder().decode(new String(sb)); PKCS10 req = new PKCS10(rawReq); info.set(X509CertInfo.KEY, new CertificateX509Key(req.getSubjectPublicKeyInfo())); @@ -1266,7 +1265,7 @@ public final class Main { crl.sign(privateKey, sigAlgName); if (rfc) { out.println("-----BEGIN X509 CRL-----"); - new BASE64Encoder().encodeBuffer(crl.getEncodedInternal(), out); + out.println(Base64.getMimeEncoder().encodeToString(crl.getEncodedInternal())); out.println("-----END X509 CRL-----"); } else { out.write(crl.getEncodedInternal()); @@ -2148,7 +2147,7 @@ public final class Main { if (rfc) { X509CRL xcrl = (X509CRL)crl; out.println("-----BEGIN X509 CRL-----"); - new BASE64Encoder().encodeBuffer(xcrl.getEncoded(), out); + out.println(Base64.getMimeEncoder().encodeToString(xcrl.getEncoded())); out.println("-----END X509 CRL-----"); } else { out.println(crl.toString()); @@ -2175,7 +2174,7 @@ public final class Main { sb.append(s); } } - PKCS10 req = new PKCS10(new BASE64Decoder().decodeBuffer(new String(sb))); + PKCS10 req = new PKCS10(Base64.getMimeDecoder().decode(new String(sb))); PublicKey pkey = req.getSubjectPublicKeyInfo(); out.printf(rb.getString("PKCS.10.Certificate.Request.Version.1.0.Subject.s.Public.Key.s.format.s.key."), @@ -2227,8 +2226,10 @@ public final class Main { Object[] source = {new Integer(i + 1)}; out.println(form.format(source)); } - if (rfc) dumpCert(x509Cert, out); - else printX509Cert(x509Cert, out); + if (rfc) + dumpCert(x509Cert, out); + else + printX509Cert(x509Cert, out); if (i < (certs.length-1)) { out.println(); } @@ -2946,9 +2947,8 @@ public final class Main { throws IOException, CertificateException { if (rfc) { - BASE64Encoder encoder = new BASE64Encoder(); out.println(X509Factory.BEGIN_CERT); - encoder.encodeBuffer(cert.getEncoded(), out); + out.println(Base64.getMimeEncoder().encodeToString(cert.getEncoded())); out.println(X509Factory.END_CERT); } else { out.write(cert.getEncoded()); // binary diff --git a/jdk/src/share/classes/sun/security/util/ManifestEntryVerifier.java b/jdk/src/share/classes/sun/security/util/ManifestEntryVerifier.java index 3d1b4733c30..548133cfa40 100644 --- a/jdk/src/share/classes/sun/security/util/ManifestEntryVerifier.java +++ b/jdk/src/share/classes/sun/security/util/ManifestEntryVerifier.java @@ -31,7 +31,7 @@ import java.security.CodeSigner; import java.util.*; import java.util.jar.*; -import sun.misc.BASE64Decoder; +import java.util.Base64; import sun.security.jca.Providers; @@ -63,7 +63,6 @@ public class ManifestEntryVerifier { /** the manifest hashes for the digests in use */ ArrayList<byte[]> manifestHashes; - private BASE64Decoder decoder = null; private String name = null; private Manifest man; @@ -81,7 +80,6 @@ public class ManifestEntryVerifier { createdDigests = new HashMap<String, MessageDigest>(11); digests = new ArrayList<MessageDigest>(); manifestHashes = new ArrayList<byte[]>(); - decoder = new BASE64Decoder(); this.man = man; } @@ -147,7 +145,7 @@ public class ManifestEntryVerifier { digest.reset(); digests.add(digest); manifestHashes.add( - decoder.decodeBuffer((String)se.getValue())); + Base64.getMimeDecoder().decode((String)se.getValue())); } } } diff --git a/jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java b/jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java index 715a5da356b..e84cc2c37a8 100644 --- a/jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java +++ b/jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java @@ -35,7 +35,7 @@ import java.util.*; import java.util.jar.*; import sun.security.pkcs.*; -import sun.misc.BASE64Decoder; +import java.util.Base64; import sun.security.jca.Providers; @@ -220,7 +220,6 @@ public class SignatureFileVerifier { name); } - BASE64Decoder decoder = new BASE64Decoder(); CodeSigner[] newSigners = getSigners(infos, block); @@ -232,10 +231,10 @@ public class SignatureFileVerifier { sf.getEntries().entrySet().iterator(); // see if we can verify the whole manifest first - boolean manifestSigned = verifyManifestHash(sf, md, decoder, manifestDigests); + boolean manifestSigned = verifyManifestHash(sf, md, manifestDigests); // verify manifest main attributes - if (!manifestSigned && !verifyManifestMainAttrs(sf, md, decoder)) { + if (!manifestSigned && !verifyManifestMainAttrs(sf, md)) { throw new SecurityException ("Invalid signature file digest for Manifest main attributes"); } @@ -247,7 +246,7 @@ public class SignatureFileVerifier { String name = e.getKey(); if (manifestSigned || - (verifySection(e.getValue(), name, md, decoder))) { + (verifySection(e.getValue(), name, md))) { if (name.startsWith("./")) name = name.substring(2); @@ -275,7 +274,6 @@ public class SignatureFileVerifier { */ private boolean verifyManifestHash(Manifest sf, ManifestDigester md, - BASE64Decoder decoder, List<Object> manifestDigests) throws IOException { @@ -297,7 +295,7 @@ public class SignatureFileVerifier { if (digest != null) { byte[] computedHash = md.manifestDigest(digest); byte[] expectedHash = - decoder.decodeBuffer((String)se.getValue()); + Base64.getMimeDecoder().decode((String)se.getValue()); if (debug != null) { debug.println("Signature File: Manifest digest " + @@ -320,8 +318,7 @@ public class SignatureFileVerifier { } private boolean verifyManifestMainAttrs(Manifest sf, - ManifestDigester md, - BASE64Decoder decoder) + ManifestDigester md) throws IOException { Attributes mattr = sf.getMainAttributes(); @@ -342,7 +339,7 @@ public class SignatureFileVerifier { md.get(ManifestDigester.MF_MAIN_ATTRS, false); byte[] computedHash = mde.digest(digest); byte[] expectedHash = - decoder.decodeBuffer((String)se.getValue()); + Base64.getMimeDecoder().decode((String)se.getValue()); if (debug != null) { debug.println("Signature File: " + @@ -387,8 +384,7 @@ public class SignatureFileVerifier { private boolean verifySection(Attributes sfAttr, String name, - ManifestDigester md, - BASE64Decoder decoder) + ManifestDigester md) throws IOException { boolean oneDigestVerified = false; @@ -418,7 +414,7 @@ public class SignatureFileVerifier { boolean ok = false; byte[] expected = - decoder.decodeBuffer((String)se.getValue()); + Base64.getMimeDecoder().decode((String)se.getValue()); byte[] computed; if (workaround) { computed = mde.digestWorkaround(digest); diff --git a/jdk/src/share/classes/sun/security/x509/X509CertImpl.java b/jdk/src/share/classes/sun/security/x509/X509CertImpl.java index 64e06ceaebf..1593e5ed4ab 100644 --- a/jdk/src/share/classes/sun/security/x509/X509CertImpl.java +++ b/jdk/src/share/classes/sun/security/x509/X509CertImpl.java @@ -41,7 +41,7 @@ import java.util.*; import javax.security.auth.x500.X500Principal; import sun.misc.HexDumpEncoder; -import sun.misc.BASE64Decoder; +import java.util.Base64; import sun.security.util.*; import sun.security.provider.X509Factory; @@ -263,7 +263,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { } if (line.equals(X509Factory.BEGIN_CERT)) { /* stream appears to be hex-encoded bytes */ - BASE64Decoder decoder = new BASE64Decoder(); ByteArrayOutputStream decstream = new ByteArrayOutputStream(); try { while ((line = certBufferedReader.readLine()) != null) { @@ -271,7 +270,7 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { der = new DerValue(decstream.toByteArray()); break; } else { - decstream.write(decoder.decodeBuffer(line)); + decstream.write(Base64.getMimeDecoder().decode(line)); } } } catch (IOException ioe2) { diff --git a/jdk/src/share/classes/sun/tools/jar/Manifest.java b/jdk/src/share/classes/sun/tools/jar/Manifest.java index 7a8cf74a906..b1e23ce8e81 100644 --- a/jdk/src/share/classes/sun/tools/jar/Manifest.java +++ b/jdk/src/share/classes/sun/tools/jar/Manifest.java @@ -30,8 +30,7 @@ import java.util.*; import java.security.*; import sun.net.www.MessageHeader; -import sun.misc.BASE64Encoder; -import sun.misc.BASE64Decoder; +import java.util.Base64; /** * This is OBSOLETE. DO NOT USE THIS. Use java.util.jar.Manifest @@ -178,7 +177,6 @@ public class Manifest { return; } - BASE64Encoder enc = new BASE64Encoder(); /* compute hashes, write over any other "Hash-Algorithms" (?) */ for (int j = 0; j < hashes.length; ++j) { @@ -190,7 +188,7 @@ public class Manifest { while ((len = is.read(tmpbuf, 0, tmpbuf.length)) != -1) { dig.update(tmpbuf, 0, len); } - mh.set(hashes[j] + "-Digest", enc.encode(dig.digest())); + mh.set(hashes[j] + "-Digest", Base64.getMimeEncoder().encodeToString(dig.digest())); } catch (NoSuchAlgorithmException e) { throw new JarException("Digest algorithm " + hashes[j] + " not available."); diff --git a/jdk/src/share/classes/sun/tools/jar/SignatureFile.java b/jdk/src/share/classes/sun/tools/jar/SignatureFile.java index 8e7d3f59435..007b67962e5 100644 --- a/jdk/src/share/classes/sun/tools/jar/SignatureFile.java +++ b/jdk/src/share/classes/sun/tools/jar/SignatureFile.java @@ -30,8 +30,8 @@ import java.util.*; import java.security.*; import sun.net.www.MessageHeader; -import sun.misc.BASE64Encoder; -import sun.misc.BASE64Decoder; +import java.util.Base64; + import sun.security.pkcs.*; import sun.security.x509.AlgorithmId; @@ -305,7 +305,6 @@ public class SignatureFile { } smh.set("Name", name); - BASE64Encoder encoder = new BASE64Encoder(); try { for (int i = 0; i < hashes.length; ++i) { MessageDigest dig = getDigest(hashes[i]); @@ -314,7 +313,7 @@ public class SignatureFile { mh.print(ps); byte[] headerBytes = baos.toByteArray(); byte[] digest = dig.digest(headerBytes); - smh.set(hashes[i] + "-Digest", encoder.encode(digest)); + smh.set(hashes[i] + "-Digest", Base64.getMimeEncoder().encodeToString(digest)); } return smh; } catch (NoSuchAlgorithmException e) { diff --git a/jdk/test/javax/security/auth/kerberos/KerberosTixDateTest.java b/jdk/test/javax/security/auth/kerberos/KerberosTixDateTest.java index c2f9e619ac4..00ee727401c 100644 --- a/jdk/test/javax/security/auth/kerberos/KerberosTixDateTest.java +++ b/jdk/test/javax/security/auth/kerberos/KerberosTixDateTest.java @@ -34,7 +34,7 @@ import java.io.*; import javax.security.auth.kerberos.KerberosKey; import javax.security.auth.kerberos.KerberosPrincipal; import javax.security.auth.kerberos.KerberosTicket; -import sun.misc.BASE64Decoder; +import java.util.Base64; public class KerberosTixDateTest { @@ -127,7 +127,7 @@ public class KerberosTixDateTest { System.out.println("Testing against KerberosTicket from JDK6..."); byte[] serializedBytes = - new BASE64Decoder().decodeBuffer(serializedKerberosTix); + Base64.getMimeDecoder().decode(serializedKerberosTix); checkEqualsAndHashCode(serializedBytes, t); System.out.println("Testing against KerberosTicket from current rel..."); diff --git a/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java b/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java index 19f3355ce09..82333d7783b 100644 --- a/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java +++ b/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java @@ -55,6 +55,7 @@ import org.ietf.jgss.GSSCredential; import org.ietf.jgss.GSSManager; import sun.security.jgss.GSSUtil; import sun.security.krb5.Config; +import java.util.Base64; /** * Basic JGSS/krb5 test with 3 parties: client, server, backend server. Each @@ -341,12 +342,11 @@ public class HttpNegotiateServer { exch.getHttpContext().getAttributes().put("GSSContext", c); return new com.sun.net.httpserver.Authenticator.Retry(err); } else { // Later requests - byte[] token = new sun.misc.BASE64Decoder() - .decodeBuffer(auth.split(" ")[1]); + byte[] token = Base64.getMimeDecoder().decode(auth.split(" ")[1]); token = c.acceptSecContext(token, 0, token.length); Headers map = exch.getResponseHeaders(); - map.set (reqHdr, scheme + " " + new sun.misc.BASE64Encoder() - .encode(token).replaceAll("\\s", "")); + map.set (reqHdr, scheme + " " + Base64.getMimeEncoder() + .encodeToString(token).replaceAll("\\s", "")); if (c.isEstablished()) { return new com.sun.net.httpserver.Authenticator.Success( new HttpPrincipal(c.getSrcName().toString(), "")); diff --git a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/MD2InTrustAnchor.java b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/MD2InTrustAnchor.java index 0a25f7f21ce..9cf0fbb7185 100644 --- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/MD2InTrustAnchor.java +++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/MD2InTrustAnchor.java @@ -46,8 +46,7 @@ import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.spec.*; import java.security.interfaces.*; -import sun.misc.BASE64Decoder; - +import java.util.Base64; public class MD2InTrustAnchor { @@ -238,7 +237,7 @@ public class MD2InTrustAnchor { if (keyCertStr != null) { // generate the private key. PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - new BASE64Decoder().decodeBuffer(keySpecStr)); + Base64.getMimeDecoder().decode(keySpecStr)); KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKey priKey = (RSAPrivateKey)kf.generatePrivate(priKeySpec); diff --git a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/TrustTrustedCert.java b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/TrustTrustedCert.java index 3aeeb081b34..ff8887c212a 100644 --- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/TrustTrustedCert.java +++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/TrustTrustedCert.java @@ -44,7 +44,7 @@ import java.security.*; import java.security.cert.*; import java.security.spec.*; import java.security.interfaces.*; -import sun.misc.BASE64Decoder; +import java.util.Base64; public class TrustTrustedCert { @@ -230,7 +230,7 @@ public class TrustTrustedCert { // generate the private key. PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - new BASE64Decoder().decodeBuffer(targetPrivateKey)); + Base64.getMimeDecoder().decode(targetPrivateKey)); KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKey priKey = (RSAPrivateKey)kf.generatePrivate(priKeySpec); diff --git a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/BasicConstraints.java b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/BasicConstraints.java index 1756ba0cacd..8f1e71622c4 100644 --- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/BasicConstraints.java +++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/BasicConstraints.java @@ -44,7 +44,7 @@ import java.security.spec.*; import java.security.interfaces.*; import java.math.BigInteger; -import sun.misc.BASE64Decoder; +import java.util.Base64; public class BasicConstraints { @@ -400,11 +400,11 @@ public class BasicConstraints { PKCS8EncodedKeySpec priKeySpec = null; if (isServer) { priKeySpec = new PKCS8EncodedKeySpec( - new BASE64Decoder().decodeBuffer(serverPrivateKey)); + Base64.getMimeDecoder().decode(serverPrivateKey)); is = new ByteArrayInputStream(serverCertStr.getBytes()); } else { priKeySpec = new PKCS8EncodedKeySpec( - new BASE64Decoder().decodeBuffer(clientPrivateKey)); + Base64.getMimeDecoder().decode(clientPrivateKey)); is = new ByteArrayInputStream(clientCertStr.getBytes()); } KeyFactory kf = KeyFactory.getInstance("RSA"); diff --git a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/SelfIssuedCert.java b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/SelfIssuedCert.java index 0037b6f379f..1f8f7298383 100644 --- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/SelfIssuedCert.java +++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/SelfIssuedCert.java @@ -45,7 +45,7 @@ import java.security.spec.*; import java.security.interfaces.*; import java.math.BigInteger; -import sun.misc.BASE64Decoder; +import java.util.Base64; public class SelfIssuedCert { @@ -242,7 +242,7 @@ public class SelfIssuedCert { if (keyCertStr != null) { // generate the private key. PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - new BASE64Decoder().decodeBuffer(keySpecStr)); + Base64.getMimeDecoder().decode(keySpecStr)); KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKey priKey = (RSAPrivateKey)kf.generatePrivate(priKeySpec); diff --git a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/www/protocol/https/HttpsClient/ProxyTunnelServer.java b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/www/protocol/https/HttpsClient/ProxyTunnelServer.java index 9d77078f12e..e5fa754391e 100644 --- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/www/protocol/https/HttpsClient/ProxyTunnelServer.java +++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/www/protocol/https/HttpsClient/ProxyTunnelServer.java @@ -33,6 +33,7 @@ import java.net.*; import javax.net.ssl.*; import javax.net.ServerSocketFactory; import sun.net.www.*; +import java.util.Base64; public class ProxyTunnelServer extends Thread { @@ -292,12 +293,12 @@ public class ProxyTunnelServer extends Thread { authInfo.trim(); int ind = authInfo.indexOf(' '); String recvdUserPlusPass = authInfo.substring(ind + 1).trim(); + // extract encoded (username:passwd if (userPlusPass.equals( - new String( - (new sun.misc.BASE64Decoder()). - decodeBuffer(recvdUserPlusPass) - ))) { + new String( Base64.getMimeDecoder() + .decode(recvdUserPlusPass)))) + { matched = true; } } catch (Exception e) { diff --git a/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/SSLSocketSNISensitive.java b/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/SSLSocketSNISensitive.java index 03a841bfd85..1b93237a544 100644 --- a/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/SSLSocketSNISensitive.java +++ b/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/SSLSocketSNISensitive.java @@ -51,7 +51,7 @@ import java.security.cert.X509Certificate; import java.security.cert.CertificateFactory; import java.security.spec.*; import java.security.interfaces.*; -import sun.misc.BASE64Decoder; +import java.util.Base64; public class SSLSocketSNISensitive { @@ -391,7 +391,7 @@ public class SSLSocketSNISensitive { // generate the private key. String keySpecStr = keyStrs[i]; PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - new BASE64Decoder().decodeBuffer(keySpecStr)); + Base64.getMimeDecoder().decode(keySpecStr)); KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKey priKey = (RSAPrivateKey)kf.generatePrivate(priKeySpec); diff --git a/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/DisabledShortRSAKeys.java b/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/DisabledShortRSAKeys.java index 4a7130964b8..f92d7f69c05 100644 --- a/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/DisabledShortRSAKeys.java +++ b/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/DisabledShortRSAKeys.java @@ -53,7 +53,7 @@ import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.spec.*; import java.security.interfaces.*; -import sun.misc.BASE64Decoder; +import java.util.Base64; public class DisabledShortRSAKeys { @@ -244,7 +244,7 @@ public class DisabledShortRSAKeys { if (keyCertStr != null) { // generate the private key. PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - new BASE64Decoder().decodeBuffer(keySpecStr)); + Base64.getMimeDecoder().decode(keySpecStr)); KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKey priKey = (RSAPrivateKey)kf.generatePrivate(priKeySpec); diff --git a/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKey512.java b/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKey512.java index c3c170205a4..8370f9d3525 100644 --- a/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKey512.java +++ b/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKey512.java @@ -48,7 +48,7 @@ import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.spec.*; import java.security.interfaces.*; -import sun.misc.BASE64Decoder; +import java.util.Base64; public class ShortRSAKey512 { @@ -229,7 +229,7 @@ public class ShortRSAKey512 { if (keyCertStr != null) { // generate the private key. PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - new BASE64Decoder().decodeBuffer(keySpecStr)); + Base64.getMimeDecoder().decode(keySpecStr)); KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKey priKey = (RSAPrivateKey)kf.generatePrivate(priKeySpec); diff --git a/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/ProxyTunnelServer.java b/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/ProxyTunnelServer.java index a70eb7fb680..f2f3430e12e 100644 --- a/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/ProxyTunnelServer.java +++ b/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/ProxyTunnelServer.java @@ -35,6 +35,7 @@ import java.net.*; import javax.net.ssl.*; import javax.net.ServerSocketFactory; import sun.net.www.*; +import java.util.Base64; public class ProxyTunnelServer extends Thread { @@ -296,10 +297,9 @@ public class ProxyTunnelServer extends Thread { String recvdUserPlusPass = authInfo.substring(ind + 1).trim(); // extract encoded (username:passwd if (userPlusPass.equals( - new String( - (new sun.misc.BASE64Decoder()). - decodeBuffer(recvdUserPlusPass) - ))) { + new String( Base64.getMimeDecoder() + .decode(recvdUserPlusPass)))) + { matched = true; } } catch (Exception e) { From 98e5a4b3938563472ee1572373bacf845936b7d4 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov <vlivanov@openjdk.org> Date: Fri, 22 Feb 2013 03:00:48 -0800 Subject: [PATCH 086/180] 8006439: Improve MethodHandles coverage Reviewed-by: jrose, twisti --- .../java/lang/invoke/MethodHandleImpl.java | 24 +------- .../java/lang/invoke/MethodHandleNatives.java | 16 ++++- .../java/lang/invoke/MethodHandles.java | 60 ++++++++++++++----- 3 files changed, 62 insertions(+), 38 deletions(-) diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java index 3cdd99cc4a1..1b35e0fc8bf 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -801,12 +801,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; static MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) { // Do not use this function to inject calls into system classes. - if (hostClass == null) { - hostClass = C_Trampoline; - } else if (hostClass.isArray() || + if (hostClass == null + || (hostClass.isArray() || hostClass.isPrimitive() || hostClass.getName().startsWith("java.") || - hostClass.getName().startsWith("sun.")) { + hostClass.getName().startsWith("sun."))) { throw new InternalError(); // does not happen, and should not anyway } // For simplicity, convert mh to a varargs-like method. @@ -816,23 +815,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; return restoreToType(bccInvoker.bindTo(vamh), mh.type()); } - // This class ("Trampoline") is known to be inside a dead-end class loader. - // Inject all doubtful calls into this class. - private static Class<?> C_Trampoline; - static { - Class<?> tramp = null; - try { - final int FRAME_COUNT_ARG = 1; // [0] Reflection [1] Trampoline - java.lang.reflect.Method gcc = sun.reflect.Reflection.class.getMethod("getCallerClass", int.class); - tramp = (Class<?>) sun.reflect.misc.MethodUtil.invoke(gcc, null, new Object[]{ FRAME_COUNT_ARG }); - if (tramp.getClassLoader() == BindCaller.class.getClassLoader()) - throw new RuntimeException(tramp.getName()+" class loader"); - } catch (Throwable ex) { - throw new InternalError(ex); - } - C_Trampoline = tramp; - } - private static MethodHandle makeInjectedInvoker(Class<?> hostClass) { Class<?> bcc = UNSAFE.defineAnonymousClass(hostClass, T_BYTES, null); if (hostClass.getClassLoader() != bcc.getClassLoader()) diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java index 8f1d0c3164e..8d40ac96726 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java @@ -393,11 +393,14 @@ class MethodHandleNatives { */ // FIXME: Replace this pattern match by an annotation @sun.reflect.CallerSensitive. static boolean isCallerSensitive(MemberName mem) { - assert(mem.isInvocable()); + if (!mem.isInvocable()) return false; // fields are not caller sensitive Class<?> defc = mem.getDeclaringClass(); switch (mem.getName()) { case "doPrivileged": + case "doPrivilegedWithCombiner": return defc == java.security.AccessController.class; + case "checkMemberAccess": + return canBeCalledVirtual(mem, java.lang.SecurityManager.class); case "getUnsafe": return defc == sun.misc.Unsafe.class; case "lookup": @@ -455,7 +458,7 @@ class MethodHandleNatives { if (defc == java.util.concurrent.atomic.AtomicReferenceFieldUpdater.class) return true; break; case "getContextClassLoader": - return defc == java.lang.Thread.class; + return canBeCalledVirtual(mem, java.lang.Thread.class); case "getPackage": case "getPackages": return defc == java.lang.Package.class; @@ -473,6 +476,8 @@ class MethodHandleNatives { break; case "getCallerClassLoader": return defc == java.lang.ClassLoader.class; + case "registerAsParallelCapable": + return canBeCalledVirtual(mem, java.lang.ClassLoader.class); case "getProxyClass": case "newProxyInstance": return defc == java.lang.reflect.Proxy.class; @@ -494,4 +499,11 @@ class MethodHandleNatives { throw new InternalError(e); } } + static boolean canBeCalledVirtual(MemberName symbolicRef, Class<?> definingClass) { + Class<?> symbolicRefClass = symbolicRef.getDeclaringClass(); + if (symbolicRefClass == definingClass) return true; + if (symbolicRef.isStatic() || symbolicRef.isPrivate()) return false; + return (definingClass.isAssignableFrom(symbolicRefClass) || // Msym overrides Mdef + symbolicRefClass.isInterface()); // Mdef implements Msym + } } diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java index e7007dd2b89..d2a499e9867 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java @@ -598,7 +598,8 @@ public class MethodHandles { MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type); checkSecurityManager(refc, method); // stack walk magic: do not refactor - return getDirectMethod(REF_invokeStatic, refc, method); + Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor + return getDirectMethod(REF_invokeStatic, refc, method, callerClass); } /** @@ -652,7 +653,8 @@ public class MethodHandles { byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual); MemberName method = resolveOrFail(refKind, refc, name, type); checkSecurityManager(refc, method); // stack walk magic: do not refactor - return getDirectMethod(refKind, refc, method); + Class<?> callerClass = findBoundCallerClass(method); + return getDirectMethod(refKind, refc, method, callerClass); } private MethodHandle findVirtualForMH(String name, MethodType type) { // these names require special lookups because of the implicit MethodType argument @@ -736,7 +738,8 @@ public class MethodHandles { Lookup specialLookup = this.in(specialCaller); MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type); checkSecurityManager(refc, method); // stack walk magic: do not refactor - return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method); + Class<?> callerClass = findBoundCallerClass(method); + return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, callerClass); } /** @@ -879,7 +882,8 @@ return mh1; Class<? extends Object> refc = receiver.getClass(); // may get NPE MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type); checkSecurityManager(refc, method); // stack walk magic: do not refactor - MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method); + Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor + MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, callerClass); return mh.bindReceiver(receiver).setVarargs(method); } @@ -910,8 +914,9 @@ return mh1; if (refKind == REF_invokeSpecial) refKind = REF_invokeVirtual; assert(method.isMethod()); + Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this; - return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method); + return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, callerClass); } /** @@ -940,8 +945,9 @@ return mh1; Lookup specialLookup = this.in(specialCaller); MemberName method = new MemberName(m, true); assert(method.isMethod()); + Class<?> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor // ignore m.isAccessible: this is a new kind of access - return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method); + return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, callerClass); } /** @@ -1039,8 +1045,30 @@ return mh1; throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this); } + /** + * Find my trustable caller class if m is a caller sensitive method. + * If this lookup object has private access, then the caller class is the lookupClass. + * Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual). + * This is the same caller class as is used by checkSecurityManager. + * This function performs stack walk magic: do not refactor it. + */ + Class<?> findBoundCallerClass(MemberName m) { + Class<?> callerClass = null; + if (MethodHandleNatives.isCallerSensitive(m)) { + // Do not refactor this to a more "logical" place, since it is stack walk magic. + // Note that this is the same expression as in Step 2 below in checkSecurityManager. + callerClass = ((allowedModes & PRIVATE) != 0 + ? lookupClass // for strong access modes, no extra check + // next line does stack walk magic; do not refactor: + : getCallerClassAtEntryPoint(true)); + } + return callerClass; + } /** * Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>. + * Determines a trustable caller class to compare with refc, the symbolic reference class. + * If this lookup object has private access, then the caller class is the lookupClass. + * Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual). * This function performs stack walk magic: do not refactor it. */ void checkSecurityManager(Class<?> refc, MemberName m) { @@ -1195,22 +1223,22 @@ return mh1; return mh.viewAsType(narrowType); } - private MethodHandle getDirectMethod(byte refKind, Class<?> refc, MemberName method) throws IllegalAccessException { + private MethodHandle getDirectMethod(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException { return getDirectMethodCommon(refKind, refc, method, (refKind == REF_invokeSpecial || (MethodHandleNatives.refKindHasReceiver(refKind) && - restrictProtectedReceiver(method)))); + restrictProtectedReceiver(method))), callerClass); } - private MethodHandle getDirectMethodNoRestrict(byte refKind, Class<?> refc, MemberName method) throws IllegalAccessException { - return getDirectMethodCommon(refKind, refc, method, false); + private MethodHandle getDirectMethodNoRestrict(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException { + return getDirectMethodCommon(refKind, refc, method, false, callerClass); } private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method, - boolean doRestrict) throws IllegalAccessException { + boolean doRestrict, Class<?> callerClass) throws IllegalAccessException { checkMethod(refKind, refc, method); if (method.isMethodHandleInvoke()) return fakeMethodHandleInvoke(method); MethodHandle mh = DirectMethodHandle.make(refc, method); - mh = maybeBindCaller(method, mh); + mh = maybeBindCaller(method, mh, callerClass); mh = mh.setVarargs(method); if (doRestrict) mh = restrictReceiver(method, mh, lookupClass()); @@ -1219,12 +1247,14 @@ return mh1; private MethodHandle fakeMethodHandleInvoke(MemberName method) { return throwException(method.getReturnType(), UnsupportedOperationException.class); } - private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh) throws IllegalAccessException { + private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh, + Class<?> callerClass) + throws IllegalAccessException { if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method)) return mh; Class<?> hostClass = lookupClass; if ((allowedModes & PRIVATE) == 0) // caller must use full-power lookup - hostClass = null; + hostClass = callerClass; // callerClass came from a security manager style stack walk MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass); // Note: caller will apply varargs after this step happens. return cbmh; @@ -1262,7 +1292,7 @@ return mh1; } else if (MethodHandleNatives.refKindIsMethod(refKind)) { MemberName method = (resolved != null) ? resolved : resolveOrFail(refKind, defc, name, (MethodType) type); - return getDirectMethod(refKind, defc, method); + return getDirectMethod(refKind, defc, method, lookupClass); } else if (refKind == REF_newInvokeSpecial) { assert(name == null || name.equals("<init>")); MemberName ctor = (resolved != null) ? resolved From f179e269b978443b6e45f86faffb5cfcd2cfa92b Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov <vlivanov@openjdk.org> Date: Fri, 22 Feb 2013 03:00:12 -0800 Subject: [PATCH 087/180] 8006179: JSR292 MethodHandles lookup with interface using findVirtual() Reviewed-by: jrose, twisti --- .../classes/java/lang/invoke/DirectMethodHandle.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java b/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java index 0df8e730937..db8d35fd400 100644 --- a/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java +++ b/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java @@ -51,6 +51,16 @@ class DirectMethodHandle extends MethodHandle { private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) { super(mtype, form); if (!member.isResolved()) throw new InternalError(); + + if (member.getDeclaringClass().isInterface() && !member.isAbstract()) { + // Check for corner case: invokeinterface of Object method + MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind()); + m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null); + if (m != null && m.isPublic()) { + member = m; + } + } + this.member = member; } From 0ae708ca99b6aebd91cf3486ddffc7fc8e742722 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov <vlivanov@openjdk.org> Date: Fri, 22 Feb 2013 02:59:24 -0800 Subject: [PATCH 088/180] 8006125: Update MethodHandles library interactions Reviewed-by: jrose --- jdk/src/share/classes/sun/reflect/misc/MethodUtil.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java b/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java index 0eade8de571..9d9c5ab6015 100644 --- a/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java +++ b/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java @@ -252,6 +252,12 @@ public final class MethodUtil extends SecureClassLoader { public static Object invoke(Method m, Object obj, Object[] params) throws InvocationTargetException, IllegalAccessException { if (m.getDeclaringClass().equals(AccessController.class) || + (m.getDeclaringClass().equals(java.lang.invoke.MethodHandles.class) + && m.getName().equals("lookup")) || + (m.getDeclaringClass().equals(java.lang.invoke.MethodHandles.Lookup.class) + && (m.getName().startsWith("find") || + m.getName().startsWith("bind") || + m.getName().startsWith("unreflect"))) || m.getDeclaringClass().equals(Method.class)) throw new InvocationTargetException( new UnsupportedOperationException("invocation not supported")); From 17992b9ac9c1509c24eb0d072c7ff79cdb294151 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov <vlivanov@openjdk.org> Date: Fri, 22 Feb 2013 02:58:38 -0800 Subject: [PATCH 089/180] 8004933: Improve MethodHandle interaction with libraries Reviewed-by: jrose --- .../java/lang/invoke/MethodHandleNatives.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java index 8d40ac96726..db072126e1f 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java @@ -405,6 +405,21 @@ class MethodHandleNatives { return defc == sun.misc.Unsafe.class; case "lookup": return defc == java.lang.invoke.MethodHandles.class; + case "findStatic": + case "findVirtual": + case "findConstructor": + case "findSpecial": + case "findGetter": + case "findSetter": + case "findStaticGetter": + case "findStaticSetter": + case "bind": + case "unreflect": + case "unreflectSpecial": + case "unreflectConstructor": + case "unreflectGetter": + case "unreflectSetter": + return defc == java.lang.invoke.MethodHandles.Lookup.class; case "invoke": return defc == java.lang.reflect.Method.class; case "get": From a8305fc6e6f713c2c2762d8dbed869bd158d9aa9 Mon Sep 17 00:00:00 2001 From: Anton Tarasov <ant@openjdk.org> Date: Fri, 22 Feb 2013 15:13:13 +0400 Subject: [PATCH 090/180] 8006406: lightweight embedding in other Java UI toolkits Reviewed-by: serb, anthony, art --- .../classes/sun/lwawt/LWComponentPeer.java | 2 +- .../sun/lwawt/LWLightweightFramePeer.java | 115 ++++++++ .../macosx/classes/sun/lwawt/LWToolkit.java | 19 ++ .../classes/sun/lwawt/LWWindowPeer.java | 12 +- .../sun/lwawt/macosx/CPlatformComponent.java | 2 +- .../lwawt/macosx/CPlatformLWComponent.java | 53 ++++ .../sun/lwawt/macosx/CPlatformLWView.java | 82 ++++++ .../sun/lwawt/macosx/CPlatformLWWindow.java | 202 ++++++++++++++ .../sun/lwawt/macosx/CPlatformView.java | 8 +- .../sun/lwawt/macosx/CPlatformWindow.java | 18 +- .../classes/sun/lwawt/macosx/LWCToolkit.java | 7 + .../classes/java/awt/peer/FramePeer.java | 6 + .../classes/java/awt/peer/WindowPeer.java | 2 - .../share/classes/sun/awt/EmbeddedFrame.java | 5 +- jdk/src/share/classes/sun/awt/HToolkit.java | 5 + .../classes/sun/awt/LightweightFrame.java | 127 +++++++++ jdk/src/share/classes/sun/awt/SunToolkit.java | 3 + .../classes/sun/swing/JLightweightFrame.java | 250 ++++++++++++++++++ .../classes/sun/swing/LightweightContent.java | 164 ++++++++++++ .../classes/sun/awt/X11/XFramePeer.java | 2 + .../solaris/classes/sun/awt/X11/XToolkit.java | 4 + .../sun/awt/windows/WEmbeddedFrame.java | 8 +- .../sun/awt/windows/WEmbeddedFramePeer.java | 2 - .../classes/sun/awt/windows/WFramePeer.java | 7 + .../awt/windows/WLightweightFramePeer.java | 86 ++++++ .../classes/sun/awt/windows/WToolkit.java | 7 + .../windows/native/sun/windows/awt_Frame.cpp | 55 +++- .../windows/native/sun/windows/awt_Frame.h | 5 + .../windows/native/sun/windows/awt_Window.h | 5 +- 29 files changed, 1229 insertions(+), 34 deletions(-) create mode 100644 jdk/src/macosx/classes/sun/lwawt/LWLightweightFramePeer.java create mode 100644 jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformLWComponent.java create mode 100644 jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformLWView.java create mode 100644 jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java create mode 100644 jdk/src/share/classes/sun/awt/LightweightFrame.java create mode 100644 jdk/src/share/classes/sun/swing/JLightweightFrame.java create mode 100644 jdk/src/share/classes/sun/swing/LightweightContent.java create mode 100644 jdk/src/windows/classes/sun/awt/windows/WLightweightFramePeer.java diff --git a/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java b/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java index aa9b798c617..301fbb476d8 100644 --- a/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java +++ b/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java @@ -439,7 +439,7 @@ public abstract class LWComponentPeer<T extends Component, D extends JComponent> } @Override - public final Graphics getGraphics() { + public Graphics getGraphics() { final Graphics g = getOnscreenGraphics(); if (g != null) { synchronized (getPeerTreeLock()){ diff --git a/jdk/src/macosx/classes/sun/lwawt/LWLightweightFramePeer.java b/jdk/src/macosx/classes/sun/lwawt/LWLightweightFramePeer.java new file mode 100644 index 00000000000..90e2e88c441 --- /dev/null +++ b/jdk/src/macosx/classes/sun/lwawt/LWLightweightFramePeer.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.lwawt; + +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Window; +import java.awt.dnd.DropTarget; + +import sun.awt.CausedFocusEvent; +import sun.awt.LightweightFrame; + +public class LWLightweightFramePeer extends LWWindowPeer { + + public LWLightweightFramePeer(LightweightFrame target, + PlatformComponent platformComponent, + PlatformWindow platformWindow) + { + super(target, platformComponent, platformWindow, LWWindowPeer.PeerType.LW_FRAME); + } + + private LightweightFrame getLwTarget() { + return (LightweightFrame)getTarget(); + } + + @Override + public Graphics getGraphics() { + return getLwTarget().getGraphics(); + } + + @Override + protected void setVisibleImpl(final boolean visible) { + } + + @Override + public boolean requestWindowFocus(CausedFocusEvent.Cause cause) { + if (!focusAllowedFor()) { + return false; + } + if (getPlatformWindow().rejectFocusRequest(cause)) { + return false; + } + + Window opposite = LWKeyboardFocusManagerPeer.getInstance(). + getCurrentFocusedWindow(); + + changeFocusedWindow(true, opposite); + + return true; + } + + @Override + public Point getLocationOnScreen() { + Rectangle bounds = getBounds(); + return new Point(bounds.x, bounds.y); // todo + } + + @Override + public Insets getInsets() { + return new Insets(0, 0, 0, 0); + } + + @Override + public void setBounds(int x, int y, int w, int h, int op) { + setBounds(x, y, w, h, op, true, false); + } + + @Override + public void updateCursorImmediately() { + // TODO: tries to switch to the awt/fx toolkit thread and causes a deadlock on macosx + } + + @Override + public void addDropTarget(DropTarget dt) { + } + + @Override + public void removeDropTarget(DropTarget dt) { + } + + @Override + public void grab() { + getLwTarget().grabFocus(); + } + + @Override + public void ungrab() { + getLwTarget().ungrabFocus(); + } +} diff --git a/jdk/src/macosx/classes/sun/lwawt/LWToolkit.java b/jdk/src/macosx/classes/sun/lwawt/LWToolkit.java index 89f39fccbf8..cad6e4353ba 100644 --- a/jdk/src/macosx/classes/sun/lwawt/LWToolkit.java +++ b/jdk/src/macosx/classes/sun/lwawt/LWToolkit.java @@ -218,6 +218,23 @@ public abstract class LWToolkit extends SunToolkit implements Runnable { return peer; } + private LWLightweightFramePeer createDelegatedLwPeer(LightweightFrame target, + PlatformComponent platformComponent, + PlatformWindow platformWindow) + { + LWLightweightFramePeer peer = new LWLightweightFramePeer(target, platformComponent, platformWindow); + targetCreatedPeer(target, peer); + peer.initialize(); + return peer; + } + + @Override + public FramePeer createLightweightFrame(LightweightFrame target) { + PlatformComponent platformComponent = createLwPlatformComponent(); + PlatformWindow platformWindow = createPlatformWindow(LWWindowPeer.PeerType.LW_FRAME); + return createDelegatedLwPeer(target, platformComponent, platformWindow); + } + @Override public WindowPeer createWindow(Window target) { PlatformComponent platformComponent = createPlatformComponent(); @@ -502,6 +519,8 @@ public abstract class LWToolkit extends SunToolkit implements Runnable { protected abstract PlatformComponent createPlatformComponent(); + protected abstract PlatformComponent createLwPlatformComponent(); + protected abstract FileDialogPeer createFileDialogPeer(FileDialog target); // ---- UTILITY METHODS ---- // diff --git a/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java b/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java index 5b19788f244..d50335f7cd5 100644 --- a/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java +++ b/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java @@ -48,7 +48,8 @@ public class LWWindowPeer FRAME, DIALOG, EMBEDDED_FRAME, - VIEW_EMBEDDED_FRAME + VIEW_EMBEDDED_FRAME, + LW_FRAME } private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.lwawt.focus.LWWindowPeer"); @@ -1090,7 +1091,7 @@ public class LWWindowPeer return platformWindow.requestWindowFocus(); } - private boolean focusAllowedFor() { + protected boolean focusAllowedFor() { Window window = getTarget(); // TODO: check if modal blocked return window.isVisible() && window.isEnabled() && isFocusableWindow(); @@ -1113,10 +1114,15 @@ public class LWWindowPeer return !(window instanceof Dialog || window instanceof Frame); } + @Override + public void emulateActivation(boolean activate) { + changeFocusedWindow(activate, null); + } + /* * Changes focused window on java level. */ - private void changeFocusedWindow(boolean becomesFocused, Window opposite) { + protected void changeFocusedWindow(boolean becomesFocused, Window opposite) { if (focusLog.isLoggable(PlatformLogger.FINE)) { focusLog.fine((becomesFocused?"gaining":"loosing") + " focus window: " + this); } diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformComponent.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformComponent.java index 370b930ea98..978f65c3c91 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformComponent.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformComponent.java @@ -35,7 +35,7 @@ import sun.lwawt.PlatformWindow; * On OSX {@code CPlatformComponent} stores pointer to the native CAlayer which * can be used from JAWT. */ -final class CPlatformComponent extends CFRetainedResource +class CPlatformComponent extends CFRetainedResource implements PlatformComponent { private volatile PlatformWindow platformWindow; diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformLWComponent.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformLWComponent.java new file mode 100644 index 00000000000..fd76cf5c898 --- /dev/null +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformLWComponent.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package sun.lwawt.macosx; + +import sun.lwawt.PlatformWindow; + +class CPlatformLWComponent extends CPlatformComponent { + + CPlatformLWComponent() { + super(); + } + + @Override + public long getPointer() { + return 0; + } + + @Override + public void initialize(final PlatformWindow platformWindow) { + } + + @Override + public void setBounds(final int x, final int y, final int w, final int h) { + } + + @Override + public void dispose() { + } +} diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformLWView.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformLWView.java new file mode 100644 index 00000000000..e5d99678b18 --- /dev/null +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformLWView.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.lwawt.macosx; + +import sun.lwawt.LWWindowPeer; +import sun.java2d.SurfaceData; + +public class CPlatformLWView extends CPlatformView { + + public CPlatformLWView() { + super(); + } + + @Override + public void initialize(LWWindowPeer peer, CPlatformResponder responder) { + initializeBase(peer, responder); + } + + @Override + public long getAWTView() { + return 0; + } + + @Override + public boolean isOpaque() { + return true; + } + + @Override + public void setBounds(int x, int y, int width, int height) { + } + + @Override + public void enterFullScreenMode() { + } + + @Override + public void exitFullScreenMode() { + } + + @Override + public SurfaceData replaceSurfaceData() { + return null; + } + + @Override + public SurfaceData getSurfaceData() { + return null; + } + + @Override + public void dispose() { + } + + @Override + public long getWindowLayerPtr() { + return 0; + } +} diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java new file mode 100644 index 00000000000..d7a91264328 --- /dev/null +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.lwawt.macosx; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.GraphicsDevice; +import java.awt.Insets; +import java.awt.MenuBar; +import java.awt.Point; +import java.awt.Window; +import sun.awt.CausedFocusEvent; +import sun.java2d.SurfaceData; +import sun.lwawt.LWWindowPeer; +import sun.lwawt.PlatformWindow; + +public class CPlatformLWWindow extends CPlatformWindow { + + @Override + public void initialize(Window target, LWWindowPeer peer, PlatformWindow owner) { + initializeBase(target, peer, owner, new CPlatformLWView()); + } + + @Override + public void toggleFullScreen() { + } + + @Override + public void setMenuBar(MenuBar mb) { + } + + @Override + public void dispose() { + } + + @Override + public FontMetrics getFontMetrics(Font f) { + return null; + } + + @Override + public Insets getInsets() { + return new Insets(0, 0, 0, 0); + } + + @Override + public Point getLocationOnScreen() { + return null; + } + + @Override + public GraphicsDevice getGraphicsDevice() { + return null; + } + + @Override + public SurfaceData getScreenSurface() { + return null; + } + + @Override + public SurfaceData replaceSurfaceData() { + return null; + } + + @Override + public void setBounds(int x, int y, int w, int h) { + if (getPeer() != null) { + getPeer().notifyReshape(x, y, w, h); + } + } + + @Override + public void setVisible(boolean visible) { + } + + @Override + public void setTitle(String title) { + } + + @Override + public void updateIconImages() { + } + + @Override + public long getNSWindowPtr() { + return 0; + } + + @Override + public SurfaceData getSurfaceData() { + return null; + } + + @Override + public void toBack() { + } + + @Override + public void toFront() { + } + + @Override + public void setResizable(final boolean resizable) { + } + + @Override + public void setSizeConstraints(int minW, int minH, int maxW, int maxH) { + } + + @Override + public boolean rejectFocusRequest(CausedFocusEvent.Cause cause) { + return false; + } + + @Override + public boolean requestWindowFocus() { + return true; + } + + @Override + public boolean isActive() { + return true; + } + + @Override + public void updateFocusableWindowState() { + } + + @Override + public Graphics transformGraphics(Graphics g) { + return null; + } + + @Override + public void setAlwaysOnTop(boolean isAlwaysOnTop) { + } + + @Override + public PlatformWindow getTopmostPlatformWindowUnderMouse(){ + return null; + } + + @Override + public void setOpacity(float opacity) { + } + + @Override + public void setOpaque(boolean isOpaque) { + } + + @Override + public void enterFullScreenMode() { + } + + @Override + public void exitFullScreenMode() { + } + + @Override + public void setWindowState(int windowState) { + } + + @Override + public LWWindowPeer getPeer() { + return super.getPeer(); + } + + @Override + public CPlatformView getContentView() { + return super.getContentView(); + } + + @Override + public long getLayerPtr() { + return 0; + } +} diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java index 495657963bd..3a0bec48629 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java @@ -54,8 +54,7 @@ public class CPlatformView extends CFRetainedResource { } public void initialize(LWWindowPeer peer, CPlatformResponder responder) { - this.peer = peer; - this.responder = responder; + initializeBase(peer, responder); if (!LWCToolkit.getSunAwtDisableCALayers()) { this.windowLayer = new CGLLayer(peer); @@ -63,6 +62,11 @@ public class CPlatformView extends CFRetainedResource { setPtr(nativeCreateView(0, 0, 0, 0, getWindowLayerPtr())); } + protected void initializeBase(LWWindowPeer peer, CPlatformResponder responder) { + this.peer = peer; + this.responder = responder; + } + public long getAWTView() { return ptr; } diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java index 8f83702a209..dc51373cc1b 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java @@ -44,7 +44,7 @@ import com.apple.laf.*; import com.apple.laf.ClientPropertyApplicator.Property; import com.sun.awt.AWTUtilities; -public final class CPlatformWindow extends CFRetainedResource implements PlatformWindow { +public class CPlatformWindow extends CFRetainedResource implements PlatformWindow { private native long nativeCreateNSWindow(long nsViewPtr, long styleBits, double x, double y, double w, double h); private static native void nativeSetNSWindowStyleBits(long nsWindowPtr, int mask, int data); private static native void nativeSetNSWindowMenuBar(long nsWindowPtr, long menuBarPtr); @@ -218,11 +218,7 @@ public final class CPlatformWindow extends CFRetainedResource implements Platfor */ @Override // PlatformWindow public void initialize(Window _target, LWWindowPeer _peer, PlatformWindow _owner) { - this.peer = _peer; - this.target = _target; - if (_owner instanceof CPlatformWindow) { - this.owner = (CPlatformWindow)_owner; - } + initializeBase(_target, _peer, _owner, new CPlatformView()); final int styleBits = getInitialStyleBits(); @@ -231,7 +227,6 @@ public final class CPlatformWindow extends CFRetainedResource implements Platfor String warningString = target.getWarningString(); responder = new CPlatformResponder(peer, false); - contentView = new CPlatformView(); contentView.initialize(peer, responder); final long nativeWindowPtr = nativeCreateNSWindow(contentView.getAWTView(), styleBits, 0, 0, 0, 0); @@ -253,6 +248,15 @@ public final class CPlatformWindow extends CFRetainedResource implements Platfor validateSurface(); } + protected void initializeBase(Window target, LWWindowPeer peer, PlatformWindow owner, CPlatformView view) { + this.peer = peer; + this.target = target; + if (owner instanceof CPlatformWindow) { + this.owner = (CPlatformWindow)owner; + } + this.contentView = view; + } + private int getInitialStyleBits() { // defaults style bits int styleBits = DECORATED | HAS_SHADOW | CLOSEABLE | MINIMIZABLE | ZOOMABLE | RESIZABLE; diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java index ae6a4f77662..801c3d41605 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java @@ -160,6 +160,8 @@ public final class LWCToolkit extends LWToolkit { return new CPlatformEmbeddedFrame(); } else if (peerType == PeerType.VIEW_EMBEDDED_FRAME) { return new CViewPlatformEmbeddedFrame(); + } else if (peerType == PeerType.LW_FRAME) { + return new CPlatformLWWindow(); } else { assert (peerType == PeerType.SIMPLEWINDOW || peerType == PeerType.DIALOG || peerType == PeerType.FRAME); return new CPlatformWindow(); @@ -171,6 +173,11 @@ public final class LWCToolkit extends LWToolkit { return new CPlatformComponent(); } + @Override + protected PlatformComponent createLwPlatformComponent() { + return new CPlatformLWComponent(); + } + @Override protected FileDialogPeer createFileDialogPeer(FileDialog target) { return new CFileDialog(target); diff --git a/jdk/src/share/classes/java/awt/peer/FramePeer.java b/jdk/src/share/classes/java/awt/peer/FramePeer.java index 8bb3b07add9..e9d2b002fb0 100644 --- a/jdk/src/share/classes/java/awt/peer/FramePeer.java +++ b/jdk/src/share/classes/java/awt/peer/FramePeer.java @@ -125,4 +125,10 @@ public interface FramePeer extends WindowPeer { // into an EmbeddedFramePeer which would extend FramePeer Rectangle getBoundsPrivate(); + /** + * Requests the peer to emulate window activation. + * + * @param activate activate or deactivate the window + */ + void emulateActivation(boolean activate); } diff --git a/jdk/src/share/classes/java/awt/peer/WindowPeer.java b/jdk/src/share/classes/java/awt/peer/WindowPeer.java index f2e8993e101..fca78b7eed4 100644 --- a/jdk/src/share/classes/java/awt/peer/WindowPeer.java +++ b/jdk/src/share/classes/java/awt/peer/WindowPeer.java @@ -27,8 +27,6 @@ package java.awt.peer; import java.awt.*; -import java.awt.image.BufferedImage; - /** * The peer interface for {@link Window}. * diff --git a/jdk/src/share/classes/sun/awt/EmbeddedFrame.java b/jdk/src/share/classes/sun/awt/EmbeddedFrame.java index d05e30fe742..0ae1ec762df 100644 --- a/jdk/src/share/classes/sun/awt/EmbeddedFrame.java +++ b/jdk/src/share/classes/sun/awt/EmbeddedFrame.java @@ -582,5 +582,8 @@ public abstract class EmbeddedFrame extends Frame public void repositionSecurityWarning() { } - } + + public void emulateActivation(boolean activate) { + } + } } // class EmbeddedFrame diff --git a/jdk/src/share/classes/sun/awt/HToolkit.java b/jdk/src/share/classes/sun/awt/HToolkit.java index 57217678bfc..8671d8b5150 100644 --- a/jdk/src/share/classes/sun/awt/HToolkit.java +++ b/jdk/src/share/classes/sun/awt/HToolkit.java @@ -64,6 +64,11 @@ public class HToolkit extends SunToolkit throw new HeadlessException(); } + public FramePeer createLightweightFrame(LightweightFrame target) + throws HeadlessException { + throw new HeadlessException(); + } + public FramePeer createFrame(Frame target) throws HeadlessException { throw new HeadlessException(); diff --git a/jdk/src/share/classes/sun/awt/LightweightFrame.java b/jdk/src/share/classes/sun/awt/LightweightFrame.java new file mode 100644 index 00000000000..71e3dd30333 --- /dev/null +++ b/jdk/src/share/classes/sun/awt/LightweightFrame.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.awt; + +import java.awt.Container; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.MenuBar; +import java.awt.MenuComponent; +import java.awt.Toolkit; +import java.awt.peer.FramePeer; + +/** + * The class provides basic functionality for a lightweight frame + * implementation. A subclass is expected to provide painting to an + * offscreen image and access to it. Thus it can be used for lightweight + * embedding. + * + * @author Artem Ananiev + * @author Anton Tarasov + */ +@SuppressWarnings("serial") +public abstract class LightweightFrame extends Frame { + + /** + * Constructs a new, initially invisible {@code LightweightFrame} + * instance. + */ + public LightweightFrame() { + setUndecorated(true); + setResizable(true); + setEnabled(true); + } + + /** + * Blocks introspection of a parent window by this child. + * + * @return null + */ + @Override public final Container getParent() { return null; } + + @Override public Graphics getGraphics() { return null; } + + @Override public final boolean isResizable() { return true; } + + // Block modification of any frame attributes, since they aren't + // applicable for a lightweight frame. + + @Override public final void setTitle(String title) {} + @Override public final void setIconImage(Image image) {} + @Override public final void setIconImages(java.util.List<? extends Image> icons) {} + @Override public final void setMenuBar(MenuBar mb) {} + @Override public final void setResizable(boolean resizable) {} + @Override public final void remove(MenuComponent m) {} + @Override public final void toFront() {} + @Override public final void toBack() {} + + @Override public void addNotify() { + synchronized (getTreeLock()) { + if (getPeer() == null) { + SunToolkit stk = (SunToolkit)Toolkit.getDefaultToolkit(); + try { + setPeer(stk.createLightweightFrame(this)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + super.addNotify(); + } + } + + private void setPeer(final FramePeer p) { + AWTAccessor.getComponentAccessor().setPeer(this, p); + } + + /** + * Requests the peer to emulate activation or deactivation of the + * frame. Peers should override this method if they are to implement + * this functionality. + * + * @param activate if <code>true</code>, activates the frame; + * otherwise, deactivates the frame + */ + public void emulateActivation(boolean activate) { + ((FramePeer)getPeer()).emulateActivation(activate); + } + + /** + * Delegates the focus grab action to the client (embedding) application. + * The method is called by the AWT grab machinery. + * + * @see SunToolkit#grab(java.awt.Window) + */ + public abstract void grabFocus(); + + /** + * Delegates the focus ungrab action to the client (embedding) application. + * The method is called by the AWT grab machinery. + * + * @see SunToolkit#ungrab(java.awt.Window) + */ + public abstract void ungrabFocus(); +} diff --git a/jdk/src/share/classes/sun/awt/SunToolkit.java b/jdk/src/share/classes/sun/awt/SunToolkit.java index 4ae6a94f0dc..8fc568913fb 100644 --- a/jdk/src/share/classes/sun/awt/SunToolkit.java +++ b/jdk/src/share/classes/sun/awt/SunToolkit.java @@ -131,6 +131,9 @@ public abstract class SunToolkit extends Toolkit public abstract FramePeer createFrame(Frame target) throws HeadlessException; + public abstract FramePeer createLightweightFrame(LightweightFrame target) + throws HeadlessException; + public abstract DialogPeer createDialog(Dialog target) throws HeadlessException; diff --git a/jdk/src/share/classes/sun/swing/JLightweightFrame.java b/jdk/src/share/classes/sun/swing/JLightweightFrame.java new file mode 100644 index 00000000000..f7ea0aead1e --- /dev/null +++ b/jdk/src/share/classes/sun/swing/JLightweightFrame.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.swing; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.EventQueue; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; + +import javax.swing.JLayeredPane; +import javax.swing.JPanel; +import javax.swing.JRootPane; +import javax.swing.LayoutFocusTraversalPolicy; +import javax.swing.RootPaneContainer; + +import sun.awt.LightweightFrame; + +/** + * The frame serves as a lightweight container which paints its content + * to an offscreen image and provides access to the image's data via the + * {@link LightweightContent} interface. Note, that it may not be shown + * as a standalone toplevel frame. Its purpose is to provide functionality + * for lightweight embedding. + * + * @author Artem Ananiev + * @author Anton Tarasov + */ +public final class JLightweightFrame extends LightweightFrame implements RootPaneContainer { + + private final JRootPane rootPane = new JRootPane(); + + private LightweightContent content; + + private Component component; + private JPanel contentPane; + + private BufferedImage bbImage; + + /** + * Constructs a new, initially invisible {@code JLightweightFrame} + * instance. + */ + public JLightweightFrame() { + super(); + add(rootPane, BorderLayout.CENTER); + setBackground(new Color(0, 0, 0, 0)); + setFocusTraversalPolicy(new LayoutFocusTraversalPolicy()); + } + + /** + * Sets the {@link LightweightContent} instance for this frame. + * The {@code JComponent} object returned by the + * {@link LightweightContent#getComponent()} method is immediately + * added to the frame's content pane. + * + * @param content the {@link LightweightContent} instance + */ + public void setContent(LightweightContent content) { + this.content = content; + this.component = content.getComponent(); + + initInterior(); + } + + @Override + public Graphics getGraphics() { + if (bbImage == null) return null; + + Graphics2D g = bbImage.createGraphics(); + g.setBackground(getBackground()); + g.setColor(getForeground()); + g.setFont(getFont()); + return g; + } + + /** + * {@inheritDoc} + * + * @see LightweightContent#focusGrabbed() + */ + @Override + public void grabFocus() { + if (content != null) content.focusGrabbed(); + } + + /** + * {@inheritDoc} + * + * @see LightweightContent#focusUngrabbed() + */ + @Override + public void ungrabFocus() { + if (content != null) content.focusUngrabbed(); + } + + private void initInterior() { + contentPane = new JPanel() { + @Override + public void paint(Graphics g) { + content.paintLock(); + try { + super.paint(g); + + final Rectangle clip = g.getClipBounds() != null ? + g.getClipBounds() : new Rectangle(0, 0, contentPane.getWidth(), contentPane.getHeight()); + + clip.x = Math.max(0, clip.x); + clip.y = Math.max(0, clip.y); + clip.width = Math.min(contentPane.getWidth(), clip.width); + clip.height = Math.min(contentPane.getHeight(), clip.height); + + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + content.imageUpdated(clip.x, clip.y, clip.width, clip.height); + } + }); + } finally { + content.paintUnlock(); + } + } + @Override + protected boolean isPaintingOrigin() { + return true; + } + }; + contentPane.setLayout(new BorderLayout()); + contentPane.add(component); + setContentPane(contentPane); + } + + @SuppressWarnings("deprecation") + @Override public void reshape(int x, int y, int width, int height) { + super.reshape(x, y, width, height); + + if (width == 0 || height == 0) { + return; + } + + content.paintLock(); + try { + if ((bbImage == null) || (width != bbImage.getWidth()) || (height != bbImage.getHeight())) { + boolean createBB = true; + int newW = width; + int newH = height; + if (bbImage != null) { + int oldW = bbImage.getWidth(); + int oldH = bbImage.getHeight(); + if ((oldW >= newW) && (oldH >= newH)) { + createBB = false; + } else { + if (oldW >= newW) { + newW = oldW; + } else { + newW = Math.max((int)(oldW * 1.2), width); + } + if (oldH >= newH) { + newH = oldH; + } else { + newH = Math.max((int)(oldH * 1.2), height); + } + } + } + if (createBB) { + BufferedImage oldBB = bbImage; + bbImage = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_ARGB_PRE); + if (oldBB != null) { + Graphics g = bbImage.getGraphics(); + try { + g.drawImage(oldBB, 0, 0, newW, newH, null); + } finally { + g.dispose(); + oldBB.flush(); + } + } + DataBufferInt dataBuf = (DataBufferInt)bbImage.getRaster().getDataBuffer(); + content.imageBufferReset(dataBuf.getData(), 0, 0, width, height, bbImage.getWidth()); + } else { + content.imageReshaped(0, 0, width, height); + } + } + } finally { + content.paintUnlock(); + } + } + + @Override + public JRootPane getRootPane() { + return rootPane; + } + + @Override + public void setContentPane(Container contentPane) { + getRootPane().setContentPane(contentPane); + } + + @Override + public Container getContentPane() { + return getRootPane().getContentPane(); + } + + @Override + public void setLayeredPane(JLayeredPane layeredPane) { + getRootPane().setLayeredPane(layeredPane); + } + + @Override + public JLayeredPane getLayeredPane() { + return getRootPane().getLayeredPane(); + } + + @Override + public void setGlassPane(Component glassPane) { + getRootPane().setGlassPane(glassPane); + } + + @Override + public Component getGlassPane() { + return getRootPane().getGlassPane(); + } +} diff --git a/jdk/src/share/classes/sun/swing/LightweightContent.java b/jdk/src/share/classes/sun/swing/LightweightContent.java new file mode 100644 index 00000000000..2d443fba23c --- /dev/null +++ b/jdk/src/share/classes/sun/swing/LightweightContent.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.swing; + +import javax.swing.JComponent; + +/** + * The interface by means of which the {@link JLightweightFrame} class + * communicates to its client application. + * <p> + * The client application implements this interface so it can response + * to requests and process notifications from {@code JLightweightFrame}. + * An implementation of this interface is associated with a {@code + * JLightweightFrame} instance via the {@link JLightweightFrame#setContent} + * method. + * + * A hierarchy of components contained in the {@code JComponent} instance + * returned by the {@link #getComponent} method should not contain any + * heavyweight components, otherwise {@code JLightweightFrame} may fail + * to paint it. + * + * @author Artem Ananiev + * @author Anton Tarasov + * @author Jim Graham + */ +public interface LightweightContent { + + /** + * The client application overrides this method to return the {@code + * JComponent} instance which the {@code JLightweightFrame} container + * will paint as its lightweight content. A hierarchy of components + * contained in this component should not contain any heavyweight objects. + * + * @return the component to paint + */ + public JComponent getComponent(); + + /** + * {@code JLightweightFrame} calls this method to notify the client + * application that it acquires the paint lock. The client application + * should implement the locking mechanism in order to synchronize access + * to the content image data, shared between {@code JLightweightFrame} + * and the client application. + * + * @see #paintUnlock + */ + public void paintLock(); + + /** + * {@code JLightweightFrame} calls this method to notify the client + * application that it releases the paint lock. The client application + * should implement the locking mechanism in order to synchronize access + * to the content image data, shared between {@code JLightweightFrame} + * and the client application. + * + * @see #paintLock + */ + public void paintUnlock(); + + /** + * {@code JLightweightFrame} calls this method to notify the client + * application that a new data buffer has been set as a content pixel + * buffer. Typically this occurs when a buffer of a larger size is + * created in response to a content resize event. The method reports + * a reference to the pixel data buffer, the content image bounds + * within the buffer and the line stride of the buffer. These values + * have the following correlation. + * <p> + * The {@code width} and {@code height} matches the size of the content + * (the component returned from the {@link #getComponent} method). The + * {@code x} and {@code y} is the origin of the content, {@code (0, 0)} + * in the coordinate space of the content, appearing at + * {@code data[y * linestride + x]} in the buffer. All indices + * {@code data[(y + j) * linestride + (x + i)]} where + * {@code (0 <= i < width)} and {@code (0 <= j < height)} will represent + * valid pixel data, {@code (i, j)} in the coordinate space of the content. + * + * @param data the content pixel data buffer of INT_ARGB_PRE type + * @param x the x coordinate of the image + * @param y the y coordinate of the image + * @param width the width of the image + * @param height the height of the image + * @param linestride the line stride of the pixel buffer + */ + public void imageBufferReset(int[] data, + int x, int y, + int width, int height, + int linestride); + + /** + * {@code JLightweightFrame} calls this method to notify the client + * application that the content image bounds have been changed within the + * image's pixel buffer. + * + * @param x the x coordinate of the image + * @param y the y coordinate of the image + * @param width the width of the image + * @param height the height of the image + * + * @see #imageBufferReset + */ + public void imageReshaped(int x, int y, int width, int height); + + /** + * {@code JLightweightFrame} calls this method to notify the client + * application that a part of the content image, or the whole image has + * been updated. The method reports bounds of the rectangular dirty region. + * The {@code dirtyX} and {@code dirtyY} is the origin of the dirty + * rectangle, which is relative to the origin of the content, appearing + * at {@code data[(y + dirtyY] * linestride + (x + dirtyX)]} in the pixel + * buffer (see {@link #imageBufferReset}). All indices + * {@code data[(y + dirtyY + j) * linestride + (x + dirtyX + i)]} where + * {@code (0 <= i < dirtyWidth)} and {@code (0 <= j < dirtyHeight)} + * will represent valid pixel data, {@code (i, j)} in the coordinate space + * of the dirty rectangle. + * + * @param dirtyX the x coordinate of the dirty rectangle, + * relative to the image origin + * @param dirtyY the y coordinate of the dirty rectangle, + * relative to the image origin + * @param dirtyWidth the width of the dirty rectangle + * @param dirtyHeight the height of the dirty rectangle + * + * @see #imageBufferReset + * @see #imageReshaped + */ + public void imageUpdated(int dirtyX, int dirtyY, + int dirtyWidth, int dirtyHeight); + + /** + * {@code JLightweightFrame} calls this method to notify the client + * application that the frame has grabbed focus. + */ + public void focusGrabbed(); + + /** + * {@code JLightweightFrame} calls this method to notify the client + * application that the frame has ungrabbed focus. + */ + public void focusUngrabbed(); +} diff --git a/jdk/src/solaris/classes/sun/awt/X11/XFramePeer.java b/jdk/src/solaris/classes/sun/awt/X11/XFramePeer.java index fdefb1047ce..0c540b17855 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XFramePeer.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XFramePeer.java @@ -641,4 +641,6 @@ class XFramePeer extends XDecoratedPeer implements FramePeer { public Rectangle getBoundsPrivate() { return getBounds(); } + + public void emulateActivation(boolean doActivate) {} } diff --git a/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java index 7c40e8260ef..b4fb9c76f17 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java @@ -419,6 +419,10 @@ public final class XToolkit extends UNIXToolkit implements Runnable { return peer; } + public FramePeer createLightweightFrame(LightweightFrame target) { + return null; + } + public FramePeer createFrame(Frame target) { FramePeer peer = new XFramePeer(target); targetCreatedPeer(target, peer); diff --git a/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java b/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java index b0f9cd3279d..ba6ae8aefb2 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java +++ b/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java @@ -226,15 +226,15 @@ public class WEmbeddedFrame extends EmbeddedFrame { } @SuppressWarnings("deprecation") - public void synthesizeWindowActivation(final boolean doActivate) { - if (!doActivate || EventQueue.isDispatchThread()) { - ((WEmbeddedFramePeer)getPeer()).synthesizeWmActivate(doActivate); + public void synthesizeWindowActivation(final boolean activate) { + if (!activate || EventQueue.isDispatchThread()) { + ((WFramePeer)getPeer()).emulateActivation(activate); } else { // To avoid focus concurrence b/w IE and EmbeddedFrame // activation is postponed by means of posting it to EDT. EventQueue.invokeLater(new Runnable() { public void run() { - ((WEmbeddedFramePeer)getPeer()).synthesizeWmActivate(true); + ((WFramePeer)getPeer()).emulateActivation(true); } }); } diff --git a/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java b/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java index 3b6d298bda8..ec551e30ced 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java +++ b/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java @@ -65,8 +65,6 @@ public class WEmbeddedFramePeer extends WFramePeer { public native Rectangle getBoundsPrivate(); - public native void synthesizeWmActivate(boolean doActivate); - @Override public boolean isAccelCapable() { // REMIND: Temp workaround for issues with using HW acceleration diff --git a/jdk/src/windows/classes/sun/awt/windows/WFramePeer.java b/jdk/src/windows/classes/sun/awt/windows/WFramePeer.java index 368b8f60696..588b3caebdd 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WFramePeer.java +++ b/jdk/src/windows/classes/sun/awt/windows/WFramePeer.java @@ -200,4 +200,11 @@ class WFramePeer extends WWindowPeer implements FramePeer { public Rectangle getBoundsPrivate() { return getBounds(); } + + // TODO: implement it in peers. WLightweightFramePeer may implement lw version. + public void emulateActivation(boolean activate) { + synthesizeWmActivate(activate); + } + + private native void synthesizeWmActivate(boolean activate); } diff --git a/jdk/src/windows/classes/sun/awt/windows/WLightweightFramePeer.java b/jdk/src/windows/classes/sun/awt/windows/WLightweightFramePeer.java new file mode 100644 index 00000000000..c2c1604bef4 --- /dev/null +++ b/jdk/src/windows/classes/sun/awt/windows/WLightweightFramePeer.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.awt.windows; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.event.ComponentEvent; +import java.awt.event.MouseEvent; + +import sun.awt.LightweightFrame; + +public class WLightweightFramePeer extends WFramePeer { + + public WLightweightFramePeer(LightweightFrame target) { + super(target); + } + + private LightweightFrame getLwTarget() { + return (LightweightFrame)target; + } + + @Override + public Graphics getGraphics() { + return getLwTarget().getGraphics(); + } + + @Override + public void show() { + super.show(); + postEvent(new ComponentEvent((Component)getTarget(), ComponentEvent.COMPONENT_SHOWN)); + } + + @Override + public void hide() { + super.hide(); + postEvent(new ComponentEvent((Component)getTarget(), ComponentEvent.COMPONENT_HIDDEN)); + } + + @Override + public void reshape(int x, int y, int width, int height) { + super.reshape(x, y, width, height); + postEvent(new ComponentEvent((Component) getTarget(), ComponentEvent.COMPONENT_MOVED)); + postEvent(new ComponentEvent((Component) getTarget(), ComponentEvent.COMPONENT_RESIZED)); + } + + @Override + public void handleEvent(java.awt.AWTEvent e) { + if (e.getID() == MouseEvent.MOUSE_PRESSED) { + emulateActivation(true); + } + super.handleEvent(e); + } + + @Override + public void grab() { + getLwTarget().grabFocus(); + } + + @Override + public void ungrab() { + getLwTarget().ungrabFocus(); + } +} diff --git a/jdk/src/windows/classes/sun/awt/windows/WToolkit.java b/jdk/src/windows/classes/sun/awt/windows/WToolkit.java index afbdfa6c1f9..e87b0ad8c08 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WToolkit.java +++ b/jdk/src/windows/classes/sun/awt/windows/WToolkit.java @@ -37,6 +37,7 @@ import java.beans.PropertyChangeListener; import java.security.AccessController; import java.security.PrivilegedAction; import sun.awt.AWTAutoShutdown; +import sun.awt.LightweightFrame; import sun.awt.SunToolkit; import sun.awt.Win32GraphicsDevice; import sun.awt.Win32GraphicsEnvironment; @@ -398,6 +399,12 @@ public class WToolkit extends SunToolkit implements Runnable { return peer; } + public FramePeer createLightweightFrame(LightweightFrame target) { + FramePeer peer = new WLightweightFramePeer(target); + targetCreatedPeer(target, peer); + return peer; + } + public CanvasPeer createCanvas(Canvas target) { CanvasPeer peer = new WCanvasPeer(target); targetCreatedPeer(target, peer); diff --git a/jdk/src/windows/native/sun/windows/awt_Frame.cpp b/jdk/src/windows/native/sun/windows/awt_Frame.cpp index da1df839535..41c5624f001 100644 --- a/jdk/src/windows/native/sun/windows/awt_Frame.cpp +++ b/jdk/src/windows/native/sun/windows/awt_Frame.cpp @@ -105,6 +105,7 @@ AwtFrame::AwtFrame() { m_parentWnd = NULL; menuBar = NULL; m_isEmbedded = FALSE; + m_isLightweight = FALSE; m_ignoreWmSize = FALSE; m_isMenuDropped = FALSE; m_isInputMethodWindow = FALSE; @@ -170,14 +171,13 @@ AwtFrame* AwtFrame::Create(jobject self, jobject parent) * area of the browser is a Java Frame for parenting purposes, but * really a Windows child window */ + BOOL isEmbeddedInstance = FALSE; + BOOL isEmbedded = FALSE; cls = env->FindClass("sun/awt/EmbeddedFrame"); - if (cls == NULL) { - return NULL; + if (cls) { + isEmbeddedInstance = env->IsInstanceOf(target, cls); } INT_PTR handle; - jboolean isEmbeddedInstance = env->IsInstanceOf(target, cls); - jboolean isEmbedded = FALSE; - if (isEmbeddedInstance) { handle = static_cast<INT_PTR>(env->GetLongField(target, AwtFrame::handleID)); if (handle != 0) { @@ -186,6 +186,13 @@ AwtFrame* AwtFrame::Create(jobject self, jobject parent) } frame->m_isEmbedded = isEmbedded; + BOOL isLightweight = FALSE; + cls = env->FindClass("sun/awt/LightweightFrame"); + if (cls) { + isLightweight = env->IsInstanceOf(target, cls); + } + frame->m_isLightweight = isLightweight; + if (isEmbedded) { hwndParent = (HWND)handle; RECT rect; @@ -230,6 +237,23 @@ AwtFrame* AwtFrame::Create(jobject self, jobject parent) rect.bottom-rect.top); frame->InitPeerGraphicsConfig(env, self); AwtToolkit::GetInstance().RegisterEmbedderProcessId(hwndParent); + } else if (isLightweight) { + frame->m_isUndecorated = true; + frame->m_peerObject = env->NewGlobalRef(self); + frame->RegisterClass(); + + DWORD exStyle = 0; + DWORD style = WS_POPUP; + + frame->CreateHWnd(env, L"", + style, + exStyle, + 0, 0, 0, 0, + 0, + NULL, + ::GetSysColor(COLOR_WINDOWTEXT), + ::GetSysColor(COLOR_WINDOWFRAME), + self); } else { jint state = env->CallIntMethod(self, AwtFrame::getExtendedStateMID); DWORD exStyle; @@ -345,16 +369,20 @@ LRESULT AwtFrame::ProxyWindowProc(UINT message, WPARAM wParam, LPARAM lParam, Ms case WM_SETFOCUS: if (sm_inSynthesizeFocus) break; // pass it up the WindowProc chain - if (!sm_suppressFocusAndActivation && IsEmbeddedFrame()) { - AwtSetActiveWindow(); + if (!sm_suppressFocusAndActivation) { + if (IsLightweightFrame() || IsEmbeddedFrame()) { + AwtSetActiveWindow(); + } } mr = mrConsume; break; case WM_KILLFOCUS: if (sm_inSynthesizeFocus) break; // pass it up the WindowProc chain - if (!sm_suppressFocusAndActivation && IsEmbeddedFrame()) { - AwtWindow::SynthesizeWmActivate(FALSE, GetHWnd(), NULL); + if (!sm_suppressFocusAndActivation) { + if (IsLightweightFrame() || IsEmbeddedFrame()) { + AwtWindow::SynthesizeWmActivate(FALSE, GetHWnd(), NULL); + } } else if (sm_restoreFocusAndActivation) { if (AwtComponent::GetFocusedWindow() != NULL) { @@ -640,6 +668,10 @@ AwtFrame::Show() HWND hwnd = GetHWnd(); JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); + if (IsLightweightFrame()) { + return; + } + DTRACE_PRINTLN3("AwtFrame::Show:%s%s%s", m_iconic ? " iconic" : "", m_zoomed ? " zoomed" : "", @@ -992,6 +1024,9 @@ BOOL AwtFrame::AwtSetActiveWindow(BOOL isMouseEventCause, UINT hittest) // b) focus is requested to some of the frame's child. m_actualFocusedWindow = NULL; } + if (IsLightweightFrame()) { + return TRUE; + } return AwtWindow::AwtSetActiveWindow(isMouseEventCause); } @@ -1873,7 +1908,7 @@ Java_sun_awt_windows_WEmbeddedFramePeer_getBoundsPrivate(JNIEnv *env, jobject se } JNIEXPORT void JNICALL -Java_sun_awt_windows_WEmbeddedFramePeer_synthesizeWmActivate(JNIEnv *env, jobject self, jboolean doActivate) +Java_sun_awt_windows_WFramePeer_synthesizeWmActivate(JNIEnv *env, jobject self, jboolean doActivate) { TRY; diff --git a/jdk/src/windows/native/sun/windows/awt_Frame.h b/jdk/src/windows/native/sun/windows/awt_Frame.h index f6d692b87eb..e151c17c2a5 100644 --- a/jdk/src/windows/native/sun/windows/awt_Frame.h +++ b/jdk/src/windows/native/sun/windows/awt_Frame.h @@ -72,6 +72,8 @@ public: /* Returns whether this frame is embedded in an external native frame. */ INLINE BOOL IsEmbeddedFrame() { return m_isEmbedded; } + /* Returns whether this frame is lightweight. */ + INLINE virtual BOOL IsLightweightFrame() { return m_isLightweight; } INLINE BOOL IsSimpleWindow() { return FALSE; } @@ -169,6 +171,9 @@ private: /* The frame is an EmbeddedFrame. */ BOOL m_isEmbedded; + /* The frame is a LightweightFrame */ + BOOL m_isLightweight; + /* used so that calls to ::MoveWindow in SetMenuBar don't propogate because they are immediately followed by calls to Component.resize */ BOOL m_ignoreWmSize; diff --git a/jdk/src/windows/native/sun/windows/awt_Window.h b/jdk/src/windows/native/sun/windows/awt_Window.h index 8ad2b0902b2..0ee23322d4b 100644 --- a/jdk/src/windows/native/sun/windows/awt_Window.h +++ b/jdk/src/windows/native/sun/windows/awt_Window.h @@ -143,6 +143,7 @@ public: INLINE HICON GetHIcon() {return m_hIcon;}; INLINE HICON GetHIconSm() {return m_hIconSm;}; INLINE BOOL IsIconInherited() {return m_iconInherited;}; + INLINE virtual BOOL IsLightweightFrame() {return FALSE;} /* Post events to the EventQueue */ void SendComponentEvent(jint eventId); @@ -193,8 +194,10 @@ public: // Execute on Toolkit only. INLINE static LRESULT SynthesizeWmActivate(BOOL doActivate, HWND targetHWnd, HWND oppositeHWnd) { + AwtWindow *win = static_cast<AwtWindow*>(AwtComponent::GetComponent(targetHWnd)); if (doActivate && - (!::IsWindowVisible(targetHWnd) || ::IsIconic(::GetAncestor(targetHWnd, GA_ROOT)))) + (!::IsWindowVisible(targetHWnd) || ::IsIconic(::GetAncestor(targetHWnd, GA_ROOT))) && + (win == NULL || !win->IsLightweightFrame())) { // The activation is rejected if either: // - The toplevel is not visible From ba7a50ebcfccfe0e03c058a8f66a622403664b80 Mon Sep 17 00:00:00 2001 From: Alan Bateman <alanb@openjdk.org> Date: Fri, 22 Feb 2013 14:04:06 +0000 Subject: [PATCH 091/180] 8008290: (profiles) Startup regression due to additional checking of JAR file manifests Reviewed-by: lancea, chegar, iris, mchung, sherman --- .../share/classes/java/util/jar/JarFile.java | 147 ++++++++++++------ .../java/util/jar/JavaUtilJarAccessImpl.java | 4 + .../classes/sun/misc/JavaUtilJarAccess.java | 1 + .../share/classes/sun/misc/URLClassPath.java | 6 +- 4 files changed, 105 insertions(+), 53 deletions(-) diff --git a/jdk/src/share/classes/java/util/jar/JarFile.java b/jdk/src/share/classes/java/util/jar/JarFile.java index 513d509e2f8..a225d95fce7 100644 --- a/jdk/src/share/classes/java/util/jar/JarFile.java +++ b/jdk/src/share/classes/java/util/jar/JarFile.java @@ -63,8 +63,13 @@ class JarFile extends ZipFile { private JarVerifier jv; private boolean jvInitialized; private boolean verify; - private boolean computedHasClassPathAttribute; + + // indicates if Class-Path attribute present (only valid if hasCheckedSpecialAttributes true) private boolean hasClassPathAttribute; + // indicates if Profile attribute present (only valid if hasCheckedSpecialAttributes true) + private boolean hasProfileAttribute; + // true if manifest checked for special attributes + private volatile boolean hasCheckedSpecialAttributes; // Set up JavaUtilJarAccess in SharedSecrets static { @@ -421,27 +426,45 @@ class JarFile extends ZipFile { jv); } - // Statics for hand-coded Boyer-Moore search in hasClassPathAttribute() + // Statics for hand-coded Boyer-Moore search + private static final char[] CLASSPATH_CHARS = {'c','l','a','s','s','-','p','a','t','h'}; + private static final char[] PROFILE_CHARS = { 'p', 'r', 'o', 'f', 'i', 'l', 'e' }; // The bad character shift for "class-path" - private static int[] lastOcc; + private static final int[] CLASSPATH_LASTOCC; // The good suffix shift for "class-path" - private static int[] optoSft; - // Initialize the shift arrays to search for "class-path" - private static char[] src = {'c','l','a','s','s','-','p','a','t','h'}; + private static final int[] CLASSPATH_OPTOSFT; + // The bad character shift for "profile" + private static final int[] PROFILE_LASTOCC; + // The good suffix shift for "profile" + private static final int[] PROFILE_OPTOSFT; + static { - lastOcc = new int[128]; - optoSft = new int[10]; - lastOcc[(int)'c']=1; - lastOcc[(int)'l']=2; - lastOcc[(int)'s']=5; - lastOcc[(int)'-']=6; - lastOcc[(int)'p']=7; - lastOcc[(int)'a']=8; - lastOcc[(int)'t']=9; - lastOcc[(int)'h']=10; + CLASSPATH_LASTOCC = new int[128]; + CLASSPATH_OPTOSFT = new int[10]; + CLASSPATH_LASTOCC[(int)'c'] = 1; + CLASSPATH_LASTOCC[(int)'l'] = 2; + CLASSPATH_LASTOCC[(int)'s'] = 5; + CLASSPATH_LASTOCC[(int)'-'] = 6; + CLASSPATH_LASTOCC[(int)'p'] = 7; + CLASSPATH_LASTOCC[(int)'a'] = 8; + CLASSPATH_LASTOCC[(int)'t'] = 9; + CLASSPATH_LASTOCC[(int)'h'] = 10; for (int i=0; i<9; i++) - optoSft[i]=10; - optoSft[9]=1; + CLASSPATH_OPTOSFT[i] = 10; + CLASSPATH_OPTOSFT[9]=1; + + PROFILE_LASTOCC = new int[128]; + PROFILE_OPTOSFT = new int[7]; + PROFILE_LASTOCC[(int)'p'] = 1; + PROFILE_LASTOCC[(int)'r'] = 2; + PROFILE_LASTOCC[(int)'o'] = 3; + PROFILE_LASTOCC[(int)'f'] = 4; + PROFILE_LASTOCC[(int)'i'] = 5; + PROFILE_LASTOCC[(int)'l'] = 6; + PROFILE_LASTOCC[(int)'e'] = 7; + for (int i=0; i<6; i++) + PROFILE_OPTOSFT[i] = 7; + PROFILE_OPTOSFT[6] = 1; } private JarEntry getManEntry() { @@ -466,17 +489,55 @@ class JarFile extends ZipFile { return manEntry; } - // Returns true iff this jar file has a manifest with a class path - // attribute. Returns false if there is no manifest or the manifest - // does not contain a "Class-Path" attribute. Currently exported to - // core libraries via sun.misc.SharedSecrets. + /** + * Returns {@code true} iff this JAR file has a manifest with the + * Class-Path attribute + */ boolean hasClassPathAttribute() throws IOException { - if (computedHasClassPathAttribute) { - return hasClassPathAttribute; - } + checkForSpecialAttributes(); + return hasClassPathAttribute; + } - hasClassPathAttribute = false; - if (!isKnownToNotHaveClassPathAttribute()) { + /** + * Returns {@code true} iff this JAR file has a manifest with the + * Profile attribute + */ + boolean hasProfileAttribute() throws IOException { + checkForSpecialAttributes(); + return hasProfileAttribute; + } + + /** + * Returns true if the pattern {@code src} is found in {@code b}. + * The {@code lastOcc} and {@code optoSft} arrays are the precomputed + * bad character and good suffix shifts. + */ + private boolean match(char[] src, byte[] b, int[] lastOcc, int[] optoSft) { + int len = src.length; + int last = b.length - len; + int i = 0; + next: + while (i<=last) { + for (int j=(len-1); j>=0; j--) { + char c = (char) b[i+j]; + c = (((c-'A')|('Z'-c)) >= 0) ? (char)(c + 32) : c; + if (c != src[j]) { + i += Math.max(j + 1 - lastOcc[c&0x7F], optoSft[j]); + continue next; + } + } + return true; + } + return false; + } + + /** + * On first invocation, check if the JAR file has the Class-Path + * and/or Profile attributes. A no-op on subsequent calls. + */ + private void checkForSpecialAttributes() throws IOException { + if (hasCheckedSpecialAttributes) return; + if (!isKnownNotToHaveSpecialAttributes()) { JarEntry manEntry = getManEntry(); if (manEntry != null) { byte[] b = new byte[(int)manEntry.getSize()]; @@ -484,31 +545,18 @@ class JarFile extends ZipFile { super.getInputStream(manEntry))) { dis.readFully(b, 0, b.length); } - - int last = b.length - src.length; - int i = 0; - next: - while (i<=last) { - for (int j=9; j>=0; j--) { - char c = (char) b[i+j]; - c = (((c-'A')|('Z'-c)) >= 0) ? (char)(c + 32) : c; - if (c != src[j]) { - i += Math.max(j + 1 - lastOcc[c&0x7F], optoSft[j]); - continue next; - } - } + if (match(CLASSPATH_CHARS, b, CLASSPATH_LASTOCC, CLASSPATH_OPTOSFT)) hasClassPathAttribute = true; - break; - } + if (match(PROFILE_CHARS, b, PROFILE_LASTOCC, PROFILE_OPTOSFT)) + hasProfileAttribute = true; } } - computedHasClassPathAttribute = true; - return hasClassPathAttribute; + hasCheckedSpecialAttributes = true; } private static String javaHome; - private static String[] jarNames; - private boolean isKnownToNotHaveClassPathAttribute() { + private static volatile String[] jarNames; + private boolean isKnownNotToHaveSpecialAttributes() { // Optimize away even scanning of manifest for jar files we // deliver which don't have a class-path attribute. If one of // these jars is changed to include such an attribute this code @@ -518,19 +566,20 @@ class JarFile extends ZipFile { new GetPropertyAction("java.home")); } if (jarNames == null) { - String[] names = new String[10]; + String[] names = new String[11]; String fileSep = File.separator; int i = 0; names[i++] = fileSep + "rt.jar"; - names[i++] = fileSep + "sunrsasign.jar"; names[i++] = fileSep + "jsse.jar"; names[i++] = fileSep + "jce.jar"; names[i++] = fileSep + "charsets.jar"; names[i++] = fileSep + "dnsns.jar"; - names[i++] = fileSep + "ldapsec.jar"; + names[i++] = fileSep + "zipfs.jar"; names[i++] = fileSep + "localedata.jar"; + names[i++] = fileSep = "cldrdata.jar"; names[i++] = fileSep + "sunjce_provider.jar"; names[i++] = fileSep + "sunpkcs11.jar"; + names[i++] = fileSep + "sunec.jar"; jarNames = names; } diff --git a/jdk/src/share/classes/java/util/jar/JavaUtilJarAccessImpl.java b/jdk/src/share/classes/java/util/jar/JavaUtilJarAccessImpl.java index 9541a5a45f3..86a7ec5d2c6 100644 --- a/jdk/src/share/classes/java/util/jar/JavaUtilJarAccessImpl.java +++ b/jdk/src/share/classes/java/util/jar/JavaUtilJarAccessImpl.java @@ -37,6 +37,10 @@ class JavaUtilJarAccessImpl implements JavaUtilJarAccess { return jar.hasClassPathAttribute(); } + public boolean jarFileHasProfileAttribute(JarFile jar) throws IOException { + return jar.hasProfileAttribute(); + } + public CodeSource[] getCodeSources(JarFile jar, URL url) { return jar.getCodeSources(url); } diff --git a/jdk/src/share/classes/sun/misc/JavaUtilJarAccess.java b/jdk/src/share/classes/sun/misc/JavaUtilJarAccess.java index 81654824c3a..9b09cd23b1a 100644 --- a/jdk/src/share/classes/sun/misc/JavaUtilJarAccess.java +++ b/jdk/src/share/classes/sun/misc/JavaUtilJarAccess.java @@ -35,6 +35,7 @@ import java.util.jar.JarFile; public interface JavaUtilJarAccess { public boolean jarFileHasClassPathAttribute(JarFile jar) throws IOException; + public boolean jarFileHasProfileAttribute(JarFile jar) throws IOException; public CodeSource[] getCodeSources(JarFile jar, URL url); public CodeSource getCodeSource(JarFile jar, URL url, String name); public Enumeration<String> entryNames(JarFile jar, CodeSource[] cs); diff --git a/jdk/src/share/classes/sun/misc/URLClassPath.java b/jdk/src/share/classes/sun/misc/URLClassPath.java index b8036ab3864..068bd72897c 100644 --- a/jdk/src/share/classes/sun/misc/URLClassPath.java +++ b/jdk/src/share/classes/sun/misc/URLClassPath.java @@ -808,9 +808,6 @@ public class URLClassPath { /** * If the Profile attribute is present then this method checks that the runtime * supports that profile. - * - * ## Add a fast path like Class-Path to avoid reading the manifest when the attribute - * is not present. */ void checkProfileAttribute() throws IOException { Manifest man = jar.getManifest(); @@ -998,7 +995,8 @@ public class URLClassPath { parseExtensionsDependencies(); // check Profile attribute if present - if (!profileCheckSuppressedByLauncher) { + if (!profileCheckSuppressedByLauncher && + SharedSecrets.javaUtilJarAccess().jarFileHasProfileAttribute(jar)) { checkProfileAttribute(); } From 36b43451a79f1b49e937028e3ecc880567a706f4 Mon Sep 17 00:00:00 2001 From: Lance Andersen <lancea@openjdk.org> Date: Fri, 22 Feb 2013 09:29:50 -0500 Subject: [PATCH 092/180] 8008716: address typo in CallableStatement javadocs Reviewed-by: chegar --- jdk/src/share/classes/java/sql/CallableStatement.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/jdk/src/share/classes/java/sql/CallableStatement.java b/jdk/src/share/classes/java/sql/CallableStatement.java index 1200f771dad..a39af405220 100644 --- a/jdk/src/share/classes/java/sql/CallableStatement.java +++ b/jdk/src/share/classes/java/sql/CallableStatement.java @@ -2621,7 +2621,7 @@ public interface CallableStatement extends PreparedStatement { * parameter determines the Java type that must be used * in the {@code get} method to read the value of that parameter. * <p> - * This version of {@code registrOutParameter} should be + * This version of {@code registerOutParameter} should be * used when the parameter is of JDBC type {@code JDBCType.NUMERIC} * or {@code JDBCType.DECIMAL}. *<P> @@ -2649,7 +2649,7 @@ public interface CallableStatement extends PreparedStatement { /** * Registers the designated output parameter. * This version of - * the method {@code registrOutParameter} + * the method {@code registerOutParameter} * should be used for a user-defined or {@code REF} output parameter. * Examples * of user-defined types include: {@code STRUCT}, {@code DISTINCT}, @@ -2717,7 +2717,7 @@ public interface CallableStatement extends PreparedStatement { * register the OUT Parameter. * If the parameter is of JDBC type {@code JDBCType.NUMERIC} * or {@code JDBCType.DECIMAL}, the version of - * {@code registrOutParameter} that accepts a scale value + * {@code registerOutParameter} that accepts a scale value * should be used. * @exception SQLException if parameterName does not correspond to a named * parameter; if a database access error occurs or @@ -2745,7 +2745,7 @@ public interface CallableStatement extends PreparedStatement { * parameter determines the Java type that must be used * in the {@code get} method to read the value of that parameter. * <p> - * This version of {@code registrOutParameter} should be + * This version of {@code registerOutParameter} should be * used when the parameter is of JDBC type {@code JDBCType.NUMERIC} * or {@code JDBCType.DECIMAL}. *<P> @@ -2774,7 +2774,7 @@ public interface CallableStatement extends PreparedStatement { /** * Registers the designated output parameter. This version of - * the method {@code registrOutParameter} + * the method {@code registerOutParameter} * should be used for a user-named or REF output parameter. Examples * of user-named types include: STRUCT, DISTINCT, JAVA_OBJECT, and * named array types. From 3cc83d24adb47c31e1deba1ef1b8586a0d64a495 Mon Sep 17 00:00:00 2001 From: Jennifer Godinez <jgodinez@openjdk.org> Date: Fri, 22 Feb 2013 11:01:23 -0800 Subject: [PATCH 093/180] 8006110: pageDialog is showing the swing dialog with DialogTypeSelection.NATIVE Reviewed-by: bae, prr --- .../classes/sun/print/RasterPrinterJob.java | 169 ++++++++++-------- 1 file changed, 96 insertions(+), 73 deletions(-) diff --git a/jdk/src/share/classes/sun/print/RasterPrinterJob.java b/jdk/src/share/classes/sun/print/RasterPrinterJob.java index 404f66cc26f..24bece595f8 100644 --- a/jdk/src/share/classes/sun/print/RasterPrinterJob.java +++ b/jdk/src/share/classes/sun/print/RasterPrinterJob.java @@ -527,9 +527,92 @@ public abstract class RasterPrinterJob extends PrinterJob { } } + private PageFormat attributeToPageFormat(PrintService service, + PrintRequestAttributeSet attSet) { + PageFormat page = defaultPage(); + + if (service == null) { + return page; + } + + OrientationRequested orient = (OrientationRequested) + attSet.get(OrientationRequested.class); + if (orient == null) { + orient = (OrientationRequested) + service.getDefaultAttributeValue(OrientationRequested.class); + } + if (orient == OrientationRequested.REVERSE_LANDSCAPE) { + page.setOrientation(PageFormat.REVERSE_LANDSCAPE); + } else if (orient == OrientationRequested.LANDSCAPE) { + page.setOrientation(PageFormat.LANDSCAPE); + } else { + page.setOrientation(PageFormat.PORTRAIT); + } + + Media media = (Media)attSet.get(Media.class); + if (media == null) { + media = + (Media)service.getDefaultAttributeValue(Media.class); + } + if (!(media instanceof MediaSizeName)) { + media = MediaSizeName.NA_LETTER; + } + MediaSize size = + MediaSize.getMediaSizeForName((MediaSizeName)media); + if (size == null) { + size = MediaSize.NA.LETTER; + } + Paper paper = new Paper(); + float dim[] = size.getSize(1); //units == 1 to avoid FP error + double w = Math.rint((dim[0]*72.0)/Size2DSyntax.INCH); + double h = Math.rint((dim[1]*72.0)/Size2DSyntax.INCH); + paper.setSize(w, h); + MediaPrintableArea area = + (MediaPrintableArea) + attSet.get(MediaPrintableArea.class); + double ix, iw, iy, ih; + + if (area != null) { + // Should pass in same unit as updatePageAttributes + // to avoid rounding off errors. + ix = Math.rint( + area.getX(MediaPrintableArea.INCH) * DPI); + iy = Math.rint( + area.getY(MediaPrintableArea.INCH) * DPI); + iw = Math.rint( + area.getWidth(MediaPrintableArea.INCH) * DPI); + ih = Math.rint( + area.getHeight(MediaPrintableArea.INCH) * DPI); + } + else { + if (w >= 72.0 * 6.0) { + ix = 72.0; + iw = w - 2 * 72.0; + } else { + ix = w / 6.0; + iw = w * 0.75; + } + if (h >= 72.0 * 6.0) { + iy = 72.0; + ih = h - 2 * 72.0; + } else { + iy = h / 6.0; + ih = h * 0.75; + } + } + paper.setImageableArea(ix, iy, iw, ih); + page.setPaper(paper); + return page; + } protected void updatePageAttributes(PrintService service, PageFormat page) { + updateAttributesWithPageFormat(service, page, this.attributes); + } + + protected void updateAttributesWithPageFormat(PrintService service, + PageFormat page, + PrintRequestAttributeSet attributes) { if (service == null || page == null) { return; } @@ -659,6 +742,18 @@ public abstract class RasterPrinterJob extends PrinterJob { throw new HeadlessException(); } + DialogTypeSelection dlg = + (DialogTypeSelection)attributes.get(DialogTypeSelection.class); + + // Check for native, note that default dialog is COMMON. + if (dlg == DialogTypeSelection.NATIVE) { + PrintService pservice = getPrintService(); + PageFormat page = pageDialog(attributeToPageFormat(pservice, + attributes)); + updateAttributesWithPageFormat(pservice, page, attributes); + return page; + } + final GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().getDefaultConfiguration(); @@ -698,77 +793,7 @@ public abstract class RasterPrinterJob extends PrinterJob { attributes.remove(amCategory); } attributes.addAll(newas); - - PageFormat page = defaultPage(); - - OrientationRequested orient = - (OrientationRequested) - attributes.get(OrientationRequested.class); - int pfOrient = PageFormat.PORTRAIT; - if (orient != null) { - if (orient == OrientationRequested.REVERSE_LANDSCAPE) { - pfOrient = PageFormat.REVERSE_LANDSCAPE; - } else if (orient == OrientationRequested.LANDSCAPE) { - pfOrient = PageFormat.LANDSCAPE; - } - } - page.setOrientation(pfOrient); - - Media media = (Media)attributes.get(Media.class); - if (media == null) { - media = - (Media)service.getDefaultAttributeValue(Media.class); - } - if (!(media instanceof MediaSizeName)) { - media = MediaSizeName.NA_LETTER; - } - MediaSize size = - MediaSize.getMediaSizeForName((MediaSizeName)media); - if (size == null) { - size = MediaSize.NA.LETTER; - } - Paper paper = new Paper(); - float dim[] = size.getSize(1); //units == 1 to avoid FP error - double w = Math.rint((dim[0]*72.0)/Size2DSyntax.INCH); - double h = Math.rint((dim[1]*72.0)/Size2DSyntax.INCH); - paper.setSize(w, h); - MediaPrintableArea area = - (MediaPrintableArea) - attributes.get(MediaPrintableArea.class); - double ix, iw, iy, ih; - - if (area != null) { - // Should pass in same unit as updatePageAttributes - // to avoid rounding off errors. - ix = Math.rint( - area.getX(MediaPrintableArea.INCH) * DPI); - iy = Math.rint( - area.getY(MediaPrintableArea.INCH) * DPI); - iw = Math.rint( - area.getWidth(MediaPrintableArea.INCH) * DPI); - ih = Math.rint( - area.getHeight(MediaPrintableArea.INCH) * DPI); - } - else { - if (w >= 72.0 * 6.0) { - ix = 72.0; - iw = w - 2 * 72.0; - } else { - ix = w / 6.0; - iw = w * 0.75; - } - if (h >= 72.0 * 6.0) { - iy = 72.0; - ih = h - 2 * 72.0; - } else { - iy = h / 6.0; - ih = h * 0.75; - } - } - paper.setImageableArea(ix, iy, iw, ih); - page.setPaper(paper); - - return page; + return attributeToPageFormat(service, attributes); } else { return null; } @@ -795,7 +820,6 @@ public abstract class RasterPrinterJob extends PrinterJob { throw new HeadlessException(); } - DialogTypeSelection dlg = (DialogTypeSelection)attributes.get(DialogTypeSelection.class); @@ -816,7 +840,6 @@ public abstract class RasterPrinterJob extends PrinterJob { } - /* A security check has already been performed in the * java.awt.print.printerJob.getPrinterJob method. * So by the time we get here, it is OK for the current thread From d1643f183326476e986c22393b66a9bdb1137745 Mon Sep 17 00:00:00 2001 From: Jia-Hong Chen <jia-hong.chen@oracle.com> Date: Fri, 22 Feb 2013 13:20:16 -0800 Subject: [PATCH 094/180] 8005796: [parfait] Possible uninitialised variable at jdk/src/share/native/sun/java2d/loops/ByteBinary1Bit.c Reviewed-by: prr, vadim, flar --- jdk/src/share/native/sun/java2d/loops/AnyByteBinary.h | 5 ++++- jdk/src/share/native/sun/java2d/loops/ByteIndexed.h | 5 ++++- jdk/src/share/native/sun/java2d/loops/IntArgb.h | 3 ++- jdk/src/share/native/sun/java2d/loops/IntArgbBm.h | 3 ++- jdk/src/share/native/sun/java2d/loops/IntArgbPre.h | 3 ++- jdk/src/share/native/sun/java2d/loops/Ushort4444Argb.h | 3 ++- jdk/src/share/native/sun/java2d/loops/UshortIndexed.h | 5 ++++- 7 files changed, 20 insertions(+), 7 deletions(-) diff --git a/jdk/src/share/native/sun/java2d/loops/AnyByteBinary.h b/jdk/src/share/native/sun/java2d/loops/AnyByteBinary.h index abe7f230bee..3b1fa03b06a 100644 --- a/jdk/src/share/native/sun/java2d/loops/AnyByteBinary.h +++ b/jdk/src/share/native/sun/java2d/loops/AnyByteBinary.h @@ -153,7 +153,10 @@ jint PREFIX ## rgb; #define InitByteBinaryAlphaLoadData(TYPE, PREFIX, pRasInfo) \ - PREFIX ## Lut = (pRasInfo)->lutBase + do { \ + PREFIX ## Lut = (pRasInfo)->lutBase; \ + PREFIX ## rgb = 0; \ + } while (0) #define LoadAlphaFromByteBinaryFor4ByteArgb(TYPE, pRas, PREFIX, COMP_PREFIX) \ do { \ diff --git a/jdk/src/share/native/sun/java2d/loops/ByteIndexed.h b/jdk/src/share/native/sun/java2d/loops/ByteIndexed.h index 3917c238e48..215cfc0e111 100644 --- a/jdk/src/share/native/sun/java2d/loops/ByteIndexed.h +++ b/jdk/src/share/native/sun/java2d/loops/ByteIndexed.h @@ -202,7 +202,10 @@ typedef jubyte ByteIndexedBmDataType; jint PREFIX ## rgb; #define InitByteIndexedAlphaLoadData(PREFIX, pRasInfo) \ - PREFIX ## Lut = (pRasInfo)->lutBase + do { \ + PREFIX ## Lut = (pRasInfo)->lutBase; \ + PREFIX ## rgb = 0; \ + } while (0) #define LoadAlphaFromByteIndexedFor4ByteArgb(pRas, PREFIX, COMP_PREFIX) \ do { \ diff --git a/jdk/src/share/native/sun/java2d/loops/IntArgb.h b/jdk/src/share/native/sun/java2d/loops/IntArgb.h index aec63431cb1..f4ec00524cc 100644 --- a/jdk/src/share/native/sun/java2d/loops/IntArgb.h +++ b/jdk/src/share/native/sun/java2d/loops/IntArgb.h @@ -122,7 +122,8 @@ typedef jint IntArgbDataType; #define DeclareIntArgbAlphaLoadData(PREFIX) \ jint PREFIX; -#define InitIntArgbAlphaLoadData(PREFIX, pRasInfo) +#define InitIntArgbAlphaLoadData(PREFIX, pRasInfo) \ + PREFIX = 0 #define LoadAlphaFromIntArgbFor4ByteArgb(pRas, PREFIX, COMP_PREFIX) \ do { \ diff --git a/jdk/src/share/native/sun/java2d/loops/IntArgbBm.h b/jdk/src/share/native/sun/java2d/loops/IntArgbBm.h index 81d551820a8..675fba1d228 100644 --- a/jdk/src/share/native/sun/java2d/loops/IntArgbBm.h +++ b/jdk/src/share/native/sun/java2d/loops/IntArgbBm.h @@ -133,7 +133,8 @@ typedef jint IntArgbBmDataType; #define DeclareIntArgbBmAlphaLoadData(PREFIX) \ jint PREFIX; -#define InitIntArgbBmAlphaLoadData(PREFIX, pRasInfo) +#define InitIntArgbBmAlphaLoadData(PREFIX, pRasInfo) \ + PREFIX = 0 #define LoadAlphaFromIntArgbBmFor4ByteArgb(pRas, PREFIX, COMP_PREFIX) \ do { \ diff --git a/jdk/src/share/native/sun/java2d/loops/IntArgbPre.h b/jdk/src/share/native/sun/java2d/loops/IntArgbPre.h index 5ffb9dacb0b..c45013d0e00 100644 --- a/jdk/src/share/native/sun/java2d/loops/IntArgbPre.h +++ b/jdk/src/share/native/sun/java2d/loops/IntArgbPre.h @@ -153,7 +153,8 @@ typedef jint IntArgbPreDataType; #define DeclareIntArgbPreAlphaLoadData(PREFIX) \ jint PREFIX; -#define InitIntArgbPreAlphaLoadData(PREFIX, pRasInfo) +#define InitIntArgbPreAlphaLoadData(PREFIX, pRasInfo) \ + PREFIX = 0 #define LoadAlphaFromIntArgbPreFor4ByteArgb(pRas, PREFIX, COMP_PREFIX) \ do { \ diff --git a/jdk/src/share/native/sun/java2d/loops/Ushort4444Argb.h b/jdk/src/share/native/sun/java2d/loops/Ushort4444Argb.h index 348e03b7df4..aa50d8b0ff3 100644 --- a/jdk/src/share/native/sun/java2d/loops/Ushort4444Argb.h +++ b/jdk/src/share/native/sun/java2d/loops/Ushort4444Argb.h @@ -120,7 +120,8 @@ typedef jushort Ushort4444ArgbDataType; #define DeclareUshort4444ArgbAlphaLoadData(PREFIX) \ jint PREFIX; -#define InitUshort4444ArgbAlphaLoadData(PREFIX, pRasInfo) +#define InitUshort4444ArgbAlphaLoadData(PREFIX, pRasInfo) \ + PREFIX = 0 #define LoadAlphaFromUshort4444ArgbFor4ByteArgb(pRas, PREFIX, COMP_PREFIX) \ do { \ diff --git a/jdk/src/share/native/sun/java2d/loops/UshortIndexed.h b/jdk/src/share/native/sun/java2d/loops/UshortIndexed.h index 7786bda3829..6a4b5b13e5d 100644 --- a/jdk/src/share/native/sun/java2d/loops/UshortIndexed.h +++ b/jdk/src/share/native/sun/java2d/loops/UshortIndexed.h @@ -170,7 +170,10 @@ typedef jushort UshortIndexedBmDataType; jint PREFIX ## rgb; #define InitUshortIndexedAlphaLoadData(PREFIX, pRasInfo) \ - PREFIX ## Lut = (pRasInfo)->lutBase + do { \ + PREFIX ## Lut = (pRasInfo)->lutBase; \ + PREFIX ## rgb = 0; \ + } while (0) #define LoadAlphaFromUshortIndexedFor4ByteArgb(pRas, PREFIX, COMP_PREFIX) \ do { \ From b7511e7609a4f33e759bbc8352d099ce883811ba Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan <sundar@openjdk.org> Date: Wed, 27 Feb 2013 17:22:44 +0530 Subject: [PATCH 095/180] 8009115: jtreg tests under jdk/test/javax/script should use nashorn as script engine Reviewed-by: alanb --- jdk/test/javax/script/CauseExceptionTest.java | 6 +++--- ...oExceptionTest.java => ExceptionTest.java} | 4 ++-- jdk/test/javax/script/GetInterfaceTest.java | 5 +++-- jdk/test/javax/script/Helper.java | 4 ++-- .../javax/script/StringWriterPrintTest.java | 4 ++-- jdk/test/javax/script/Test3.js | 8 +++++--- jdk/test/javax/script/Test5.java | 20 +++++++++++++------ jdk/test/javax/script/Test5.js | 9 ++++----- jdk/test/javax/script/Test6.java | 20 +++++++++++++++---- jdk/test/javax/script/Test7.js | 7 ++++++- .../script/UnescapedBracketRegExTest.java | 6 +++--- jdk/test/javax/script/VersionTest.java | 19 ++++++++++++------ 12 files changed, 73 insertions(+), 39 deletions(-) rename jdk/test/javax/script/{RhinoExceptionTest.java => ExceptionTest.java} (96%) diff --git a/jdk/test/javax/script/CauseExceptionTest.java b/jdk/test/javax/script/CauseExceptionTest.java index f1ff708bc1e..41fa5e4b493 100644 --- a/jdk/test/javax/script/CauseExceptionTest.java +++ b/jdk/test/javax/script/CauseExceptionTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 6869617 - * @summary RhinoScriptEngine bug : ScriptException cause not set (with fix) + * @summary ScriptEngine bug : ScriptException cause not set (with fix) */ import javax.script.*; @@ -33,12 +33,12 @@ import java.io.*; public class CauseExceptionTest { public static void main(String[] args) throws ScriptException, NoSuchMethodException { ScriptEngineManager sem = new ScriptEngineManager(); - ScriptEngine engine = sem.getEngineByName("js"); + ScriptEngine engine = sem.getEngineByName("nashorn"); if (engine == null) { System.out.println("Warning: No js engine found; test vacuously passes."); return; } - engine.eval("function hello_world() { println('hello world'); throw 'out of here'; } "); + engine.eval("function hello_world() { print('hello world'); throw 'out of here'; } "); Invocable invocable = (Invocable) engine; try { invocable.invokeFunction("hello_world", (Object[])null); diff --git a/jdk/test/javax/script/RhinoExceptionTest.java b/jdk/test/javax/script/ExceptionTest.java similarity index 96% rename from jdk/test/javax/script/RhinoExceptionTest.java rename to jdk/test/javax/script/ExceptionTest.java index 22d5f0fd6fb..9ea2d4e3f7a 100644 --- a/jdk/test/javax/script/RhinoExceptionTest.java +++ b/jdk/test/javax/script/ExceptionTest.java @@ -24,14 +24,14 @@ /* * @test * @bug 6474943 6705893 - * @summary Test that Rhino exception messages are + * @summary Test that script engine exception messages are * available from ScriptException. */ import java.io.*; import javax.script.*; -public class RhinoExceptionTest { +public class ExceptionTest { private static final String ERROR_MSG = "error from JavaScript"; public static void main(String[] args) throws Exception { diff --git a/jdk/test/javax/script/GetInterfaceTest.java b/jdk/test/javax/script/GetInterfaceTest.java index d780a6db08b..dffc74ea3b4 100644 --- a/jdk/test/javax/script/GetInterfaceTest.java +++ b/jdk/test/javax/script/GetInterfaceTest.java @@ -22,6 +22,7 @@ */ /* + * @run ignore * @test * @bug 6960211 * @summary JavaScript engine allows creation of interface although methods not available. @@ -32,10 +33,10 @@ import javax.script.*; public class GetInterfaceTest { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine engine = manager.getEngineByName("js"); + ScriptEngine engine = manager.getEngineByName("nashorn"); if (engine == null) { - System.out.println("Warning: No engine engine found; test vacuously passes."); + System.out.println("Warning: No js engine engine found; test vacuously passes."); return; } diff --git a/jdk/test/javax/script/Helper.java b/jdk/test/javax/script/Helper.java index 73617bf5e93..fc132a457d1 100644 --- a/jdk/test/javax/script/Helper.java +++ b/jdk/test/javax/script/Helper.java @@ -24,13 +24,13 @@ import javax.script.*; /** * Helper class to consolidate testing requirements for a js engine. - * A js engine is required as part of Sun's product JDK. + * A js engine is required as part of Oracle's product JDK. */ public class Helper { private Helper() {}; // Don't instantiate public static ScriptEngine getJsEngine(ScriptEngineManager m) { - ScriptEngine e = m.getEngineByName("js"); + ScriptEngine e = m.getEngineByName("nashorn"); if (e == null && System.getProperty("java.runtime.name").startsWith("Java(TM)")) { // A js engine is requied for Sun's product JDK diff --git a/jdk/test/javax/script/StringWriterPrintTest.java b/jdk/test/javax/script/StringWriterPrintTest.java index 42345791878..7a75b6f0396 100644 --- a/jdk/test/javax/script/StringWriterPrintTest.java +++ b/jdk/test/javax/script/StringWriterPrintTest.java @@ -33,9 +33,9 @@ import java.io.*; public class StringWriterPrintTest { public static void main(String[] args) throws ScriptException { ScriptEngineManager sem = new ScriptEngineManager(); - ScriptEngine engine = sem.getEngineByName("js"); + ScriptEngine engine = sem.getEngineByName("nashorn"); if (engine == null) { - System.out.println("Warning: No js engine found; test vacuously passes."); + System.out.println("Warning: No nashorn engine found; test vacuously passes."); return; } StringWriter sw = new StringWriter(); diff --git a/jdk/test/javax/script/Test3.js b/jdk/test/javax/script/Test3.js index 4cdb8286843..5f7aba45e93 100644 --- a/jdk/test/javax/script/Test3.js +++ b/jdk/test/javax/script/Test3.js @@ -1,22 +1,24 @@ +var ScriptContext = javax.script.ScriptContext; + if (key == undefined || key != 'engine value') { throw "unexpected engine scope value"; } // pre-defined context variable refers to current ScriptContext -if (context.getAttribute('key', context.GLOBAL_SCOPE) != 'global value') { +if (context.getAttribute('key', ScriptContext.GLOBAL_SCOPE) != 'global value') { throw "unexpected global scope value"; } // change the engine scope value key = 'new engine value'; -if (context.getAttribute('key', context.GLOBAL_SCOPE) != 'global value') { +if (context.getAttribute('key', ScriptContext.GLOBAL_SCOPE) != 'global value') { throw "global scope should not change here"; } // delete engine scope value delete key; -if (key == undefined && key != 'xglobal value') { +if (key == undefined && key != 'global value') { throw 'global scope should be visible after engine scope removal'; } diff --git a/jdk/test/javax/script/Test5.java b/jdk/test/javax/script/Test5.java index 107bd148b63..acdd3a47448 100644 --- a/jdk/test/javax/script/Test5.java +++ b/jdk/test/javax/script/Test5.java @@ -48,16 +48,24 @@ public class Test5 { System.out.println("engine scope only"); e.put("count", new Integer(1)); - Reader reader = new FileReader( - new File(System.getProperty("test.src", "."), "Test5.js")); - engine.eval(reader,ctxt); + try (Reader reader = new FileReader( + new File(System.getProperty("test.src", "."), "Test5.js"))) { + engine.eval(reader,ctxt); + } + System.out.println("both scopes"); ctxt.setBindings(g, ScriptContext.GLOBAL_SCOPE); e.put("count", new Integer(2)); - engine.eval(reader,ctxt); + try (Reader reader = new FileReader( + new File(System.getProperty("test.src", "."), "Test5.js"))) { + engine.eval(reader,ctxt); + } System.out.println("only global"); e.put("count", new Integer(3)); - ctxt.setAttribute("key", null, ScriptContext.ENGINE_SCOPE); - engine.eval(reader,ctxt); + ctxt.removeAttribute("key", ScriptContext.ENGINE_SCOPE); + try (Reader reader = new FileReader( + new File(System.getProperty("test.src", "."), "Test5.js"))) { + engine.eval(reader,ctxt); + } } } diff --git a/jdk/test/javax/script/Test5.js b/jdk/test/javax/script/Test5.js index c607cbc8604..708b482d00c 100644 --- a/jdk/test/javax/script/Test5.js +++ b/jdk/test/javax/script/Test5.js @@ -1,6 +1,5 @@ -var key; -var count; +var ScriptContext = javax.script.ScriptContext; print(count); switch (count) { @@ -9,7 +8,7 @@ switch (count) { if (key != 'value in engine') { throw "unexpected engine scope value"; } - if (context.getAttribute("key", context.GLOBAL_SCOPE ) != null) { + if (context.getAttribute("key", ScriptContext.GLOBAL_SCOPE ) != null) { throw "unexpected global scope value"; } break; @@ -19,7 +18,7 @@ switch (count) { if (key != 'value in engine') { throw "unexpected engine scope value"; } - if (context.getAttribute("key", context.GLOBAL_SCOPE ) != + if (context.getAttribute("key", ScriptContext.GLOBAL_SCOPE ) != "value in global") { throw "unexpected global scope value"; } @@ -30,7 +29,7 @@ switch (count) { if (key != 'value in global') { throw "unexpected global scope value"; } - if (context.getAttribute("key", context.GLOBAL_SCOPE ) != + if (context.getAttribute("key", ScriptContext.GLOBAL_SCOPE ) != "value in global") { throw "unexpected global scope value"; } diff --git a/jdk/test/javax/script/Test6.java b/jdk/test/javax/script/Test6.java index 82758879fdb..5582b0a9025 100644 --- a/jdk/test/javax/script/Test6.java +++ b/jdk/test/javax/script/Test6.java @@ -40,11 +40,23 @@ public class Test6 { System.out.println("Warning: No js engine found; test vacuously passes."); return; } - Reader reader = new FileReader( - new File(System.getProperty("test.src", "."), "Test6.js")); - engine.eval(reader); + + try (Reader reader = new FileReader( + new File(System.getProperty("test.src", "."), "Test6.js"))) { + engine.eval(reader); + } Object res = engine.get("res"); - CompiledScript scr = ((Compilable)engine).compile(reader); + + CompiledScript scr = null; + try (Reader reader = new FileReader( + new File(System.getProperty("test.src", "."), "Test6.js"))) { + scr = ((Compilable)engine).compile(reader); + } + + if (scr == null) { + throw new RuntimeException("compilation failed!"); + } + scr.eval(); Object res1 = engine.get("res"); if (! res.equals(res1)) { diff --git a/jdk/test/javax/script/Test7.js b/jdk/test/javax/script/Test7.js index b1ec2a8fd9f..d79db96067d 100644 --- a/jdk/test/javax/script/Test7.js +++ b/jdk/test/javax/script/Test7.js @@ -1,9 +1,14 @@ //this is the first line of Test7.js var filename; +try { + load("nashorn:mozilla_compat.js"); +} catch (e) { + //ignored +} importPackage(java.io); importPackage(java); var f = new File(filename); var r = new BufferedReader(new InputStreamReader(new FileInputStream(f))); -var firstLine = r.readLine() + ''; +var firstLine = r.readLine(); print(firstLine); diff --git a/jdk/test/javax/script/UnescapedBracketRegExTest.java b/jdk/test/javax/script/UnescapedBracketRegExTest.java index f2a807065f7..472ae107ed9 100644 --- a/jdk/test/javax/script/UnescapedBracketRegExTest.java +++ b/jdk/test/javax/script/UnescapedBracketRegExTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 7012701 - * @summary 7012701 Add a test to check that Rhino's RegExp parser accepts unescaped '[' + * @summary 7012701 Add a test to check that RegExp parser accepts unescaped '[' */ import javax.script.*; @@ -33,9 +33,9 @@ import java.io.*; public class UnescapedBracketRegExTest { public static void main(String[] args) throws ScriptException { ScriptEngineManager sem = new ScriptEngineManager(); - ScriptEngine engine = sem.getEngineByName("js"); + ScriptEngine engine = sem.getEngineByName("nashorn"); if (engine == null) { - System.out.println("Warning: No js engine found; test vacuously passes."); + System.out.println("Warning: No nashorn engine found; test vacuously passes."); return; } // the following throws exception diff --git a/jdk/test/javax/script/VersionTest.java b/jdk/test/javax/script/VersionTest.java index 374f43be51c..87fa8bcfa51 100644 --- a/jdk/test/javax/script/VersionTest.java +++ b/jdk/test/javax/script/VersionTest.java @@ -31,9 +31,7 @@ import javax.script.*; import java.io.*; public class VersionTest { - - private static final String JS_LANG_VERSION = "1.8"; - private static final String JS_ENGINE_VERSION = "1.7 release 3 PRERELEASE"; + private static final String JS_LANG_VERSION = "ECMA - 262 Edition 5.1"; public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); @@ -48,9 +46,18 @@ public class VersionTest { JS_LANG_VERSION); } String engineVersion = jsengine.getFactory().getEngineVersion(); - if (! engineVersion.equals(JS_ENGINE_VERSION)) { - throw new RuntimeException("Expected Rhino version is " + - JS_ENGINE_VERSION); + String expectedVersion = getNashornVersion(); + if (! engineVersion.equals(expectedVersion)) { + throw new RuntimeException("Expected version is " + expectedVersion); + } + } + + private static String getNashornVersion() { + try { + Class versionClass = Class.forName("jdk.nashorn.internal.runtime.Version"); + return (String) versionClass.getMethod("version").invoke(null); + } catch (Exception e) { + return "Version Unknown!"; } } } From f99a5d722e62e915351f8d753a3ebf31352b1cdf Mon Sep 17 00:00:00 2001 From: Alan Bateman <alanb@openjdk.org> Date: Wed, 27 Feb 2013 14:24:45 +0000 Subject: [PATCH 096/180] 8008793: SecurityManager.checkXXX behavior not specified for methods that check AWTPermission and AWT not present Reviewed-by: hawtin, mullan, dsamersoff, mchung --- .../classes/java/lang/SecurityManager.java | 28 ++++++++- .../sun/security/util/SecurityConstants.java | 63 +++++-------------- jdk/test/java/lang/SecurityManager/NoAWT.java | 33 +++++++++- 3 files changed, 71 insertions(+), 53 deletions(-) diff --git a/jdk/src/share/classes/java/lang/SecurityManager.java b/jdk/src/share/classes/java/lang/SecurityManager.java index 80181cd4e80..31664dc6cb2 100644 --- a/jdk/src/share/classes/java/lang/SecurityManager.java +++ b/jdk/src/share/classes/java/lang/SecurityManager.java @@ -1320,6 +1320,9 @@ class SecurityManager { * <code>AWTPermission("showWindowWithoutWarningBanner")</code> permission, * and returns <code>true</code> if a SecurityException is not thrown, * otherwise it returns <code>false</code>. + * In the case of subset Profiles of Java SE that do not include the + * {@code java.awt} package, {@code checkPermission} is instead called + * to check the permission {@code java.security.AllPermission}. * <p> * If you override this method, then you should make a call to * <code>super.checkTopLevelWindow</code> @@ -1340,8 +1343,12 @@ class SecurityManager { if (window == null) { throw new NullPointerException("window can't be null"); } + Permission perm = SecurityConstants.AWT.TOPLEVEL_WINDOW_PERMISSION; + if (perm == null) { + perm = SecurityConstants.ALL_PERMISSION; + } try { - checkPermission(SecurityConstants.AWT.TOPLEVEL_WINDOW_PERMISSION); + checkPermission(perm); return true; } catch (SecurityException se) { // just return false @@ -1379,6 +1386,9 @@ class SecurityManager { * This method calls <code>checkPermission</code> with the * <code>AWTPermission("accessClipboard")</code> * permission. + * In the case of subset Profiles of Java SE that do not include the + * {@code java.awt} package, {@code checkPermission} is instead called + * to check the permission {@code java.security.AllPermission}. * <p> * If you override this method, then you should make a call to * <code>super.checkSystemClipboardAccess</code> @@ -1391,7 +1401,11 @@ class SecurityManager { * @see #checkPermission(java.security.Permission) checkPermission */ public void checkSystemClipboardAccess() { - checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION); + Permission perm = SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION; + if (perm == null) { + perm = SecurityConstants.ALL_PERMISSION; + } + checkPermission(perm); } /** @@ -1400,6 +1414,10 @@ class SecurityManager { * <p> * This method calls <code>checkPermission</code> with the * <code>AWTPermission("accessEventQueue")</code> permission. + * In the case of subset Profiles of Java SE that do not include the + * {@code java.awt} package, {@code checkPermission} is instead called + * to check the permission {@code java.security.AllPermission}. + * * <p> * If you override this method, then you should make a call to * <code>super.checkAwtEventQueueAccess</code> @@ -1412,7 +1430,11 @@ class SecurityManager { * @see #checkPermission(java.security.Permission) checkPermission */ public void checkAwtEventQueueAccess() { - checkPermission(SecurityConstants.AWT.CHECK_AWT_EVENTQUEUE_PERMISSION); + Permission perm = SecurityConstants.AWT.CHECK_AWT_EVENTQUEUE_PERMISSION; + if (perm == null) { + perm = SecurityConstants.ALL_PERMISSION; + } + checkPermission(perm); } /* diff --git a/jdk/src/share/classes/sun/security/util/SecurityConstants.java b/jdk/src/share/classes/sun/security/util/SecurityConstants.java index c9d321f7c15..2b985ad0f65 100644 --- a/jdk/src/share/classes/sun/security/util/SecurityConstants.java +++ b/jdk/src/share/classes/sun/security/util/SecurityConstants.java @@ -70,31 +70,6 @@ public final class SecurityConstants { // sun.security.provider.PolicyFile public static final AllPermission ALL_PERMISSION = new AllPermission(); - /** - * Permission type used when AWT is not present. - */ - private static class FakeAWTPermission extends BasicPermission { - private static final long serialVersionUID = -1L; - public FakeAWTPermission(String name) { - super(name); - } - public String toString() { - return "(\"java.awt.AWTPermission\" \"" + getName() + "\")"; - } - } - - /** - * Permission factory used when AWT is not present. - */ - private static class FakeAWTPermissionFactory - implements PermissionFactory<FakeAWTPermission> - { - @Override - public FakeAWTPermission newPermission(String name) { - return new FakeAWTPermission(name); - } - } - /** * AWT Permissions used in the JDK. */ @@ -107,37 +82,29 @@ public final class SecurityConstants { private static final String AWTFactory = "sun.awt.AWTPermissionFactory"; /** - * The PermissionFactory to create AWT permissions (or fake permissions - * if AWT is not present). + * The PermissionFactory to create AWT permissions (or null if AWT is + * not present) */ private static final PermissionFactory<?> factory = permissionFactory(); private static PermissionFactory<?> permissionFactory() { - Class<?> c = AccessController - .doPrivileged(new PrivilegedAction<Class<?>>() { - public Class<?> run() { - try { - return Class.forName(AWTFactory, true, null); - } catch (ClassNotFoundException e) { - // not available - return null; - } - }}); - if (c != null) { - // AWT present - try { - return (PermissionFactory<?>)c.newInstance(); - } catch (ReflectiveOperationException x) { - throw new InternalError(x.getMessage(), x); - } - } else { - // AWT not present - return new FakeAWTPermissionFactory(); + Class<?> c; + try { + c = Class.forName(AWTFactory, false, AWT.class.getClassLoader()); + } catch (ClassNotFoundException e) { + // not available + return null; + } + // AWT present + try { + return (PermissionFactory<?>)c.newInstance(); + } catch (ReflectiveOperationException x) { + throw new InternalError(x); } } private static Permission newAWTPermission(String name) { - return factory.newPermission(name); + return (factory == null) ? null : factory.newPermission(name); } // java.lang.SecurityManager diff --git a/jdk/test/java/lang/SecurityManager/NoAWT.java b/jdk/test/java/lang/SecurityManager/NoAWT.java index 3224af46dd4..d55e05c1027 100644 --- a/jdk/test/java/lang/SecurityManager/NoAWT.java +++ b/jdk/test/java/lang/SecurityManager/NoAWT.java @@ -22,14 +22,43 @@ */ /* @test - * @bug 8004502 + * @bug 8004502 8008793 * @summary Sanity check that SecurityManager methods that check AWTPermission * behave as expected when AWT is not present */ +import java.security.AllPermission; +import java.security.Permission; + public class NoAWT { + + static class MySecurityManager extends SecurityManager { + Class<?> expectedClass; + + void setExpectedPermissionClass(Class<?> c) { + expectedClass = c; + } + + @Override + public void checkPermission(Permission perm) { + if (perm.getClass() != expectedClass) + throw new RuntimeException("Got: " + perm.getClass() + ", expected: " + expectedClass); + super.checkPermission(perm); + } + } + public static void main(String[] args) { - SecurityManager sm = new SecurityManager(); + Class<?> awtPermissionClass = null; + try { + awtPermissionClass = Class.forName("java.awt.AWTPermission"); + } catch (ClassNotFoundException ignore) { } + + MySecurityManager sm = new MySecurityManager(); + if (awtPermissionClass != null) { + sm.setExpectedPermissionClass(awtPermissionClass); + } else { + sm.setExpectedPermissionClass(AllPermission.class); + } try { sm.checkAwtEventQueueAccess(); From 6715b64842a40ef4b5f63da0778292c0def0205a Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan <sundar@openjdk.org> Date: Wed, 27 Feb 2013 20:34:12 +0530 Subject: [PATCH 097/180] 8009140: jtreg tests under sun/tools/jrunscript should use nashorn engine Reviewed-by: alanb --- .../sun/tools/jrunscript/CheckEngine.java | 2 +- .../sun/tools/jrunscript/jrunscript-DTest.sh | 2 +- .../tools/jrunscript/jrunscript-argsTest.sh | 2 +- .../sun/tools/jrunscript/jrunscript-cpTest.sh | 4 ++-- .../sun/tools/jrunscript/jrunscript-eTest.sh | 13 +---------- .../sun/tools/jrunscript/jrunscript-fTest.sh | 13 +---------- .../sun/tools/jrunscript/jrunscriptTest.sh | 22 ++----------------- jdk/test/sun/tools/jrunscript/repl.out | 14 ++++++------ 8 files changed, 16 insertions(+), 56 deletions(-) diff --git a/jdk/test/sun/tools/jrunscript/CheckEngine.java b/jdk/test/sun/tools/jrunscript/CheckEngine.java index 023e5e0920a..752411da2ac 100644 --- a/jdk/test/sun/tools/jrunscript/CheckEngine.java +++ b/jdk/test/sun/tools/jrunscript/CheckEngine.java @@ -33,7 +33,7 @@ public class CheckEngine { public static void main(String... args) { int exitCode = 0; ScriptEngine engine = - (new ScriptEngineManager()).getEngineByName("js"); + (new ScriptEngineManager()).getEngineByName("nashorn"); if (engine == null && !(System.getProperty("java.runtime.name").startsWith("Java(TM)"))) { diff --git a/jdk/test/sun/tools/jrunscript/jrunscript-DTest.sh b/jdk/test/sun/tools/jrunscript/jrunscript-DTest.sh index 4d9e792c43f..b2102ef6a62 100644 --- a/jdk/test/sun/tools/jrunscript/jrunscript-DTest.sh +++ b/jdk/test/sun/tools/jrunscript/jrunscript-DTest.sh @@ -43,7 +43,7 @@ fi # to script as java.lang.System property. sysProps is # jrunscript shell built-in variable for System properties. -${JRUNSCRIPT} -Djrunscript.foo=bar <<EOF +${JRUNSCRIPT} -l nashorn -Djrunscript.foo=bar <<EOF if (sysProps["jrunscript.foo"] == "bar") { println("Passed"); exit(0); } // unexpected value println("Unexpected System property value"); diff --git a/jdk/test/sun/tools/jrunscript/jrunscript-argsTest.sh b/jdk/test/sun/tools/jrunscript/jrunscript-argsTest.sh index 55f3147039a..b104e965ddf 100644 --- a/jdk/test/sun/tools/jrunscript/jrunscript-argsTest.sh +++ b/jdk/test/sun/tools/jrunscript/jrunscript-argsTest.sh @@ -41,7 +41,7 @@ fi # we check whether "excess" args are passed as script arguments -${JRUNSCRIPT} -J-Djava.awt.headless=true -f - hello world <<EOF +${JRUNSCRIPT} -l nashorn -J-Djava.awt.headless=true -f - hello world <<EOF if (typeof(arguments) == 'undefined') { println("arguments expected"); exit(1); } diff --git a/jdk/test/sun/tools/jrunscript/jrunscript-cpTest.sh b/jdk/test/sun/tools/jrunscript/jrunscript-cpTest.sh index 05019636521..4b989ef2de1 100644 --- a/jdk/test/sun/tools/jrunscript/jrunscript-cpTest.sh +++ b/jdk/test/sun/tools/jrunscript/jrunscript-cpTest.sh @@ -46,7 +46,7 @@ ${JAVAC} ${TESTSRC}/Hello.java -d . # work with jrunscript. Script should be able to # access Java class "Hello". -${JRUNSCRIPT} -cp . <<EOF +${JRUNSCRIPT} -l nashorn -cp . <<EOF var v; try { v = new Packages.Hello(); } catch (e) { println(e); exit(1) } if (v.string != 'hello') { println("Unexpected property value"); exit(1); } @@ -58,7 +58,7 @@ fi # -classpath and -cp are synonyms -${JRUNSCRIPT} -classpath . <<EOF +${JRUNSCRIPT} -l nashorn -classpath . <<EOF var v; try { v = new Packages.Hello(); } catch (e) { println(e); exit(1) } if (v.string != 'hello') { println("unexpected property value"); exit(1); } diff --git a/jdk/test/sun/tools/jrunscript/jrunscript-eTest.sh b/jdk/test/sun/tools/jrunscript/jrunscript-eTest.sh index e9867b84ffa..97c62a261f9 100644 --- a/jdk/test/sun/tools/jrunscript/jrunscript-eTest.sh +++ b/jdk/test/sun/tools/jrunscript/jrunscript-eTest.sh @@ -39,21 +39,10 @@ if [ $? -eq 2 ]; then exit 0 fi -rm -f jrunscript-eTest.out 2>/dev/null -${JRUNSCRIPT} -J-Djava.awt.headless=true -e "println('hello')" > jrunscript-eTest.out 2>&1 - -$golden_diff jrunscript-eTest.out ${TESTSRC}/dash-e.out -if [ $? != 0 ] -then - echo "Output of jrunscript -e differ from expected output. Failed." - rm -f jrunscript-eTest.out 2>/dev/null - exit 1 -fi - # -e option with JavaScript explicitly choosen as language rm -f jrunscript-eTest.out 2>/dev/null -${JRUNSCRIPT} -J-Djava.awt.headless=true -l js -e "println('hello')" > jrunscript-eTest.out 2>&1 +${JRUNSCRIPT} -J-Djava.awt.headless=true -l nashorn -e "println('hello')" > jrunscript-eTest.out 2>&1 $golden_diff jrunscript-eTest.out ${TESTSRC}/dash-e.out if [ $? != 0 ] diff --git a/jdk/test/sun/tools/jrunscript/jrunscript-fTest.sh b/jdk/test/sun/tools/jrunscript/jrunscript-fTest.sh index 170a7dd0d11..8c402a316ea 100644 --- a/jdk/test/sun/tools/jrunscript/jrunscript-fTest.sh +++ b/jdk/test/sun/tools/jrunscript/jrunscript-fTest.sh @@ -39,22 +39,11 @@ if [ $? -eq 2 ]; then exit 0 fi -rm -f jrunscript-fTest.out 2>/dev/null -${JRUNSCRIPT} -J-Djava.awt.headless=true -f ${TESTSRC}/hello.js > jrunscript-fTest.out 2>&1 - -$golden_diff jrunscript-fTest.out ${TESTSRC}/dash-f.out -if [ $? != 0 ] -then - echo "Output of jrunscript -f differ from expected output. Failed." - rm -f jrunscript-fTest.out 2>/dev/null - exit 1 -fi - # -f option used with JavaScript as language chosen explicitly # with -l option rm -f jrunscript-fTest.out 2>/dev/null -${JRUNSCRIPT} -J-Djava.awt.headless=true -l js -f ${TESTSRC}/hello.js > jrunscript-fTest.out 2>&1 +${JRUNSCRIPT} -J-Djava.awt.headless=true -l nashorn -f ${TESTSRC}/hello.js > jrunscript-fTest.out 2>&1 $golden_diff jrunscript-fTest.out ${TESTSRC}/dash-f.out if [ $? != 0 ] diff --git a/jdk/test/sun/tools/jrunscript/jrunscriptTest.sh b/jdk/test/sun/tools/jrunscript/jrunscriptTest.sh index 0a3237536db..921524be9e0 100644 --- a/jdk/test/sun/tools/jrunscript/jrunscriptTest.sh +++ b/jdk/test/sun/tools/jrunscript/jrunscriptTest.sh @@ -40,7 +40,7 @@ if [ $? -eq 2 ]; then fi rm -f jrunscriptTest.out 2>/dev/null -${JRUNSCRIPT} -J-Djava.awt.headless=true > jrunscriptTest.out 2>&1 <<EOF +${JRUNSCRIPT} -J-Djava.awt.headless=true -l nashorn > jrunscriptTest.out 2>&1 <<EOF v = 2 + 5; v *= 5; v = v + " is the value"; @@ -52,25 +52,7 @@ EOF $golden_diff jrunscriptTest.out ${TESTSRC}/repl.out if [ $? != 0 ] then - echo "Output of jrunscript session differ from expected output. Failed." - rm -f jrunscriptTest.out 2>/dev/null - exit 1 -fi - -rm -f jrunscriptTest.out 2>/dev/null -${JRUNSCRIPT} -J-Djava.awt.headless=true -l js > jrunscriptTest.out 2>&1 <<EOF -v = 2 + 5; -v *= 5; -v = v + " is the value"; -if (v != 0) { println('yes v != 0'); } -java.lang.System.out.println('hello world from script'); -new java.lang.Runnable() { run: function() { println('I am runnable'); }}.run(); -EOF - -$golden_diff jrunscriptTest.out ${TESTSRC}/repl.out -if [ $? != 0 ] -then - echo "Output of jrunscript -l js differ from expected output. Failed." + echo "Output of jrunscript -l nashorn differ from expected output. Failed." rm -f jrunscriptTest.out 2>/dev/null exit 1 fi diff --git a/jdk/test/sun/tools/jrunscript/repl.out b/jdk/test/sun/tools/jrunscript/repl.out index 13b390fc29b..156b8263fce 100644 --- a/jdk/test/sun/tools/jrunscript/repl.out +++ b/jdk/test/sun/tools/jrunscript/repl.out @@ -1,7 +1,7 @@ -js> 7.0 -js> 35.0 -js> 35 is the value -js> yes v != 0 -js> hello world from script -js> I am runnable -js> \ No newline at end of file +nashorn> 7 +nashorn> 35.0 +nashorn> 35 is the value +nashorn> yes v != 0 +nashorn> hello world from script +nashorn> I am runnable +nashorn> \ No newline at end of file From 78a060dbde5465d75377756320f7326fe45512ad Mon Sep 17 00:00:00 2001 From: Vladimir Danushevsky <vladidan@openjdk.org> Date: Fri, 22 Feb 2013 17:12:35 -0500 Subject: [PATCH 098/180] 8005545: Add System property to identify ARCH specific details such as ARM hard-float binaries Adding sun.os.abi Java Property support Reviewed-by: bobv, alanb, dholmes --- jdk/makefiles/Images.gmk | 1 + jdk/src/share/native/java/lang/System.c | 4 ++++ jdk/src/share/native/java/lang/java_props.h | 4 ++++ jdk/src/solaris/native/java/lang/java_props_md.c | 5 +++++ 4 files changed, 14 insertions(+) diff --git a/jdk/makefiles/Images.gmk b/jdk/makefiles/Images.gmk index 28322675559..029a488f0f0 100644 --- a/jdk/makefiles/Images.gmk +++ b/jdk/makefiles/Images.gmk @@ -602,6 +602,7 @@ define create-info-file $(call info-file-item, "OS_NAME", "$(REQUIRED_OS_NAME)") $(call info-file-item, "OS_VERSION", "$(REQUIRED_OS_VERSION)") $(call info-file-item, "OS_ARCH", "$(OPENJDK_TARGET_CPU_LEGACY)") + if [ -n "$(JDK_ARCH_ABI_PROP_NAME)" ]; then $(call info-file-item, "SUN_ARCH_ABI", "$(JDK_ARCH_ABI_PROP_NAME)"); fi $(call info-file-item, "SOURCE", "$(ALL_SOURCE_TIPS)") endef diff --git a/jdk/src/share/native/java/lang/System.c b/jdk/src/share/native/java/lang/System.c index 8efd95e09b7..faef4b09314 100644 --- a/jdk/src/share/native/java/lang/System.c +++ b/jdk/src/share/native/java/lang/System.c @@ -212,6 +212,10 @@ Java_java_lang_System_initProperties(JNIEnv *env, jclass cla, jobject props) PUTPROP(props, "os.version", sprops->os_version); PUTPROP(props, "os.arch", sprops->os_arch); +#ifdef JDK_ARCH_ABI_PROP_NAME + PUTPROP(props, "sun.arch.abi", sprops->sun_arch_abi); +#endif + /* file system properties */ PUTPROP(props, "file.separator", sprops->file_separator); PUTPROP(props, "path.separator", sprops->path_separator); diff --git a/jdk/src/share/native/java/lang/java_props.h b/jdk/src/share/native/java/lang/java_props.h index e6c11c262c0..86a69d7a124 100644 --- a/jdk/src/share/native/java/lang/java_props.h +++ b/jdk/src/share/native/java/lang/java_props.h @@ -41,6 +41,10 @@ typedef struct { char *os_version; char *os_arch; +#ifdef JDK_ARCH_ABI_PROP_NAME + char *sun_arch_abi; +#endif + nchar *tmp_dir; nchar *font_dir; nchar *user_dir; diff --git a/jdk/src/solaris/native/java/lang/java_props_md.c b/jdk/src/solaris/native/java/lang/java_props_md.c index c7d3ba6eff5..c8c18982585 100644 --- a/jdk/src/solaris/native/java/lang/java_props_md.c +++ b/jdk/src/solaris/native/java/lang/java_props_md.c @@ -514,6 +514,11 @@ GetJavaProperties(JNIEnv *env) } } + /* ABI property (optional) */ +#ifdef JDK_ARCH_ABI_PROP_NAME + sprops.sun_arch_abi = JDK_ARCH_ABI_PROP_NAME; +#endif + /* Determine the language, country, variant, and encoding from the host, * and store these in the user.language, user.country, user.variant and * file.encoding system properties. */ From 797ef551291c76ba23ee556680b127aa71e166d1 Mon Sep 17 00:00:00 2001 From: Joe Darcy <darcy@openjdk.org> Date: Sat, 23 Feb 2013 13:32:32 -0800 Subject: [PATCH 099/180] 6556996: (ann spec) SuppressWarnings strings should be documented Reviewed-by: mduigou, chegar, abuckley --- jdk/src/share/classes/java/lang/Deprecated.java | 3 ++- jdk/src/share/classes/java/lang/Override.java | 4 ++-- .../share/classes/java/lang/SafeVarargs.java | 3 ++- .../classes/java/lang/SuppressWarnings.java | 17 ++++++++++++----- .../classes/java/lang/annotation/Inherited.java | 3 ++- .../classes/java/lang/annotation/Retention.java | 3 ++- .../classes/java/lang/annotation/Target.java | 5 ++++- 7 files changed, 26 insertions(+), 12 deletions(-) diff --git a/jdk/src/share/classes/java/lang/Deprecated.java b/jdk/src/share/classes/java/lang/Deprecated.java index 2b1546bc64b..58a0691f054 100644 --- a/jdk/src/share/classes/java/lang/Deprecated.java +++ b/jdk/src/share/classes/java/lang/Deprecated.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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,6 +36,7 @@ import static java.lang.annotation.ElementType.*; * * @author Neal Gafter * @since 1.5 + * @jls 9.6.3.6 @Deprecated */ @Documented @Retention(RetentionPolicy.RUNTIME) diff --git a/jdk/src/share/classes/java/lang/Override.java b/jdk/src/share/classes/java/lang/Override.java index ea6e54a151e..bf77344296c 100644 --- a/jdk/src/share/classes/java/lang/Override.java +++ b/jdk/src/share/classes/java/lang/Override.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -43,7 +43,7 @@ import java.lang.annotation.*; * * @author Peter von der Ahé * @author Joshua Bloch - * @jls 9.6.1.4 Override + * @jls 9.6.1.4 @Override * @since 1.5 */ @Target(ElementType.METHOD) diff --git a/jdk/src/share/classes/java/lang/SafeVarargs.java b/jdk/src/share/classes/java/lang/SafeVarargs.java index cb14134ffbe..6fcd48e97d7 100644 --- a/jdk/src/share/classes/java/lang/SafeVarargs.java +++ b/jdk/src/share/classes/java/lang/SafeVarargs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, 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 @@ -85,6 +85,7 @@ import java.lang.annotation.*; * @since 1.7 * @jls 4.7 Reifiable Types * @jls 8.4.1 Formal Parameters + * @jls 9.6.3.7 @SafeVarargs */ @Documented @Retention(RetentionPolicy.RUNTIME) diff --git a/jdk/src/share/classes/java/lang/SuppressWarnings.java b/jdk/src/share/classes/java/lang/SuppressWarnings.java index babb060396a..22895dc7b2c 100644 --- a/jdk/src/share/classes/java/lang/SuppressWarnings.java +++ b/jdk/src/share/classes/java/lang/SuppressWarnings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, 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 @@ -41,8 +41,13 @@ import static java.lang.annotation.ElementType.*; * suppress a warning in a particular method, you should annotate that * method rather than its class. * - * @since 1.5 * @author Josh Bloch + * @since 1.5 + * @jls 4.8 Raw Types + * @jls 4.12.2 Variables of Reference Type + * @jls 5.1.9 Unchecked Conversion + * @jls 5.5.2 Checked Casts and Unchecked Casts + * @jls 9.6.3.5 @SuppressWarnings */ @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) @@ -56,9 +61,11 @@ public @interface SuppressWarnings { * free to emit a warning if an annotation contains an unrecognized * warning name. * - * <p>Compiler vendors should document the warning names they support in - * conjunction with this annotation type. They are encouraged to cooperate - * to ensure that the same names work across multiple compilers. + * <p> The string {@code "unchecked"} is used to suppress + * unchecked warnings. Compiler vendors should document the + * additional warning names they support in conjunction with this + * annotation type. They are encouraged to cooperate to ensure + * that the same names work across multiple compilers. */ String[] value(); } diff --git a/jdk/src/share/classes/java/lang/annotation/Inherited.java b/jdk/src/share/classes/java/lang/annotation/Inherited.java index a7efa6b41d2..83391e29eac 100644 --- a/jdk/src/share/classes/java/lang/annotation/Inherited.java +++ b/jdk/src/share/classes/java/lang/annotation/Inherited.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -44,6 +44,7 @@ package java.lang.annotation; * * @author Joshua Bloch * @since 1.5 + * @jls 9.6.3.3 @Inherited */ @Documented @Retention(RetentionPolicy.RUNTIME) diff --git a/jdk/src/share/classes/java/lang/annotation/Retention.java b/jdk/src/share/classes/java/lang/annotation/Retention.java index df04a31db90..1c27ca0871e 100644 --- a/jdk/src/share/classes/java/lang/annotation/Retention.java +++ b/jdk/src/share/classes/java/lang/annotation/Retention.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -38,6 +38,7 @@ package java.lang.annotation; * * @author Joshua Bloch * @since 1.5 + * @jls 9.6.3.2 @Retention */ @Documented @Retention(RetentionPolicy.RUNTIME) diff --git a/jdk/src/share/classes/java/lang/annotation/Target.java b/jdk/src/share/classes/java/lang/annotation/Target.java index dc67de3f071..cdf4a748ae5 100644 --- a/jdk/src/share/classes/java/lang/annotation/Target.java +++ b/jdk/src/share/classes/java/lang/annotation/Target.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -59,6 +59,9 @@ package java.lang.annotation; * ... * } * </pre> + * + * @since 1.5 + * @jls 9.6.3.1 @Target */ @Documented @Retention(RetentionPolicy.RUNTIME) From 68d2d95f008bec155e83626b06d42584b3eb1bea Mon Sep 17 00:00:00 2001 From: Petr Pchelko <pchelko@openjdk.org> Date: Mon, 25 Feb 2013 10:17:25 +0000 Subject: [PATCH 100/180] 8006634: Unify LWCToolkit.invokeAndWait() and sun.awt.datatransfer.ToolkitThreadBlockedHandler Changed the logic for the nested event loops and deleted deadlock detection Reviewed-by: art, denis --- .../sun/lwawt/macosx/CPlatformWindow.java | 12 +- .../macosx/CToolkitThreadBlockedHandler.java | 32 ++--- .../classes/sun/lwawt/macosx/LWCToolkit.java | 99 ++++++---------- jdk/src/macosx/native/sun/awt/AWTView.m | 6 +- .../native/sun/awt/ApplicationDelegate.m | 5 +- jdk/src/macosx/native/sun/awt/CClipboard.m | 8 +- jdk/src/macosx/native/sun/awt/CDropTarget.m | 3 +- jdk/src/macosx/native/sun/awt/CMenu.m | 10 +- jdk/src/macosx/native/sun/awt/CMenuBar.m | 8 +- jdk/src/macosx/native/sun/awt/CMenuItem.m | 2 +- .../sun/awt/JavaComponentAccessibility.m | 24 ++-- jdk/src/macosx/native/sun/awt/LWCToolkit.m | 52 +++------ .../native/sun/osxapp/ThreadUtilities.h | 9 +- .../native/sun/osxapp/ThreadUtilities.m | 109 ------------------ 14 files changed, 113 insertions(+), 266 deletions(-) diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java index dc51373cc1b..3fb585bdb53 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java @@ -30,6 +30,7 @@ import java.awt.Dialog.ModalityType; import java.awt.event.*; import java.awt.peer.WindowPeer; import java.beans.*; +import java.lang.reflect.InvocationTargetException; import java.util.List; import javax.swing.*; @@ -861,7 +862,16 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo private void flushBuffers() { if (isVisible() && !nativeBounds.isEmpty()) { - LWCToolkit.getLWCToolkit().flushPendingEventsOnAppkit(target); + try { + LWCToolkit.invokeAndWait(new Runnable() { + @Override + public void run() { + //Posting an empty to flush the EventQueue without blocking the main thread + } + }, target); + } catch (InterruptedException | InvocationTargetException e) { + e.printStackTrace(); + } } } diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CToolkitThreadBlockedHandler.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CToolkitThreadBlockedHandler.java index 94a74e5174b..6bc6cc7c41b 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CToolkitThreadBlockedHandler.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CToolkitThreadBlockedHandler.java @@ -25,27 +25,33 @@ package sun.lwawt.macosx; +import sun.awt.Mutex; import sun.awt.datatransfer.ToolkitThreadBlockedHandler; -final class CToolkitThreadBlockedHandler implements ToolkitThreadBlockedHandler { - private final LWCToolkit toolkit = (LWCToolkit)java.awt.Toolkit.getDefaultToolkit(); +final class CToolkitThreadBlockedHandler extends Mutex implements ToolkitThreadBlockedHandler { + private long awtRunLoopMediator = 0; + private final boolean processEvents; - public void lock() { - } - - public void unlock() { - } - - protected boolean isOwned() { - return false; + CToolkitThreadBlockedHandler() { + super(); + this.processEvents = true; } public void enter() { - // Execute the next AppKit event while we are waiting for system to - // finish our request - this will save us from biting our own tail - toolkit.executeNextAppKitEvent(); + if (!isOwned()) { + throw new IllegalMonitorStateException(); + } + awtRunLoopMediator = LWCToolkit.createAWTRunLoopMediator(); + unlock(); + LWCToolkit.doAWTRunLoop(awtRunLoopMediator, processEvents); + lock(); } public void exit() { + if (!isOwned()) { + throw new IllegalMonitorStateException(); + } + LWCToolkit.stopAWTRunLoop(awtRunLoopMediator); + awtRunLoopMediator = 0; } } diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java index 801c3d41605..83bc9f1f700 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java @@ -63,8 +63,6 @@ public final class LWCToolkit extends LWToolkit { private static native void initIDs(); - static native void executeNextAppKitEvent(); - private static CInputMethodDescriptor sInputMethodDescriptor; static { @@ -502,30 +500,6 @@ public final class LWCToolkit extends LWToolkit { synchronized(ret) { return ret[0]; } } - /** - * Just a wrapper for LWCToolkit.invokeAndWait. Posts an empty event to the - * appropriate event queue and waits for it to finish. - */ - public static void flushPendingEventsOnAppkit(final Component component) { - try { - invokeAndWait(new Runnable() { - @Override - public void run() { - } - }, component); - } catch (Exception e) { - e.printStackTrace(); - } - } - - // Kicks an event over to the appropriate eventqueue and waits for it to finish - // To avoid deadlocking, we manually run the NSRunLoop while waiting - // Any selector invoked using ThreadUtilities performOnMainThread will be processed in doAWTRunLoop - // The CInvocationEvent will call LWCToolkit.stopAWTRunLoop() when finished, which will stop our manual runloop - public static void invokeAndWait(Runnable event, Component component) throws InterruptedException, InvocationTargetException { - invokeAndWait(event, component, true); - } - public static <T> T invokeAndWait(final Callable<T> callable, Component component) throws Exception { final CallableWrapper<T> wrapper = new CallableWrapper<T>(callable); invokeAndWait(wrapper, component); @@ -555,10 +529,27 @@ public final class LWCToolkit extends LWToolkit { } } - public static void invokeAndWait(Runnable event, Component component, boolean detectDeadlocks) throws InterruptedException, InvocationTargetException { - long mediator = createAWTRunLoopMediator(); + // Kicks an event over to the appropriate eventqueue and waits for it to finish + // To avoid deadlocking, we manually run the NSRunLoop while waiting + // Any selector invoked using ThreadUtilities performOnMainThread will be processed in doAWTRunLoop + // The InvocationEvent will call LWCToolkit.stopAWTRunLoop() when finished, which will stop our manual runloop + // Does not dispatch native events while in the loop + public static void invokeAndWait(Runnable event, Component component) throws InterruptedException, InvocationTargetException { + final long mediator = createAWTRunLoopMediator(); - InvocationEvent invocationEvent = new CPeerEvent(event, mediator); + InvocationEvent invocationEvent = + new InvocationEvent(component != null ? component : Toolkit.getDefaultToolkit(), event) { + @Override + public void dispatch() { + try { + super.dispatch(); + } finally { + if (mediator != 0) { + stopAWTRunLoop(mediator); + } + } + } + }; if (component != null) { AppContext appContext = SunToolkit.targetToAppContext(component); @@ -571,7 +562,7 @@ public final class LWCToolkit extends LWToolkit { ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent); } - doAWTRunLoop(mediator, true, detectDeadlocks); + doAWTRunLoop(mediator, false); Throwable eventException = invocationEvent.getException(); if (eventException != null) { @@ -583,7 +574,8 @@ public final class LWCToolkit extends LWToolkit { } public static void invokeLater(Runnable event, Component component) throws InvocationTargetException { - final InvocationEvent invocationEvent = new CPeerEvent(event, 0); + final InvocationEvent invocationEvent = + new InvocationEvent(component != null ? component : Toolkit.getDefaultToolkit(), event); if (component != null) { final AppContext appContext = SunToolkit.targetToAppContext(component); @@ -688,31 +680,6 @@ public final class LWCToolkit extends LWToolkit { return false; } - // Extends PeerEvent because we want to pass long an ObjC mediator object and because we want these events to be posted early - // Typically, rather than relying on the notifier to call notifyAll(), we use the mediator to stop the runloop - public static class CPeerEvent extends PeerEvent { - private long _mediator = 0; - - public CPeerEvent(Runnable runnable, long mediator) { - super(Toolkit.getDefaultToolkit(), runnable, null, true, 0); - _mediator = mediator; - } - - public void dispatch() { - try { - super.dispatch(); - } finally { - if (_mediator != 0) { - LWCToolkit.stopAWTRunLoop(_mediator); - } - } - } - } - - // Call through to native methods - public static void doAWTRunLoop(long mediator, boolean awtMode) { doAWTRunLoop(mediator, awtMode, true); } - public static void doAWTRunLoop(long mediator) { doAWTRunLoop(mediator, true); } - private static Boolean sunAwtDisableCALayers = null; /** @@ -737,12 +704,20 @@ public final class LWCToolkit extends LWToolkit { * Native methods section ************************/ - // These are public because they are accessed from WebKitPluginObject in JavaDeploy - // Basic usage: - // createAWTRunLoopMediator. Start client code on another thread. doAWTRunLoop. When client code is finished, stopAWTRunLoop. - public static native long createAWTRunLoopMediator(); - public static native void doAWTRunLoop(long mediator, boolean awtMode, boolean detectDeadlocks); - public static native void stopAWTRunLoop(long mediator); + static native long createAWTRunLoopMediator(); + /** + * Method to run a nested run-loop. The nested loop is spinned in the javaRunLoop mode, so selectors sent + * by [JNFRunLoop performOnMainThreadWaiting] are processed. + * @param mediator a native pointer to the mediator object created by createAWTRunLoopMediator + * @param processEvents if true - dispatches event while in the nested loop. Used in DnD. + * Additional attention is needed when using this feature as we short-circuit normal event + * processing which could break Appkit. + * (One known example is when the window is resized with the mouse) + * + * if false - all events come after exit form the nested loop + */ + static native void doAWTRunLoop(long mediator, boolean processEvents); + static native void stopAWTRunLoop(long mediator); private native boolean nativeSyncQueue(long timeout); diff --git a/jdk/src/macosx/native/sun/awt/AWTView.m b/jdk/src/macosx/native/sun/awt/AWTView.m index cc16a2026ee..7e1f248c7ed 100644 --- a/jdk/src/macosx/native/sun/awt/AWTView.m +++ b/jdk/src/macosx/native/sun/awt/AWTView.m @@ -227,7 +227,7 @@ AWT_ASSERT_APPKIT_THREAD; - (void) mouseMoved: (NSEvent *)event { // TODO: better way to redirect move events to the "under" view - + NSPoint eventLocation = [event locationInWindow]; NSPoint localPoint = [self convertPoint: eventLocation fromView: nil]; @@ -668,7 +668,7 @@ AWT_ASSERT_APPKIT_THREAD; - (void) setDropTarget:(CDropTarget *)target { self._dropTarget = target; - [ThreadUtilities performOnMainThread:@selector(controlModelControlValid) onObject:self._dropTarget withObject:nil waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(controlModelControlValid) on:self._dropTarget withObject:nil waitUntilDone:YES]; } /******************************** BEGIN NSDraggingSource Interface ********************************/ @@ -1215,7 +1215,7 @@ JNF_CLASS_CACHE(jc_CInputMethod, "sun/lwawt/macosx/CInputMethod"); fprintf(stderr, "AWTView InputMethod Selector Called : [abandonInput]\n"); #endif // IM_DEBUG - [ThreadUtilities performOnMainThread:@selector(markedTextAbandoned:) onObject:[NSInputManager currentInputManager] withObject:self waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(markedTextAbandoned:) on:[NSInputManager currentInputManager] withObject:self waitUntilDone:YES]; [self unmarkText]; } diff --git a/jdk/src/macosx/native/sun/awt/ApplicationDelegate.m b/jdk/src/macosx/native/sun/awt/ApplicationDelegate.m index 9a5aee94d44..6b584b21ca3 100644 --- a/jdk/src/macosx/native/sun/awt/ApplicationDelegate.m +++ b/jdk/src/macosx/native/sun/awt/ApplicationDelegate.m @@ -567,10 +567,9 @@ JNIEXPORT void JNICALL Java_com_apple_eawt__1AppEventHandler_nativeRegisterForNo { JNF_COCOA_ENTER(env); [ThreadUtilities performOnMainThread:@selector(_registerForNotification:) - onObject:[ApplicationDelegate class] + on:[ApplicationDelegate class] withObject:[NSNumber numberWithInt:notificationType] - waitUntilDone:NO - awtMode:NO]; // AWT_THREADING Safe (non-blocking) + waitUntilDone:NO]; // AWT_THREADING Safe (non-blocking) JNF_COCOA_EXIT(env); } diff --git a/jdk/src/macosx/native/sun/awt/CClipboard.m b/jdk/src/macosx/native/sun/awt/CClipboard.m index fb300f72971..bfba06b47d1 100644 --- a/jdk/src/macosx/native/sun/awt/CClipboard.m +++ b/jdk/src/macosx/native/sun/awt/CClipboard.m @@ -120,7 +120,7 @@ static CClipboard *sClipboard = nil; fClipboardOwner = JNFNewGlobalRef(inEnv, inClipboard); } } - [ThreadUtilities performOnMainThread:@selector(_nativeDeclareTypes:) onObject:self withObject:inTypes waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(_nativeDeclareTypes:) on:self withObject:inTypes waitUntilDone:YES]; } - (void) _nativeDeclareTypes:(NSArray *)inTypes { @@ -135,7 +135,7 @@ static CClipboard *sClipboard = nil; - (NSArray *) javaGetTypes { NSMutableArray *args = [NSMutableArray arrayWithCapacity:1]; - [ThreadUtilities performOnMainThread:@selector(_nativeGetTypes:) onObject:self withObject:args waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(_nativeGetTypes:) on:self withObject:args waitUntilDone:YES]; //NSLog(@"CClipboard getTypes returns %@", [args lastObject]); return [args lastObject]; @@ -152,7 +152,7 @@ static CClipboard *sClipboard = nil; - (void) javaSetData:(NSData *)inData forType:(NSString *) inFormat { CClipboardUpdate *newUpdate = [[CClipboardUpdate alloc] initWithData:inData withFormat:inFormat]; - [ThreadUtilities performOnMainThread:@selector(_nativeSetData:) onObject:self withObject:newUpdate waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(_nativeSetData:) on:self withObject:newUpdate waitUntilDone:YES]; [newUpdate release]; //NSLog(@"CClipboard javaSetData forType %@", inFormat); @@ -170,7 +170,7 @@ static CClipboard *sClipboard = nil; - (NSData *) javaGetDataForType:(NSString *) inFormat { NSMutableArray *args = [NSMutableArray arrayWithObject:inFormat]; - [ThreadUtilities performOnMainThread:@selector(_nativeGetDataForType:) onObject:self withObject:args waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(_nativeGetDataForType:) on:self withObject:args waitUntilDone:YES]; //NSLog(@"CClipboard javaGetDataForType %@ returns an NSData", inFormat); return [args lastObject]; diff --git a/jdk/src/macosx/native/sun/awt/CDropTarget.m b/jdk/src/macosx/native/sun/awt/CDropTarget.m index 60cd7818254..9dda8ae3551 100644 --- a/jdk/src/macosx/native/sun/awt/CDropTarget.m +++ b/jdk/src/macosx/native/sun/awt/CDropTarget.m @@ -390,8 +390,7 @@ extern JNFClassInfo jc_CDropTargetContextPeer; // Release dragging data if any when Java's AWT event thread is all finished. // Make sure dragging data is released on the native event thread. - [ThreadUtilities performOnMainThread:@selector(safeReleaseDraggingData:) onObject:self - withObject:draggingSequenceNumberID waitUntilDone:NO awtMode:NO]; + [ThreadUtilities performOnMainThread:@selector(safeReleaseDraggingData:) on:self withObject:draggingSequenceNumberID waitUntilDone:NO]; } - (jint)currentJavaActions { diff --git a/jdk/src/macosx/native/sun/awt/CMenu.m b/jdk/src/macosx/native/sun/awt/CMenu.m index e6325c2c3db..8b643b3bca0 100644 --- a/jdk/src/macosx/native/sun/awt/CMenu.m +++ b/jdk/src/macosx/native/sun/awt/CMenu.m @@ -55,11 +55,11 @@ AWT_ASSERT_APPKIT_THREAD; //- (void)finalize { [super finalize]; } - (void)addJavaSubmenu:(CMenu *)submenu { - [ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) onObject:self withObject:submenu waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) on:self withObject:submenu waitUntilDone:YES]; } - (void)addJavaMenuItem:(CMenuItem *)theMenuItem { - [ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) onObject:self withObject:theMenuItem waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) on:self withObject:theMenuItem waitUntilDone:YES]; } - (void)addNativeItem_OnAppKitThread:(CMenuItem *)itemModified { @@ -70,7 +70,7 @@ AWT_ASSERT_APPKIT_THREAD; - (void)setJavaMenuTitle:(NSString *)title { if (title) { - [ThreadUtilities performOnMainThread:@selector(setNativeMenuTitle_OnAppKitThread:) onObject:self withObject:title waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(setNativeMenuTitle_OnAppKitThread:) on:self withObject:title waitUntilDone:YES]; } } @@ -93,7 +93,7 @@ AWT_ASSERT_APPKIT_THREAD; - (void)deleteJavaItem:(jint)index { - [ThreadUtilities performOnMainThread:@selector(deleteNativeJavaItem_OnAppKitThread:) onObject:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(deleteNativeJavaItem_OnAppKitThread:) on:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES]; } - (void)deleteNativeJavaItem_OnAppKitThread:(NSNumber *)number { @@ -139,7 +139,7 @@ CMenu * createCMenu (jobject cPeerObjGlobal) { // We use an array here only to be able to get a return value NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], nil]; - [ThreadUtilities performOnMainThread:@selector(_create_OnAppKitThread:) onObject:[CMenu alloc] withObject:args waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(_create_OnAppKitThread:) on:[CMenu alloc] withObject:args waitUntilDone:YES]; aCMenu = (CMenu *)[args objectAtIndex: 0]; diff --git a/jdk/src/macosx/native/sun/awt/CMenuBar.m b/jdk/src/macosx/native/sun/awt/CMenuBar.m index 23c79496189..b0d67f71a2a 100644 --- a/jdk/src/macosx/native/sun/awt/CMenuBar.m +++ b/jdk/src/macosx/native/sun/awt/CMenuBar.m @@ -197,7 +197,7 @@ static BOOL sSetupHelpMenu = NO; if (self == sActiveMenuBar) { NSArray *args = [[NSArray alloc] initWithObjects:theMenu, [NSNumber numberWithInt:-1], nil]; - [ThreadUtilities performOnMainThread:@selector(nativeAddMenuAtIndex_OnAppKitThread:) onObject:self withObject:args waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(nativeAddMenuAtIndex_OnAppKitThread:) on:self withObject:args waitUntilDone:YES]; [args release]; } } @@ -216,7 +216,7 @@ static BOOL sSetupHelpMenu = NO; if (self == sActiveMenuBar) { NSArray *args = [[NSArray alloc] initWithObjects:theMenu, [NSNumber numberWithInt:index], nil]; - [ThreadUtilities performOnMainThread:@selector(nativeAddMenuAtIndex_OnAppKitThread:) onObject:self withObject:args waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(nativeAddMenuAtIndex_OnAppKitThread:) on:self withObject:args waitUntilDone:YES]; [args release]; } } @@ -286,7 +286,7 @@ static BOOL sSetupHelpMenu = NO; - (void) javaDeleteMenu: (jint)index { if (self == sActiveMenuBar) { - [ThreadUtilities performOnMainThread:@selector(nativeDeleteMenu_OnAppKitThread:) onObject:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(nativeDeleteMenu_OnAppKitThread:) on:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES]; } @synchronized(self) { @@ -388,7 +388,7 @@ Java_sun_lwawt_macosx_CMenuBar_nativeCreateMenuBar // We use an array here only to be able to get a return value NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], nil]; - [ThreadUtilities performOnMainThread:@selector(_create_OnAppKitThread:) onObject:[CMenuBar alloc] withObject:args waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(_create_OnAppKitThread:) on:[CMenuBar alloc] withObject:args waitUntilDone:YES]; aCMenuBar = (CMenuBar *)[args objectAtIndex: 0]; diff --git a/jdk/src/macosx/native/sun/awt/CMenuItem.m b/jdk/src/macosx/native/sun/awt/CMenuItem.m index 2281d8bcd95..b67c70658dd 100644 --- a/jdk/src/macosx/native/sun/awt/CMenuItem.m +++ b/jdk/src/macosx/native/sun/awt/CMenuItem.m @@ -386,7 +386,7 @@ JNF_COCOA_ENTER(env); args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], [NSNumber numberWithBool:NO], nil]; } - [ThreadUtilities performOnMainThread:@selector(_createMenuItem_OnAppKitThread:) onObject:[CMenuItem alloc] withObject:args waitUntilDone:YES awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(_createMenuItem_OnAppKitThread:) on:[CMenuItem alloc] withObject:args waitUntilDone:YES]; aCMenuItem = (CMenuItem *)[args objectAtIndex: 0]; diff --git a/jdk/src/macosx/native/sun/awt/JavaComponentAccessibility.m b/jdk/src/macosx/native/sun/awt/JavaComponentAccessibility.m index f886c4afbe1..a01bd781faa 100644 --- a/jdk/src/macosx/native/sun/awt/JavaComponentAccessibility.m +++ b/jdk/src/macosx/native/sun/awt/JavaComponentAccessibility.m @@ -1113,18 +1113,10 @@ static NSObject *sAttributeNamesLOCK = nil; JNIEnv *env = [ThreadUtilities getJNIEnv]; id value = nil; - // This code frequently gets called indirectly by Java when VoiceOver is active. - // Basically, we just have to know when we going to be a bad state, and do something "special". - // Note that while NSApplication isn't technically correct, we post a focus changed notification - // (which will call this method, but with the correct codepath) shortly afterwards. See +postFocusChanged. - if (sInPerformFromJava) { - return [NSApplication sharedApplication]; - } else { - jobject focused = JNFCallStaticObjectMethod(env, jm_getFocusOwner, fComponent); // AWT_THREADING Safe (AWTRunLoop) - if (focused != NULL) { - if (JNFIsInstanceOf(env, focused, &sjc_Accessible)) { - value = [JavaComponentAccessibility createWithAccessible:focused withEnv:env withView:fView]; - } + jobject focused = JNFCallStaticObjectMethod(env, jm_getFocusOwner, fComponent); // AWT_THREADING Safe (AWTRunLoop) + if (focused != NULL) { + if (JNFIsInstanceOf(env, focused, &sjc_Accessible)) { + value = [JavaComponentAccessibility createWithAccessible:focused withEnv:env withView:fView]; } } @@ -1149,7 +1141,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessibility_focusChanged { JNF_COCOA_ENTER(env); - [ThreadUtilities performOnMainThread:@selector(postFocusChanged:) onObject:[JavaComponentAccessibility class] withObject:nil waitUntilDone:NO awtMode:NO]; + [ThreadUtilities performOnMainThread:@selector(postFocusChanged:) on:[JavaComponentAccessibility class] withObject:nil waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -1164,7 +1156,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_valueChanged (JNIEnv *env, jclass jklass, jlong element) { JNF_COCOA_ENTER(env); - [ThreadUtilities performOnMainThread:@selector(postValueChanged) onObject:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO awtMode:NO]; + [ThreadUtilities performOnMainThread:@selector(postValueChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -1177,7 +1169,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectionChanged (JNIEnv *env, jclass jklass, jlong element) { JNF_COCOA_ENTER(env); - [ThreadUtilities performOnMainThread:@selector(postSelectionChanged) onObject:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO awtMode:NO]; + [ThreadUtilities performOnMainThread:@selector(postSelectionChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO]; JNF_COCOA_EXIT(env); } @@ -1191,7 +1183,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_unregisterFromCocoaAXSy (JNIEnv *env, jclass jklass, jlong element) { JNF_COCOA_ENTER(env); - [ThreadUtilities performOnMainThread:@selector(unregisterFromCocoaAXSystem) onObject:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO awtMode:NO]; + [ThreadUtilities performOnMainThread:@selector(unregisterFromCocoaAXSystem) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO]; JNF_COCOA_EXIT(env); } diff --git a/jdk/src/macosx/native/sun/awt/LWCToolkit.m b/jdk/src/macosx/native/sun/awt/LWCToolkit.m index 45c546181f0..ec4870eba69 100644 --- a/jdk/src/macosx/native/sun/awt/LWCToolkit.m +++ b/jdk/src/macosx/native/sun/awt/LWCToolkit.m @@ -332,7 +332,7 @@ AWT_ASSERT_APPKIT_THREAD; * Signature: (JZZ)V */ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_doAWTRunLoop -(JNIEnv *env, jclass clz, jlong mediator, jboolean awtMode, jboolean detectDeadlocks) +(JNIEnv *env, jclass clz, jlong mediator, jboolean processEvents) { AWT_ASSERT_APPKIT_THREAD; JNF_COCOA_ENTER(env); @@ -341,26 +341,25 @@ JNF_COCOA_ENTER(env); if (mediatorObject == nil) return; - if (!sInPerformFromJava || !detectDeadlocks) { + // Don't use acceptInputForMode because that doesn't setup autorelease pools properly + BOOL isRunning = true; + while (![mediatorObject shouldEndRunLoop] && isRunning) { + isRunning = [[NSRunLoop currentRunLoop] runMode:[JNFRunLoop javaRunLoopMode] + beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.010]]; + if (processEvents) { + //We do not spin a runloop here as date is nil, so does not matter which mode to use + NSEvent *event; + if ((event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:nil + inMode:NSDefaultRunLoopMode + dequeue:YES]) != nil) { + [NSApp sendEvent:event]; + } - NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; - NSDate *distantFuture = [NSDate distantFuture]; - NSString *mode = (awtMode) ? [JNFRunLoop javaRunLoopMode] : NSDefaultRunLoopMode; - - BOOL isRunning = YES; - while (isRunning && ![mediatorObject shouldEndRunLoop]) { - // Don't use acceptInputForMode because that doesn't setup autorelease pools properly - isRunning = [currentRunLoop runMode:mode beforeDate:distantFuture]; } - } -#ifndef PRODUCT_BUILD - if (sInPerformFromJava) { - NSLog(@"Apple AWT: Short-circuiting CToolkit.invokeAndWait trampoline deadlock!!!!!"); - NSLog(@"\tPlease file a bug report with this message and a reproducible test case."); - } -#endif + CFRelease(mediatorObject); JNF_COCOA_EXIT(env); @@ -379,7 +378,7 @@ JNF_COCOA_ENTER(env); AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator); - [ThreadUtilities performOnMainThread:@selector(endRunLoop) onObject:mediatorObject withObject:nil waitUntilDone:NO awtMode:YES]; + [ThreadUtilities performOnMainThread:@selector(endRunLoop) on:mediatorObject withObject:nil waitUntilDone:NO]; CFRelease(mediatorObject); @@ -463,20 +462,3 @@ Java_sun_font_FontManager_populateFontFileNameMap } -/* - * Class: sun_lwawt_macosx_LWCToolkit - * Method: executeNextAppKitEvent - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_executeNextAppKitEvent -(JNIEnv *env, jclass cls) -{ - // Simply get the next event in native loop and pass it to execution - // We'll be called repeatedly so there's no need to block here - NSRunLoop *theRL = [NSRunLoop currentRunLoop]; - NSApplication * app = [NSApplication sharedApplication]; - NSEvent * event = [app nextEventMatchingMask: 0xFFFFFFFF untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES]; - if (event != nil) { - [app sendEvent: event]; - } -} diff --git a/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.h b/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.h index c0d2054f6e3..2ee65e94c65 100644 --- a/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.h +++ b/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.h @@ -122,19 +122,12 @@ do { \ #endif /* AWT_THREAD_ASSERTS */ // -------------------------------------------------------------------------- -// This tracks if we are current inside of a performOnMainThread that is both waiting and in the AWTRunLoopMode -extern BOOL sInPerformFromJava; - -// This is an empty Obj-C object just so that -performSelectorOnMainThread -// can be used, and to use the Obj-C +initialize feature. __attribute__((visibility("default"))) -@interface ThreadUtilities : NSObject { } +@interface ThreadUtilities { } + (JNIEnv*)getJNIEnv; + (JNIEnv*)getJNIEnvUncached; -+ (void)performOnMainThread:(SEL)aSelector onObject:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait awtMode:(BOOL)inAWT; - //Wrappers for the corresponding JNFRunLoop methods with a check for main thread + (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block; + (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait; diff --git a/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.m b/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.m index 0b42f1b5896..d431386bbdb 100644 --- a/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.m +++ b/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.m @@ -34,85 +34,6 @@ JavaVM *jvm = NULL; static JNIEnv *appKitEnv = NULL; -static NSArray *sPerformModes = nil; -static NSArray *sAWTPerformModes = nil; - -static BOOL sLoggingEnabled = YES; - -#ifdef AWT_THREAD_ASSERTS_ENV_ASSERT -int sAWTThreadAsserts = 0; -#endif /* AWT_THREAD_ASSERTS_ENV_ASSERT */ - -BOOL sInPerformFromJava = NO; - -// This class is used so that performSelectorOnMainThread can be -// controlled a little more easily by us. It has 2 roles. -// The first is to set/unset a flag (sInPerformFromJava) that code can -// check to see if we are in a synchronous perform initiated by a java thread. -// The second is to implement the CocoaComponent backward compatibility mode. -@interface CPerformer : NSObject { - id fTarget; - SEL fSelector; - id fArg; - BOOL fWait; -} - -- (id) initWithTarget:(id)target selector:(SEL)selector arg:(id)arg wait:(BOOL)wait; -- (void) perform; -@end - - -@implementation CPerformer - -- (id) initWithTarget:(id)target selector:(SEL)selector arg:(id)arg { - return [self initWithTarget:target selector:selector arg:arg wait:YES]; -} - -- (id) initWithTarget:(id)target selector:(SEL)selector arg:(id)arg wait:(BOOL)wait { - self = [super init]; - if (self != nil) { - fTarget = [target retain]; - fSelector = selector; - fArg = [arg retain]; - // Only set sInPerformFromJava if this is a synchronous perform - fWait = wait; - } - return self; -} - -- (void) dealloc { - [fTarget release]; - [fArg release]; - [super dealloc]; -} -//- (void)finalize { [super finalize]; } - -- (void) perform { - AWT_ASSERT_APPKIT_THREAD; - - // If this is the first time we're going from java thread -> appkit thread, - // set sInPerformFromJava for the duration of the invocation - BOOL nestedPerform = sInPerformFromJava; - if (fWait) { - sInPerformFromJava = YES; - } - - // Actually do the work (cheat to avoid a method call) - @try { - objc_msgSend(fTarget, fSelector, fArg); - //[fTarget performSelector:fSelector withObject:fArg]; - } @catch (NSException *e) { - NSLog(@"*** CPerformer: ignoring exception '%@' raised during perform of selector '%@' on target '%@' with args '%@'", e, NSStringFromSelector(fSelector), fTarget, fArg); - } @finally { - // If we actually set sInPerformFromJava, unset it now - if (!nestedPerform && fWait) { - sInPerformFromJava = NO; - } - } -} -@end - - @implementation ThreadUtilities + (JNIEnv*)getJNIEnv { @@ -129,36 +50,6 @@ AWT_ASSERT_APPKIT_THREAD; return env; } -+ (void)initialize { - // Headless: BOTH - // Embedded: BOTH - // Multiple Calls: NO - // Caller: Obj-C class initialization - // Thread: ? - - if (sPerformModes == nil) { - // Create list of Run Loop modes to perform on - // The default performSelector, with no mode argument, runs in Default, - // ModalPanel, and EventTracking modes - sPerformModes = [[NSArray alloc] initWithObjects:NSDefaultRunLoopMode, NSModalPanelRunLoopMode, nil]; - sAWTPerformModes = [[NSArray alloc] initWithObjects:NSDefaultRunLoopMode, NSModalPanelRunLoopMode, NSEventTrackingRunLoopMode, [JNFRunLoop javaRunLoopMode], nil]; - -#ifdef AWT_THREAD_ASSERTS_ENV_ASSERT - sAWTThreadAsserts = (getenv("COCOA_AWT_DISABLE_THREAD_ASSERTS") == NULL); -#endif /* AWT_THREAD_ASSERTS_ENV_ASSERT */ - } -} - -// These methods can behave slightly differently than the normal -// performSelector... In particular, we define a special runloop mode -// (AWTRunLoopMode) so that we can "block" the main thread against the -// java event thread without deadlocking. See CToolkit.invokeAndWait. -+ (void)performOnMainThread:(SEL)aSelector onObject:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait awtMode:(BOOL)inAWT { - CPerformer *performer = [[CPerformer alloc] initWithTarget:target selector:aSelector arg:arg wait:wait]; - [performer performSelectorOnMainThread:@selector(perform) withObject:nil waitUntilDone:wait modes:((inAWT) ? sAWTPerformModes : sPerformModes)]; // AWT_THREADING Safe (cover method) - [performer release]; -} - + (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block { if ([NSThread isMainThread] && wait == YES) { block(); From a04fad868ef960bde43050603d386c927a9858a9 Mon Sep 17 00:00:00 2001 From: Alan Bateman <alanb@openjdk.org> Date: Mon, 25 Feb 2013 17:17:05 +0000 Subject: [PATCH 101/180] 8008808: Allowed dependencies added by JDK-8008481 no longer required Reviewed-by: tbell, chegar --- jdk/make/tools/src/build/tools/deps/refs.allowed | 5 ----- 1 file changed, 5 deletions(-) diff --git a/jdk/make/tools/src/build/tools/deps/refs.allowed b/jdk/make/tools/src/build/tools/deps/refs.allowed index 91605d535fe..ad9d5271199 100644 --- a/jdk/make/tools/src/build/tools/deps/refs.allowed +++ b/jdk/make/tools/src/build/tools/deps/refs.allowed @@ -33,8 +33,3 @@ sun.security.krb5.Realm=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,comp # java.beans.PropertyChangeListener=java.util.logging.LogManager,sun.org.mozilla.javascript.internal.Context,compact1,compact2,compact3 java.beans.PropertyChangeEvent=sun.org.mozilla.javascript.internal.Context,compact3 - -# JFR traces even in builds with JFR disabled -com.oracle.jrockit.jfr.FlightRecorder: com.sun.management.MissionControl, compact3 -com.oracle.jrockit.jfr.management.FlightRecorderMBean: com.sun.management.MissionControl, compact3 - From 944e1b9636cd93d9549d2cc43177a1cf727a04c2 Mon Sep 17 00:00:00 2001 From: Brent Christian <bchristi@openjdk.org> Date: Mon, 25 Feb 2013 14:19:48 -0800 Subject: [PATCH 102/180] 8006039: test/tools/launcher/I18NJarTest.java fails on Mac w/ LANG=C, LC_ALL=C Avoid automated test failure by just exiting when in 'C' locale Reviewed-by: naoto, ksrini --- jdk/test/ProblemList.txt | 3 --- jdk/test/tools/launcher/I18NJarTest.java | 17 ++++++++++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 7c621e00884..7adc6d2c660 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -327,9 +327,6 @@ tools/pack200/Pack200Test.java solaris-all, mac # 7150569 tools/launcher/UnicodeTest.java macosx-all -# 8006039 -tools/launcher/I18NJarTest.java macosx-all - # 8007410 tools/launcher/FXLauncherTest.java linux-all diff --git a/jdk/test/tools/launcher/I18NJarTest.java b/jdk/test/tools/launcher/I18NJarTest.java index 9c033b47f8f..ad94abcce64 100644 --- a/jdk/test/tools/launcher/I18NJarTest.java +++ b/jdk/test/tools/launcher/I18NJarTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -52,6 +52,8 @@ public class I18NJarTest extends TestHelper { private static final File cwd = new File("."); private static final File dir = new File("\uFF66\uFF67\uFF68\uFF69"); private static final String encoding = System.getProperty("sun.jnu.encoding", ""); + private static final String LANG = System.getenv("LANG"); + private static final String LC_ALL = System.getenv("LC_ALL"); public static void main(String... args) throws Exception { boolean localeAvailable = false; @@ -63,7 +65,16 @@ public class I18NJarTest extends TestHelper { } if (!localeAvailable) { System.out.println("Warning: locale: " + Locale.JAPAN - + " not found, test passes vacuosly"); + + " not found, test passes vacuously"); + return; + } + if ("C".equals(LC_ALL) || "C".equals(LANG)) { + System.out.println("Warning: The LANG and/or LC_ALL env vars are " + + "set to \"C\":\n" + + " LANG=" + LANG + "\n" + + " LC_ALL=" + LC_ALL + "\n" + + "This test requires support for multi-byte filenames.\n" + + "Test passes vacuously."); return; } if (encoding.equals("MS932") || encoding.equals("UTF-8")) { @@ -73,7 +84,7 @@ public class I18NJarTest extends TestHelper { } else { System.out.println("Warning: current encoding is " + encoding + "this test requires MS932 <Ja> or UTF-8," + - " test passes vacuosly"); + " test passes vacuously"); return; } dir.mkdir(); From b3a313fa2bff811dbd063e26fd8139ecd717a2e3 Mon Sep 17 00:00:00 2001 From: Erik Joelsson <erik.joelsson@oracle.com> Date: Mon, 25 Feb 2013 15:08:11 -0800 Subject: [PATCH 103/180] 8008914: Add nashorn to the tl build Co-authored-by: James Laskey <james.laskey@oracle.com> Reviewed-by: mr, tbell, jjh --- jdk/make/launchers/Makefile | 1 + jdk/makefiles/CompileLaunchers.gmk | 3 +++ jdk/makefiles/CreateJars.gmk | 8 ++++++++ jdk/test/tools/launcher/VersionCheck.java | 1 + 4 files changed, 13 insertions(+) diff --git a/jdk/make/launchers/Makefile b/jdk/make/launchers/Makefile index be16512e478..47645158793 100644 --- a/jdk/make/launchers/Makefile +++ b/jdk/make/launchers/Makefile @@ -77,6 +77,7 @@ $(call make-launcher, jmap, sun.tools.jmap.JMap, \ -J-Dsun.jvm.hotspot.debugger.useWindbgDebugger, ) $(call make-launcher, jps, sun.tools.jps.Jps, , ) $(call make-launcher, jrunscript, com.sun.tools.script.shell.Main, , ) +$(call make-launcher, jjs, jdk.nashorn.tools.Shell, , ) $(call make-launcher, jsadebugd, sun.jvm.hotspot.jdi.SADebugServer, , ) $(call make-launcher, jstack, sun.tools.jstack.JStack, \ -J-Dsun.jvm.hotspot.debugger.useProcDebugger \ diff --git a/jdk/makefiles/CompileLaunchers.gmk b/jdk/makefiles/CompileLaunchers.gmk index 170dc164ec4..501c986082e 100644 --- a/jdk/makefiles/CompileLaunchers.gmk +++ b/jdk/makefiles/CompileLaunchers.gmk @@ -311,6 +311,9 @@ $(eval $(call SetupLauncher,jps,\ $(eval $(call SetupLauncher,jrunscript,\ -DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "com.sun.tools.script.shell.Main"$(COMMA) }')) +$(eval $(call SetupLauncher,jjs,\ + -DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "jdk.nashorn.tools.Shell"$(COMMA) }')) + $(eval $(call SetupLauncher,jsadebugd,\ -DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "sun.jvm.hotspot.jdi.SADebugServer"$(COMMA) }' \ -DAPP_CLASSPATH='{ "/lib/tools.jar"$(COMMA) "/lib/sa-jdi.jar"$(COMMA) "/classes" }' \ diff --git a/jdk/makefiles/CreateJars.gmk b/jdk/makefiles/CreateJars.gmk index 7e33790d299..857e0d5e9a4 100644 --- a/jdk/makefiles/CreateJars.gmk +++ b/jdk/makefiles/CreateJars.gmk @@ -1119,6 +1119,14 @@ endif ########################################################################################## +# Import nashorn.jar from nashorn dist dir. +$(IMAGES_OUTPUTDIR)/lib/ext/nashorn.jar: $(NASHORN_DIST)/nashorn.jar + $(install-file) + +JARS += $(IMAGES_OUTPUTDIR)/lib/ext/nashorn.jar + +########################################################################################## + -include $(CUSTOM_MAKE_DIR)/CreateJars.gmk ########################################################################################## diff --git a/jdk/test/tools/launcher/VersionCheck.java b/jdk/test/tools/launcher/VersionCheck.java index 11f65cb2e9a..64f0e6adfb8 100644 --- a/jdk/test/tools/launcher/VersionCheck.java +++ b/jdk/test/tools/launcher/VersionCheck.java @@ -74,6 +74,7 @@ public class VersionCheck extends TestHelper { "jmap", "jps", "jrunscript", + "jjs", "jsadebugd", "jstack", "jstat", From 5c31bde4c0155aad8468ca54166c85eee5bcc2ef Mon Sep 17 00:00:00 2001 From: Erik Joelsson <erik.joelsson@oracle.com> Date: Mon, 25 Feb 2013 15:08:11 -0800 Subject: [PATCH 104/180] 8008914: Add nashorn to the tl build Co-authored-by: James Laskey <james.laskey@oracle.com> Reviewed-by: mr, tbell, jjh --- Makefile | 7 +++++++ common/autoconf/generated-configure.sh | 16 ++++++++++++++++ common/autoconf/source-dirs.m4 | 15 ++++++++++++++- common/autoconf/spec.gmk.in | 3 +++ common/bin/hgforest.sh | 2 +- common/makefiles/Main.gmk | 18 +++++++++++++----- common/makefiles/MakeBase.gmk | 3 ++- make/Defs-internal.gmk | 14 ++++++++++++++ make/jdk-rules.gmk | 3 +++ make/sanity-rules.gmk | 14 ++++++++++++++ make/scripts/hgforest.sh | 2 +- 11 files changed, 88 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index f9162f0b641..f7b9d1b35e3 100644 --- a/Makefile +++ b/Makefile @@ -90,6 +90,7 @@ include ./make/corba-rules.gmk include ./make/jaxp-rules.gmk include ./make/jaxws-rules.gmk include ./make/jdk-rules.gmk +include ./make/nashorn-rules.gmk include ./make/install-rules.gmk include ./make/sponsors-rules.gmk include ./make/deploy-rules.gmk @@ -174,6 +175,11 @@ ifeq ($(BUILD_JDK), true) clobber:: jdk-clobber endif +ifeq ($(BUILD_NASHORN), true) + generic_build_repo_series:: $(NASHORN) + clobber:: nashorn-clobber +endif + ifeq ($(BUILD_DEPLOY), true) generic_build_repo_series:: $(DEPLOY) clobber:: deploy-clobber @@ -336,6 +342,7 @@ deploy_fastdebug_only: BUILD_HOTSPOT=false \ BUILD_JDK=false \ BUILD_LANGTOOLS=false \ + BUILD_NASHORN=false \ BUILD_CORBA=false \ BUILD_JAXP=false \ BUILD_JAXWS=false \ diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 741160eab1d..00d5093259b 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -747,6 +747,7 @@ BUILD_OUTPUT OVERRIDE_SRC_ROOT ADD_SRC_ROOT JDK_TOPDIR +NASHORN_TOPDIR HOTSPOT_TOPDIR JAXWS_TOPDIR JAXP_TOPDIR @@ -15663,6 +15664,7 @@ CORBA_TOPDIR="$SRC_ROOT/corba" JAXP_TOPDIR="$SRC_ROOT/jaxp" JAXWS_TOPDIR="$SRC_ROOT/jaxws" HOTSPOT_TOPDIR="$SRC_ROOT/hotspot" +NASHORN_TOPDIR="$SRC_ROOT/nashorn" JDK_TOPDIR="$SRC_ROOT/jdk" @@ -15673,6 +15675,7 @@ JDK_TOPDIR="$SRC_ROOT/jdk" + ############################################################################### # # Pickup additional source for a component from outside of the source root @@ -15903,6 +15906,19 @@ $as_echo_n "checking if hotspot should be overridden... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes with $HOTSPOT_TOPDIR" >&5 $as_echo "yes with $HOTSPOT_TOPDIR" >&6; } fi +if test "x$with_override_nashorn" != x; then + CURDIR="$PWD" + cd "$with_override_nashorn" + NASHORN_TOPDIR="`pwd`" + cd "$CURDIR" + if ! test -f $NASHORN_TOPDIR/makefiles/BuildNashorn.gmk; then + as_fn_error $? "You have to override nashorn with a full nashorn repo!" "$LINENO" 5 + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if nashorn should be overridden" >&5 +$as_echo_n "checking if nashorn should be overridden... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes with $NASHORN_TOPDIR" >&5 +$as_echo "yes with $NASHORN_TOPDIR" >&6; } +fi if test "x$with_override_jdk" != x; then CURDIR="$PWD" cd "$with_override_jdk" diff --git a/common/autoconf/source-dirs.m4 b/common/autoconf/source-dirs.m4 index eacd056066b..bb0aba1b826 100644 --- a/common/autoconf/source-dirs.m4 +++ b/common/autoconf/source-dirs.m4 @@ -33,12 +33,14 @@ CORBA_TOPDIR="$SRC_ROOT/corba" JAXP_TOPDIR="$SRC_ROOT/jaxp" JAXWS_TOPDIR="$SRC_ROOT/jaxws" HOTSPOT_TOPDIR="$SRC_ROOT/hotspot" +NASHORN_TOPDIR="$SRC_ROOT/nashorn" JDK_TOPDIR="$SRC_ROOT/jdk" AC_SUBST(LANGTOOLS_TOPDIR) AC_SUBST(CORBA_TOPDIR) AC_SUBST(JAXP_TOPDIR) AC_SUBST(JAXWS_TOPDIR) AC_SUBST(HOTSPOT_TOPDIR) +AC_SUBST(NASHORN_TOPDIR) AC_SUBST(JDK_TOPDIR) ]) @@ -233,7 +235,18 @@ if test "x$with_override_hotspot" != x; then fi AC_MSG_CHECKING([if hotspot should be overridden]) AC_MSG_RESULT([yes with $HOTSPOT_TOPDIR]) -fi +fi +if test "x$with_override_nashorn" != x; then + CURDIR="$PWD" + cd "$with_override_nashorn" + NASHORN_TOPDIR="`pwd`" + cd "$CURDIR" + if ! test -f $NASHORN_TOPDIR/makefiles/BuildNashorn.gmk; then + AC_MSG_ERROR([You have to override nashorn with a full nashorn repo!]) + fi + AC_MSG_CHECKING([if nashorn should be overridden]) + AC_MSG_RESULT([yes with $NASHORN_TOPDIR]) +fi if test "x$with_override_jdk" != x; then CURDIR="$PWD" cd "$with_override_jdk" diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index ec47d0364fd..3d6cac27e7b 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -141,6 +141,7 @@ CORBA_TOPDIR:=@CORBA_TOPDIR@ JAXP_TOPDIR:=@JAXP_TOPDIR@ JAXWS_TOPDIR:=@JAXWS_TOPDIR@ HOTSPOT_TOPDIR:=@HOTSPOT_TOPDIR@ +NASHORN_TOPDIR:=@NASHORN_TOPDIR@ COPYRIGHT_YEAR:=@COPYRIGHT_YEAR@ # Location where build customization files may be found @@ -230,6 +231,7 @@ JAXP_OUTPUTDIR=$(BUILD_OUTPUT)/jaxp JAXWS_OUTPUTDIR=$(BUILD_OUTPUT)/jaxws HOTSPOT_OUTPUTDIR=$(BUILD_OUTPUT)/hotspot JDK_OUTPUTDIR=$(BUILD_OUTPUT)/jdk +NASHORN_OUTPUTDIR=$(BUILD_OUTPUT)/nashorn IMAGES_OUTPUTDIR=$(BUILD_OUTPUT)/images JCE_OUTPUTDIR=$(BUILD_OUTPUT)/jce-release @@ -238,6 +240,7 @@ CORBA_DIST=$(CORBA_OUTPUTDIR)/dist JAXP_DIST=$(JAXP_OUTPUTDIR)/dist JAXWS_DIST=$(JAXWS_OUTPUTDIR)/dist HOTSPOT_DIST=@HOTSPOT_DIST@ +NASHORN_DIST=$(NASHORN_OUTPUTDIR)/dist BUILD_HOTSPOT=@BUILD_HOTSPOT@ diff --git a/common/bin/hgforest.sh b/common/bin/hgforest.sh index 29e80301a06..9f0db97d578 100644 --- a/common/bin/hgforest.sh +++ b/common/bin/hgforest.sh @@ -96,7 +96,7 @@ pull_default="" repos="" repos_extra="" if [ "${command}" = "clone" -o "${command}" = "fclone" ] ; then - subrepos="corba jaxp jaxws langtools jdk hotspot" + subrepos="corba jaxp jaxws langtools jdk hotspot nashorn" if [ -f .hg/hgrc ] ; then pull_default=`hg paths default` if [ "${pull_default}" = "" ] ; then diff --git a/common/makefiles/Main.gmk b/common/makefiles/Main.gmk index 1fce2e25dc6..c43f590707c 100644 --- a/common/makefiles/Main.gmk +++ b/common/makefiles/Main.gmk @@ -123,6 +123,12 @@ jdk-only: start-make @($(CD) $(JDK_TOPDIR)/makefiles && $(BUILD_LOG_WRAPPER) $(MAKE) $(MAKE_ARGS) -f BuildJdk.gmk $(JDK_TARGET)) @$(call TargetExit) +nashorn: jdk nashorn-only +nashorn-only: start-make + @$(call TargetEnter) + @($(CD) $(NASHORN_TOPDIR)/makefiles && $(BUILD_LOG_WRAPPER) $(MAKE) $(MAKE_ARGS) -f BuildNashorn.gmk) + @$(call TargetExit) + demos: jdk demos-only demos-only: start-make @$(call TargetEnter) @@ -131,7 +137,7 @@ demos-only: start-make # Note: This double-colon rule is intentional, to support # custom make file integration. -images:: source-tips demos images-only +images:: source-tips demos nashorn images-only images-only: start-make @$(call TargetEnter) @($(CD) $(JDK_TOPDIR)/makefiles && $(BUILD_LOG_WRAPPER) $(MAKE) $(MAKE_ARGS) -f BuildJdk.gmk images) @@ -193,7 +199,7 @@ $(OUTPUT_ROOT)/source_tips: FRC # Remove everything, except the output from configure. -clean: clean-langtools clean-corba clean-jaxp clean-jaxws clean-hotspot clean-jdk clean-images clean-overlay-images clean-bootcycle-build clean-docs +clean: clean-langtools clean-corba clean-jaxp clean-jaxws clean-hotspot clean-jdk clean-nashorn clean-images clean-overlay-images clean-bootcycle-build clean-docs @($(CD) $(OUTPUT_ROOT) && $(RM) -r tmp source_tips build.log* build-trace*.log*) @$(ECHO) Cleaned all build artifacts. @@ -223,6 +229,8 @@ clean-hotspot: $(call CleanComponent,hotspot) clean-jdk: $(call CleanComponent,jdk) +clean-nashorn: + $(call CleanComponent,nashorn) clean-images: $(call CleanComponent,images) clean-overlay-images: @@ -233,10 +241,10 @@ clean-docs: $(call CleanComponent,docs) $(call CleanComponent,docstemp) -.PHONY: langtools corba jaxp jaxws hotspot jdk images overlay-images install -.PHONY: langtools-only corba-only jaxp-only jaxws-only hotspot-only jdk-only images-only overlay-images-only install-only +.PHONY: langtools corba jaxp jaxws hotspot jdk nashorn images overlay-images install +.PHONY: langtools-only corba-only jaxp-only jaxws-only hotspot-only jdk-only nashorn-only images-only overlay-images-only install-only .PHONY: all test clean dist-clean bootcycle-images start-make -.PHONY: clean-langtools clean-corba clean-jaxp clean-jaxws clean-hotspot clean-jdk clean-images clean-overlay-images clean-bootcycle-build +.PHONY: clean-langtools clean-corba clean-jaxp clean-jaxws clean-hotspot clean-jdk clean-nashorn clean-images clean-overlay-images clean-bootcycle-build .PHONY: profiles profiles-only profiles-oscheck FRC: # Force target diff --git a/common/makefiles/MakeBase.gmk b/common/makefiles/MakeBase.gmk index 708cbada085..4c1ecc8c8b7 100644 --- a/common/makefiles/MakeBase.gmk +++ b/common/makefiles/MakeBase.gmk @@ -51,8 +51,9 @@ decompress_paths=$(SED) -f $(SRC_ROOT)/common/makefiles/support/ListPathsSafely- -e 's|X98|$(OUTPUT_ROOT)|g' -e 's|X97|$(SRC_ROOT)|g' \ -e 's|X00|X|g' | tr '\n' '$2' +# Subst in an extra $ to prevent it from disappearing. define ListPathsSafely_If - $(if $(word $3,$($1)),$(eval $1_LPS$3:=$(call compress_paths,$(wordlist $3,$4,$($1))))) + $(if $(word $3,$($1)),$(eval $1_LPS$3:=$(call compress_paths,$(subst $$,$$$$,$(wordlist $3,$4,$($1)))))) endef define ListPathsSafely_Printf diff --git a/make/Defs-internal.gmk b/make/Defs-internal.gmk index 6f40f763bc9..15374ff7c51 100644 --- a/make/Defs-internal.gmk +++ b/make/Defs-internal.gmk @@ -100,6 +100,7 @@ ABS_JAXP_TOPDIR:=$(call OptFullPath,"$(JAXP_TOPDIR)") ABS_JAXWS_TOPDIR:=$(call OptFullPath,"$(JAXWS_TOPDIR)") ABS_JDK_TOPDIR:=$(call OptFullPath,"$(JDK_TOPDIR)") ABS_HOTSPOT_TOPDIR:=$(call OptFullPath,"$(HOTSPOT_TOPDIR)") +ABS_NASHORN_TOPDIR:=$(call OptFullPath,"$(NASHORN_TOPDIR)") ABS_INSTALL_TOPDIR:=$(call OptFullPath,"$(INSTALL_TOPDIR)") ABS_SPONSORS_TOPDIR:=$(call OptFullPath,"$(SPONSORS_TOPDIR)") ABS_DEPLOY_TOPDIR:=$(call OptFullPath,"$(DEPLOY_TOPDIR)") @@ -165,6 +166,15 @@ ifeq ($(JDK_SRC_AVAILABLE),true) endif endif +NASHORN_SRC_AVAILABLE := $(call MkExists,$(NASHORN_TOPDIR)/make/Makefile) +ifndef BUILD_NASHORN + ifdef ALT_NASHORN_DIST + BUILD_NASHORN := false + else + BUILD_NASHORN := $(NASHORN_SRC_AVAILABLE) + endif +endif + DEPLOY_SRC_AVAILABLE := $(call MkExists,$(DEPLOY_TOPDIR)/make/Makefile) ifndef BUILD_DEPLOY BUILD_DEPLOY := $(DEPLOY_SRC_AVAILABLE) @@ -308,6 +318,10 @@ ifndef ALT_JAXWS_DIST JAXWS_OUTPUTDIR = $(ABS_OUTPUTDIR)/jaxws ABS_JAXWS_DIST = $(JAXWS_OUTPUTDIR)/dist endif +ifndef ALT_NASHORN_DIST + NASHORN_OUTPUTDIR = $(ABS_OUTPUTDIR)/nashorn + ABS_NASHORN_DIST = $(NASHORN_OUTPUTDIR)/dist +endif # Common make arguments (supplied to all component builds) COMMON_BUILD_ARGUMENTS = \ diff --git a/make/jdk-rules.gmk b/make/jdk-rules.gmk index 42ba6adf627..dc6b5556dd0 100644 --- a/make/jdk-rules.gmk +++ b/make/jdk-rules.gmk @@ -62,6 +62,9 @@ endif ifeq ($(BUILD_JAXWS), true) JDK_BUILD_ARGUMENTS += ALT_JAXWS_DIST=$(ABS_JAXWS_DIST) endif +ifeq ($(BUILD_NASHORN), true) + JDK_BUILD_ARGUMENTS += ALT_NASHORN_DIST=$(ABS_NASHORN_DIST) +endif ifeq ($(BUILD_HOTSPOT), true) JDK_BUILD_ARGUMENTS += ALT_HOTSPOT_IMPORT_PATH=$(HOTSPOT_DIR)/import diff --git a/make/sanity-rules.gmk b/make/sanity-rules.gmk index 544dba10ffd..ee3d6f88ab1 100644 --- a/make/sanity-rules.gmk +++ b/make/sanity-rules.gmk @@ -182,6 +182,14 @@ ifeq ($(JDK_SRC_AVAILABLE), true) "" >> $(WARNING_FILE) endif endif +ifeq ($(NASHORN_SRC_AVAILABLE), true) + ifneq ($(BUILD_NASHORN), true) + @$(ECHO) "WARNING: You are not building the NASHORN sources.\n" \ + " The nashorn files will be obtained from \n" \ + " the location set in ALT_JDK_IMPORT_PATH. \n" \ + "" >> $(WARNING_FILE) + endif +endif ifeq ($(DEPLOY_SRC_AVAILABLE), true) ifneq ($(BUILD_DEPLOY), true) @$(ECHO) "WARNING: You are not building the DEPLOY sources.\n" \ @@ -268,6 +276,9 @@ endif ifeq ($(JDK_SRC_AVAILABLE), true) @$(ECHO) " JDK_TOPDIR = $(JDK_TOPDIR)" >> $(MESSAGE_FILE) endif +ifeq ($(NASHORN_SRC_AVAILABLE), true) + @$(ECHO) " NASHORN_TOPDIR = $(NASHORN_TOPDIR)" >> $(MESSAGE_FILE) +endif ifeq ($(DEPLOY_SRC_AVAILABLE), true) @$(ECHO) " DEPLOY_TOPDIR = $(DEPLOY_TOPDIR)" >> $(MESSAGE_FILE) endif @@ -303,6 +314,9 @@ endif ifeq ($(JDK_SRC_AVAILABLE), true) @$(ECHO) " BUILD_JDK = $(BUILD_JDK) " >> $(MESSAGE_FILE) endif +ifeq ($(NASHORN_SRC_AVAILABLE), true) + @$(ECHO) " BUILD_NASHORN = $(BUILD_NASHORN) " >> $(MESSAGE_FILE) +endif ifeq ($(DEPLOY_SRC_AVAILABLE), true) @$(ECHO) " BUILD_DEPLOY = $(BUILD_DEPLOY) " >> $(MESSAGE_FILE) endif diff --git a/make/scripts/hgforest.sh b/make/scripts/hgforest.sh index ed937f3711e..f30d3eb7768 100644 --- a/make/scripts/hgforest.sh +++ b/make/scripts/hgforest.sh @@ -40,7 +40,7 @@ pull_default="" repos="" repos_extra="" if [ "${command}" = "clone" -o "${command}" = "fclone" ] ; then - subrepos="corba jaxp jaxws langtools jdk hotspot" + subrepos="corba jaxp jaxws langtools jdk hotspot nashorn" if [ -f .hg/hgrc ] ; then pull_default=`hg paths default` if [ "${pull_default}" = "" ] ; then From f5666f9a691c21722765adb8e84543d1c99eb652 Mon Sep 17 00:00:00 2001 From: Krystal Mo <kmo@openjdk.org> Date: Tue, 26 Feb 2013 11:05:26 +0000 Subject: [PATCH 105/180] 7087570: java.lang.invoke.MemberName information wrong for method handles created with findConstructor REF_invokeSpecial DMHs (which are unusual) get marked explicitly; tweak the MHI to use this bit Reviewed-by: jrose, twisti --- .../java/lang/invoke/DirectMethodHandle.java | 52 ++- .../java/lang/invoke/MethodHandle.java | 9 +- .../java/lang/invoke/MethodHandleImpl.java | 16 +- .../java/lang/invoke/MethodHandleInfo.java | 15 +- .../java/lang/invoke/MethodHandles.java | 4 +- .../java/lang/invoke/7087570/Test7087570.java | 326 ++++++++++++++++++ 6 files changed, 401 insertions(+), 21 deletions(-) create mode 100644 jdk/test/java/lang/invoke/7087570/Test7087570.java diff --git a/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java b/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java index 0df8e730937..68fe71c72c0 100644 --- a/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java +++ b/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2013, 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 @@ -55,8 +55,7 @@ class DirectMethodHandle extends MethodHandle { } // Factory methods: - - static DirectMethodHandle make(Class<?> receiver, MemberName member) { + static DirectMethodHandle make(byte refKind, Class<?> receiver, MemberName member) { MethodType mtype = member.getMethodOrFieldType(); if (!member.isStatic()) { if (!member.getDeclaringClass().isAssignableFrom(receiver) || member.isConstructor()) @@ -64,8 +63,14 @@ class DirectMethodHandle extends MethodHandle { mtype = mtype.insertParameterTypes(0, receiver); } if (!member.isField()) { - LambdaForm lform = preparedLambdaForm(member); - return new DirectMethodHandle(mtype, lform, member); + if (refKind == REF_invokeSpecial) { + member = member.asSpecial(); + LambdaForm lform = preparedLambdaForm(member); + return new Special(mtype, lform, member); + } else { + LambdaForm lform = preparedLambdaForm(member); + return new DirectMethodHandle(mtype, lform, member); + } } else { LambdaForm lform = preparedFieldLambdaForm(member); if (member.isStatic()) { @@ -79,6 +84,12 @@ class DirectMethodHandle extends MethodHandle { } } } + static DirectMethodHandle make(Class<?> receiver, MemberName member) { + byte refKind = member.getReferenceKind(); + if (refKind == REF_invokeSpecial) + refKind = REF_invokeVirtual; + return make(refKind, receiver, member); + } static DirectMethodHandle make(MemberName member) { if (member.isConstructor()) return makeAllocator(member); @@ -114,6 +125,10 @@ class DirectMethodHandle extends MethodHandle { //// Implementation methods. @Override + MethodHandle viewAsType(MethodType newType) { + return new DirectMethodHandle(newType, form, member); + } + @Override @ForceInline MemberName internalMemberName() { return member; @@ -357,6 +372,21 @@ class DirectMethodHandle extends MethodHandle { ((DirectMethodHandle)mh).ensureInitialized(); } + /** This subclass represents invokespecial instructions. */ + static class Special extends DirectMethodHandle { + private Special(MethodType mtype, LambdaForm form, MemberName member) { + super(mtype, form, member); + } + @Override + boolean isInvokeSpecial() { + return true; + } + @Override + MethodHandle viewAsType(MethodType newType) { + return new Special(newType, form, member); + } + } + /** This subclass handles constructor references. */ static class Constructor extends DirectMethodHandle { final MemberName initMethod; @@ -369,6 +399,10 @@ class DirectMethodHandle extends MethodHandle { this.instanceClass = instanceClass; assert(initMethod.isResolved()); } + @Override + MethodHandle viewAsType(MethodType newType) { + return new Constructor(newType, form, member, initMethod, instanceClass); + } } /*non-public*/ static Object constructorMethod(Object mh) { @@ -395,6 +429,10 @@ class DirectMethodHandle extends MethodHandle { @Override Object checkCast(Object obj) { return fieldType.cast(obj); } + @Override + MethodHandle viewAsType(MethodType newType) { + return new Accessor(newType, form, member, fieldOffset); + } } @ForceInline @@ -434,6 +472,10 @@ class DirectMethodHandle extends MethodHandle { @Override Object checkCast(Object obj) { return fieldType.cast(obj); } + @Override + MethodHandle viewAsType(MethodType newType) { + return new StaticAccessor(newType, form, member, staticBase, staticOffset); + } } @ForceInline diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandle.java b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java index aa323eb358a..774faff5afb 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandle.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2013, 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 @@ -1250,8 +1250,6 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); /*non-public*/ MethodHandle viewAsType(MethodType newType) { // No actual conversions, just a new view of the same method. - if (!type.isViewableAs(newType)) - throw new InternalError(); return MethodHandleImpl.makePairwiseConvert(this, newType, 0); } @@ -1267,6 +1265,11 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); return null; // DMH returns DMH.member } + /*non-public*/ + boolean isInvokeSpecial() { + return false; // DMH.Special returns true + } + /*non-public*/ Object internalValues() { return null; diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java index 3cdd99cc4a1..376a0a0f552 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2013, 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 @@ -367,11 +367,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; @Override MethodHandle viewAsType(MethodType newType) { - MethodHandle mh = super.viewAsType(newType); + if (newType.lastParameterType() != type().lastParameterType()) + throw new InternalError(); + MethodHandle newTarget = asFixedArity().viewAsType(newType); // put back the varargs bit: - MethodType type = mh.type(); - int arity = type.parameterCount(); - return mh.asVarargsCollector(type.parameterType(arity-1)); + return new AsVarargsCollector(newTarget, newType, arrayType); } @Override @@ -379,6 +379,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; return asFixedArity().internalMemberName(); } + /*non-public*/ + @Override + boolean isInvokeSpecial() { + return asFixedArity().isInvokeSpecial(); + } + @Override MethodHandle bindArgument(int pos, char basicType, Object value) { diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java index ae579ab84c4..380ca59b6e1 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -32,7 +32,6 @@ import java.lang.invoke.MethodHandleNatives.Constants; */ final class MethodHandleInfo { public static final int - REF_NONE = Constants.REF_NONE, REF_getField = Constants.REF_getField, REF_getStatic = Constants.REF_getStatic, REF_putField = Constants.REF_putField, @@ -48,12 +47,17 @@ final class MethodHandleInfo { private final MethodType methodType; private final int referenceKind; - public MethodHandleInfo(MethodHandle mh) throws ReflectiveOperationException { + public MethodHandleInfo(MethodHandle mh) { MemberName mn = mh.internalMemberName(); + if (mn == null) throw new IllegalArgumentException("not a direct method handle"); this.declaringClass = mn.getDeclaringClass(); this.name = mn.getName(); - this.methodType = mn.getMethodType(); - this.referenceKind = mn.getReferenceKind(); + this.methodType = mn.getMethodOrFieldType(); + byte refKind = mn.getReferenceKind(); + if (refKind == REF_invokeSpecial && !mh.isInvokeSpecial()) + // Devirtualized method invocation is usually formally virtual. + refKind = REF_invokeVirtual; + this.referenceKind = refKind; } public Class<?> getDeclaringClass() { @@ -78,7 +82,6 @@ final class MethodHandleInfo { static String getReferenceKindString(int referenceKind) { switch (referenceKind) { - case REF_NONE: return "REF_NONE"; case REF_getField: return "getfield"; case REF_getStatic: return "getstatic"; case REF_putField: return "putfield"; diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java index e7007dd2b89..80a44ff2f35 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2013, 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 @@ -1209,7 +1209,7 @@ return mh1; checkMethod(refKind, refc, method); if (method.isMethodHandleInvoke()) return fakeMethodHandleInvoke(method); - MethodHandle mh = DirectMethodHandle.make(refc, method); + MethodHandle mh = DirectMethodHandle.make(refKind, refc, method); mh = maybeBindCaller(method, mh); mh = mh.setVarargs(method); if (doRestrict) diff --git a/jdk/test/java/lang/invoke/7087570/Test7087570.java b/jdk/test/java/lang/invoke/7087570/Test7087570.java new file mode 100644 index 00000000000..572faccdf5a --- /dev/null +++ b/jdk/test/java/lang/invoke/7087570/Test7087570.java @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2013, 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 7087570 + * @summary REF_invokeSpecial DMHs (which are unusual) get marked explicitly; tweak the MHI to use this bit + * + * @run main Test7087570 + */ + +import java.lang.invoke.*; +import java.lang.reflect.*; +import java.util.*; + +import static java.lang.invoke.MethodHandles.*; +import static java.lang.invoke.MethodType.*; + +public class Test7087570 { + // XXX may remove the following constant declarations when MethodHandleInfo is made public + private static final int + REF_getField = 1, + REF_getStatic = 2, + REF_putField = 3, + REF_putStatic = 4, + REF_invokeVirtual = 5, + REF_invokeStatic = 6, + REF_invokeSpecial = 7, + REF_newInvokeSpecial = 8, + REF_invokeInterface = 9, + REF_LIMIT = 10; + + private static final TestMethodData[] TESTS = new TestMethodData[] { + // field accessors + data(DummyFieldHolder.class, "instanceField", getterMethodType(String.class), DummyFieldHolder.class, REF_getField), + data(DummyFieldHolder.class, "instanceField", setterMethodType(String.class), DummyFieldHolder.class, REF_putField), + data(DummyFieldHolder.class, "staticField", getterMethodType(Integer.class), DummyFieldHolder.class, REF_getStatic), + data(DummyFieldHolder.class, "staticField", setterMethodType(Integer.class), DummyFieldHolder.class, REF_putStatic), + data(DummyFieldHolder.class, "instanceByteField", getterMethodType(byte.class), DummyFieldHolder.class, REF_getField), + data(DummyFieldHolder.class, "instanceByteField", setterMethodType(byte.class), DummyFieldHolder.class, REF_putField), + + // REF_invokeVirtual + data(Object.class, "hashCode", methodType(int.class), Object.class, REF_invokeVirtual), + + // REF_invokeVirtual strength-reduced to REF_invokeSpecial, + // test if it normalizes back to REF_invokeVirtual in MethodHandleInfo as expected + data(String.class, "hashCode", methodType(int.class), String.class, REF_invokeVirtual), + + // REF_invokeStatic + data(Collections.class, "sort", methodType(void.class, List.class), Collections.class, REF_invokeStatic), + data(Arrays.class, "asList", methodType(List.class, Object[].class), Arrays.class, REF_invokeStatic), // varargs case + + // REF_invokeSpecial + data(Object.class, "hashCode", methodType(int.class), Object.class, REF_invokeSpecial), + + // REF_newInvokeSpecial + data(String.class, "<init>", methodType(void.class, char[].class), String.class, REF_newInvokeSpecial), + data(DummyFieldHolder.class, "<init>", methodType(void.class, byte.class, Long[].class), DummyFieldHolder.class, REF_newInvokeSpecial), // varargs case + + // REF_invokeInterface + data(List.class, "size", methodType(int.class), List.class, REF_invokeInterface) + }; + + public static void main(String... args) throws Throwable { + testWithLookup(); + testWithUnreflect(); + } + + private static void doTest(MethodHandle mh, TestMethodData testMethod) { + Object mhi = newMethodHandleInfo(mh); + + System.out.printf("%s.%s: %s, nominal refKind: %s, actual refKind: %s\n", + testMethod.clazz.getName(), testMethod.name, testMethod.methodType, + REF_KIND_NAMES[testMethod.referenceKind], + REF_KIND_NAMES[getReferenceKind(mhi)]); + assertEquals(testMethod.name, getName(mhi)); + assertEquals(testMethod.methodType, getMethodType(mhi)); + assertEquals(testMethod.declaringClass, getDeclaringClass(mhi)); + assertEquals(testMethod.referenceKind == REF_invokeSpecial, isInvokeSpecial(mh)); + assertRefKindEquals(testMethod.referenceKind, getReferenceKind(mhi)); + } + + private static void testWithLookup() throws Throwable { + for (TestMethodData testMethod : TESTS) { + MethodHandle mh = lookupFrom(testMethod); + doTest(mh, testMethod); + } + } + + private static void testWithUnreflect() throws Throwable { + for (TestMethodData testMethod : TESTS) { + MethodHandle mh = unreflectFrom(testMethod); + doTest(mh, testMethod); + } + } + + private static MethodType getterMethodType(Class<?> clazz) { + return methodType(clazz); + } + + private static MethodType setterMethodType(Class<?> clazz) { + return methodType(void.class, clazz); + } + + private static final String[] REF_KIND_NAMES = { + "MH::invokeBasic", + "REF_getField", "REF_getStatic", "REF_putField", "REF_putStatic", + "REF_invokeVirtual", "REF_invokeStatic", "REF_invokeSpecial", + "REF_newInvokeSpecial", "REF_invokeInterface" + }; + + private static final Lookup LOOKUP = lookup(); + + // XXX may remove the following reflective logic when MethodHandleInfo is made public + private static final MethodHandle MH_IS_INVOKESPECIAL; + private static final MethodHandle MHI_CONSTRUCTOR; + private static final MethodHandle MHI_GET_NAME; + private static final MethodHandle MHI_GET_METHOD_TYPE; + private static final MethodHandle MHI_GET_DECLARING_CLASS; + private static final MethodHandle MHI_GET_REFERENCE_KIND; + + static { + try { + // This is white box testing. Use reflection to grab private implementation bits. + String magicName = "IMPL_LOOKUP"; + Field magicLookup = MethodHandles.Lookup.class.getDeclaredField(magicName); + // This unit test will fail if a security manager is installed. + magicLookup.setAccessible(true); + // Forbidden fruit... + Lookup directInvokeLookup = (Lookup) magicLookup.get(null); + Class<?> mhiClass = Class.forName("java.lang.invoke.MethodHandleInfo", false, MethodHandle.class.getClassLoader()); + MH_IS_INVOKESPECIAL = directInvokeLookup + .findVirtual(MethodHandle.class, "isInvokeSpecial", methodType(boolean.class)); + MHI_CONSTRUCTOR = directInvokeLookup + .findConstructor(mhiClass, methodType(void.class, MethodHandle.class)); + MHI_GET_NAME = directInvokeLookup + .findVirtual(mhiClass, "getName", methodType(String.class)); + MHI_GET_METHOD_TYPE = directInvokeLookup + .findVirtual(mhiClass, "getMethodType", methodType(MethodType.class)); + MHI_GET_DECLARING_CLASS = directInvokeLookup + .findVirtual(mhiClass, "getDeclaringClass", methodType(Class.class)); + MHI_GET_REFERENCE_KIND = directInvokeLookup + .findVirtual(mhiClass, "getReferenceKind", methodType(int.class)); + } catch (ReflectiveOperationException ex) { + throw new Error(ex); + } + } + + private static class TestMethodData { + final Class<?> clazz; + final String name; + final MethodType methodType; + final Class<?> declaringClass; + final int referenceKind; // the nominal refKind + + public TestMethodData(Class<?> clazz, String name, + MethodType methodType, Class<?> declaringClass, + int referenceKind) { + this.clazz = clazz; + this.name = name; + this.methodType = methodType; + this.declaringClass = declaringClass; + this.referenceKind = referenceKind; + } + } + + private static TestMethodData data(Class<?> clazz, String name, + MethodType methodType, Class<?> declaringClass, + int referenceKind) { + return new TestMethodData(clazz, name, methodType, declaringClass, referenceKind); + } + + private static MethodHandle lookupFrom(TestMethodData testMethod) + throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException { + switch (testMethod.referenceKind) { + case REF_getField: + return LOOKUP.findGetter(testMethod.clazz, testMethod.name, testMethod.methodType.returnType()); + case REF_putField: + return LOOKUP.findSetter(testMethod.clazz, testMethod.name, testMethod.methodType.parameterType(0)); + case REF_getStatic: + return LOOKUP.findStaticGetter(testMethod.clazz, testMethod.name, testMethod.methodType.returnType()); + case REF_putStatic: + return LOOKUP.findStaticSetter(testMethod.clazz, testMethod.name, testMethod.methodType.parameterType(0)); + case REF_invokeVirtual: + case REF_invokeInterface: + return LOOKUP.findVirtual(testMethod.clazz, testMethod.name, testMethod.methodType); + case REF_invokeStatic: + return LOOKUP.findStatic(testMethod.clazz, testMethod.name, testMethod.methodType); + case REF_invokeSpecial: + Class<?> thisClass = LOOKUP.lookupClass(); + return LOOKUP.findSpecial(testMethod.clazz, testMethod.name, testMethod.methodType, thisClass); + case REF_newInvokeSpecial: + return LOOKUP.findConstructor(testMethod.clazz, testMethod.methodType); + default: + throw new Error("ERROR: unexpected referenceKind in test data"); + } + } + + private static MethodHandle unreflectFrom(TestMethodData testMethod) + throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException { + switch (testMethod.referenceKind) { + case REF_getField: + case REF_getStatic: { + Field f = testMethod.clazz.getDeclaredField(testMethod.name); + return LOOKUP.unreflectGetter(f); + } + case REF_putField: + case REF_putStatic: { + Field f = testMethod.clazz.getDeclaredField(testMethod.name); + return LOOKUP.unreflectSetter(f); + } + case REF_invokeVirtual: + case REF_invokeStatic: + case REF_invokeInterface: { + Method m = testMethod.clazz.getDeclaredMethod(testMethod.name, testMethod.methodType.parameterArray()); + return LOOKUP.unreflect(m); + } + case REF_invokeSpecial: { + Method m = testMethod.clazz.getDeclaredMethod(testMethod.name, testMethod.methodType.parameterArray()); + Class<?> thisClass = LOOKUP.lookupClass(); + return LOOKUP.unreflectSpecial(m, thisClass); + } + case REF_newInvokeSpecial: { + Constructor c = testMethod.clazz.getDeclaredConstructor(testMethod.methodType.parameterArray()); + return LOOKUP.unreflectConstructor(c); + } + default: + throw new Error("ERROR: unexpected referenceKind in test data"); + } + } + + private static Object newMethodHandleInfo(MethodHandle mh) { + try { + return MHI_CONSTRUCTOR.invoke(mh); + } catch (Throwable ex) { + throw new Error(ex); + } + } + + private static boolean isInvokeSpecial(MethodHandle mh) { + try { + return (boolean) MH_IS_INVOKESPECIAL.invokeExact(mh); + } catch (Throwable ex) { + throw new Error(ex); + } + } + + private static String getName(Object mhi) { + try { + return (String) MHI_GET_NAME.invoke(mhi); + } catch (Throwable ex) { + throw new Error(ex); + } + } + + private static MethodType getMethodType(Object mhi) { + try { + return (MethodType) MHI_GET_METHOD_TYPE.invoke(mhi); + } catch (Throwable ex) { + throw new Error(ex); + } + } + + private static Class<?> getDeclaringClass(Object mhi) { + try { + return (Class<?>) MHI_GET_DECLARING_CLASS.invoke(mhi); + } catch (Throwable ex) { + throw new Error(ex); + } + } + + private static int getReferenceKind(Object mhi) { + try { + return (int) MHI_GET_REFERENCE_KIND.invoke(mhi); + } catch (Throwable ex) { + throw new Error(ex); + } + } + + private static void assertRefKindEquals(int expect, int observed) { + if (expect == observed) return; + + String msg = "expected " + REF_KIND_NAMES[(int) expect] + + " but observed " + REF_KIND_NAMES[(int) observed]; + System.out.println("FAILED: " + msg); + throw new AssertionError(msg); + } + + private static void assertEquals(Object expect, Object observed) { + if (java.util.Objects.equals(expect, observed)) return; + + String msg = "expected " + expect + " but observed " + observed; + System.out.println("FAILED: " + msg); + throw new AssertionError(msg); + } +} + +class DummyFieldHolder { + public static Integer staticField; + public String instanceField; + public byte instanceByteField; + + public DummyFieldHolder(byte unused1, Long... unused2) { + } +} + From 61e56e8ead612e72306dd14cb2d83b327f75b6b4 Mon Sep 17 00:00:00 2001 From: Erik Joelsson <erik.joelsson@oracle.com> Date: Tue, 26 Feb 2013 14:08:19 +0000 Subject: [PATCH 106/180] 8008978: nashorn-rules.gmk missing Co-authored-by: James Laskey <james.laskey@oracle.com> Reviewed-by: alanb --- make/nashorn-rules.gmk | 59 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 make/nashorn-rules.gmk diff --git a/make/nashorn-rules.gmk b/make/nashorn-rules.gmk new file mode 100644 index 00000000000..a86a0475ced --- /dev/null +++ b/make/nashorn-rules.gmk @@ -0,0 +1,59 @@ +# +# Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# 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. +# + +################################################################ +# NASHORN TARGETS +################################################################ + +NASHORN_BUILD_ARGUMENTS = \ + $(COMMON_BUILD_ARGUMENTS) \ + ALT_OUTPUTDIR=$(NASHORN_OUTPUTDIR) \ + ALT_BOOTDIR=$(BOOTDIR) \ + ALT_JDK_IMPORT_PATH=$(JDK_IMPORT_PATH) + +ifeq ($(BUILD_LANGTOOLS), true) + NASHORN_BUILD_ARGUMENTS += ALT_LANGTOOLS_DIST=$(ABS_LANGTOOLS_DIST) +endif + +# Default targets +NASHORN = nashorn-build + +nashorn: nashorn-build +nashorn-build: + $(MKDIR) -p $(NASHORN_OUTPUTDIR) + @$(call MakeStart,nashorn,all) + ($(CD) $(NASHORN_TOPDIR)/make && \ + $(MAKE) $(NASHORN_BUILD_ARGUMENTS) all) + @$(call MakeFinish,nashorn,all) + +nashorn-clobber:: + $(MKDIR) -p $(NASHORN_OUTPUTDIR) + @$(call MakeStart,nashorn,clobber) + ($(CD) $(NASHORN_TOPDIR)/make && \ + $(MAKE) $(NASHORN_BUILD_ARGUMENTS) clobber) + @$(call MakeFinish,nashorn,clobber) + +.PHONY: nashorn nashorn-build nashorn-clobber + From 8eaa894f7c13b225cd57c9b080ff798772f4836b Mon Sep 17 00:00:00 2001 From: Alan Bateman <alanb@openjdk.org> Date: Tue, 26 Feb 2013 14:16:48 +0000 Subject: [PATCH 107/180] 8008977: profiles build broken by Nashorn build changes Reviewed-by: chegar --- jdk/makefiles/profile-rtjar-includes.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/jdk/makefiles/profile-rtjar-includes.txt b/jdk/makefiles/profile-rtjar-includes.txt index 4722727ea31..4cc528e67d5 100644 --- a/jdk/makefiles/profile-rtjar-includes.txt +++ b/jdk/makefiles/profile-rtjar-includes.txt @@ -349,6 +349,7 @@ PROFILE_3_RTJAR_INCLUDE_PACKAGES := \ com/sun/rowset/providers \ com/sun/script/javascript \ com/sun/script/util \ + com/sun/security/auth \ com/sun/security/auth/callback \ com/sun/security/auth/login \ com/sun/security/auth/module \ @@ -448,8 +449,7 @@ PROFILE_3_RTJAR_INCLUDE_PACKAGES := \ sun/tracing \ sun/tracing/dtrace -PROFILE_3_RTJAR_INCLUDE_TYPES := \ - com/sun/security/auth/*.class +PROFILE_3_RTJAR_INCLUDE_TYPES := PROFILE_3_RTJAR_EXCLUDE_TYPES := \ javax/management/remote/rmi/_RMIConnectionImpl_Tie.class \ @@ -457,10 +457,10 @@ PROFILE_3_RTJAR_EXCLUDE_TYPES := \ javax/management/remote/rmi/_RMIServerImpl_Tie.class \ javax/management/remote/rmi/_RMIServer_Stub.class \ com/sun/security/auth/callback/DialogCallbackHandler.class \ - com/sun/security/auth/callback/DialogCallbackHandler\$$$$1.class \ - com/sun/security/auth/callback/DialogCallbackHandler\$$$$2.class \ - com/sun/security/auth/callback/DialogCallbackHandler\$$$$Action.class \ - com/sun/security/auth/callback/DialogCallbackHandler\$$$$ConfirmationInfo.class + com/sun/security/auth/callback/DialogCallbackHandler\$$1.class \ + com/sun/security/auth/callback/DialogCallbackHandler\$$2.class \ + com/sun/security/auth/callback/DialogCallbackHandler\$$Action.class \ + com/sun/security/auth/callback/DialogCallbackHandler\$$ConfirmationInfo.class PROFILE_3_INCLUDE_METAINF_SERVICES := \ META-INF/services/javax.script.ScriptEngineFactory From 20b2cd48901fbdbc0ae36926dc32aca81b3f1fae Mon Sep 17 00:00:00 2001 From: Tim Bell <tbell@openjdk.org> Date: Tue, 26 Feb 2013 09:25:44 -0800 Subject: [PATCH 108/180] 8009019: Updates to generated-configure.sh required for 8008914 Reviewed-by: sundar, jlaskey, jjg --- common/autoconf/generated-configure.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 00d5093259b..04bef5cadc1 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -3733,7 +3733,7 @@ fi #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1361218904 +DATE_WHEN_GENERATED=1361899489 ############################################################################### # From b0dc9de25e90f1aeef23e5a254ead3d70e32ac99 Mon Sep 17 00:00:00 2001 From: Robert Field <rfield@openjdk.org> Date: Tue, 26 Feb 2013 10:38:58 -0800 Subject: [PATCH 109/180] 8008770: SerializedLambda incorrect class loader for lambda deserializing class Current thread's context ClassLoader was used to load class by name, pass class not name in serialization (Thank you Peter Levart for test and prototype. Thank you Sundar and Peter for unofficial reviews) Reviewed-by: forax --- .../invoke/InnerClassLambdaMetafactory.java | 4 +- .../java/lang/invoke/SerializedLambda.java | 20 +-- .../LambdaClassLoaderSerialization.java | 164 ++++++++++++++++++ .../invoke/lambda/LambdaSerialization.java | 1 - 4 files changed, 170 insertions(+), 19 deletions(-) create mode 100644 jdk/test/java/lang/invoke/lambda/LambdaClassLoaderSerialization.java diff --git a/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index f2bb8ebc62c..f7191f7679f 100644 --- a/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -53,7 +53,7 @@ import java.security.PrivilegedAction; private static final String NAME_OBJECT = "java/lang/Object"; private static final String DESCR_CTOR_SERIALIZED_LAMBDA = MethodType.methodType(void.class, - String.class, + Class.class, int.class, String.class, String.class, String.class, int.class, String.class, String.class, String.class, String.class, @@ -284,7 +284,7 @@ import java.security.PrivilegedAction; mv.visitCode(); mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA); mv.visitInsn(DUP);; - mv.visitLdcInsn(targetClass.getName().replace('.', '/')); + mv.visitLdcInsn(Type.getType(targetClass)); mv.visitLdcInsn(samInfo.getReferenceKind()); mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/')); mv.visitLdcInsn(samInfo.getName()); diff --git a/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java b/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java index 1a2db3f072a..3679e3f726d 100644 --- a/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java +++ b/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java @@ -40,7 +40,7 @@ import java.util.Objects; */ public final class SerializedLambda implements Serializable { private static final long serialVersionUID = 8025925345765570181L; - private final String capturingClass; + private final Class<?> capturingClass; private final String functionalInterfaceClass; private final String functionalInterfaceMethodName; private final String functionalInterfaceMethodSignature; @@ -73,7 +73,7 @@ public final class SerializedLambda implements Serializable { * @param capturedArgs The dynamic arguments to the lambda factory site, which represent variables captured by * the lambda */ - public SerializedLambda(String capturingClass, + public SerializedLambda(Class<?> capturingClass, int functionalInterfaceMethodKind, String functionalInterfaceClass, String functionalInterfaceMethodName, @@ -99,7 +99,7 @@ public final class SerializedLambda implements Serializable { /** Get the name of the class that captured this lambda */ public String getCapturingClass() { - return capturingClass; + return capturingClass.getName().replace('.', '/'); } /** Get the name of the functional interface class to which this lambda has been converted */ @@ -166,9 +166,7 @@ public final class SerializedLambda implements Serializable { Method deserialize = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() { @Override public Method run() throws Exception { - Class<?> clazz = Class.forName(capturingClass.replace('/', '.'), true, - Thread.currentThread().getContextClassLoader()); - Method m = clazz.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class); + Method m = capturingClass.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class); m.setAccessible(true); return m; } @@ -196,14 +194,4 @@ public final class SerializedLambda implements Serializable { MethodHandleInfo.getReferenceKindString(implMethodKind), implClass, implMethodName, implMethodSignature, instantiatedMethodType, capturedArgs.length); } - - /* - // @@@ Review question: is it worthwhile implementing a versioned serialization protocol? - - private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { - } - - private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { - } -*/ } diff --git a/jdk/test/java/lang/invoke/lambda/LambdaClassLoaderSerialization.java b/jdk/test/java/lang/invoke/lambda/LambdaClassLoaderSerialization.java new file mode 100644 index 00000000000..9d38102b14a --- /dev/null +++ b/jdk/test/java/lang/invoke/lambda/LambdaClassLoaderSerialization.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2013, 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 8004970 +@summary Lambda serialization in the presence of class loaders +@author Peter Levart +*/ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Arrays; + +public class LambdaClassLoaderSerialization { + + public interface SerializableRunnable extends Runnable, Serializable {} + + public static class MyCode implements SerializableRunnable { + + private byte[] serialize(Object o) { + ByteArrayOutputStream baos; + try ( + ObjectOutputStream oos = + new ObjectOutputStream(baos = new ByteArrayOutputStream()) + ) { + oos.writeObject(o); + } + catch (IOException e) { + throw new RuntimeException(e); + } + return baos.toByteArray(); + } + + private <T> T deserialize(byte[] bytes) { + try ( + ObjectInputStream ois = + new ObjectInputStream(new ByteArrayInputStream(bytes)) + ) { + return (T) ois.readObject(); + } + catch (IOException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + @Override + public void run() { + System.out.println(" this: " + this); + + SerializableRunnable deSerializedThis = deserialize(serialize(this)); + System.out.println(" deSerializedThis: " + deSerializedThis); + + SerializableRunnable runnable = () -> {System.out.println("HELLO");}; + System.out.println(" runnable: " + runnable); + + SerializableRunnable deSerializedRunnable = deserialize(serialize(runnable)); + System.out.println("deSerializedRunnable: " + deSerializedRunnable); + } + } + + public static void main(String[] args) throws Exception { + ClassLoader myCl = new MyClassLoader( + LambdaClassLoaderSerialization.class.getClassLoader() + ); + Class<?> myCodeClass = Class.forName( + LambdaClassLoaderSerialization.class.getName() + "$MyCode", + true, + myCl + ); + Runnable myCode = (Runnable) myCodeClass.newInstance(); + myCode.run(); + } + + static class MyClassLoader extends ClassLoader { + MyClassLoader(ClassLoader parent) { + super(parent); + } + + @Override + protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { + if (name.indexOf('.') < 0) { + synchronized (getClassLoadingLock(name)) { + Class<?> c = findLoadedClass(name); + if (c == null) { + c = findClass(name); + } + if (resolve) { + resolveClass(c); + } + return c; + } + } else { + return super.loadClass(name, resolve); + } + } + + @Override + protected Class<?> findClass(String name) throws ClassNotFoundException { + String path = name.replace('.', '/').concat(".class"); + try (InputStream is = getResourceAsStream(path)) { + if (is != null) { + byte[] bytes = readFully(is); + return defineClass(name, bytes, 0, bytes.length); + } else { + throw new ClassNotFoundException(name); + } + } + catch (IOException e) { + throw new ClassNotFoundException(name, e); + } + } + + static byte[] readFully(InputStream is) throws IOException { + byte[] output = {}; + int pos = 0; + while (true) { + int bytesToRead; + if (pos >= output.length) { // Only expand when there's no room + bytesToRead = output.length + 1024; + if (output.length < pos + bytesToRead) { + output = Arrays.copyOf(output, pos + bytesToRead); + } + } else { + bytesToRead = output.length - pos; + } + int cc = is.read(output, pos, bytesToRead); + if (cc < 0) { + if (output.length != pos) { + output = Arrays.copyOf(output, pos); + } + break; + } + pos += cc; + } + return output; + } + } +} diff --git a/jdk/test/java/lang/invoke/lambda/LambdaSerialization.java b/jdk/test/java/lang/invoke/lambda/LambdaSerialization.java index ebe846b173e..6d681c35a66 100644 --- a/jdk/test/java/lang/invoke/lambda/LambdaSerialization.java +++ b/jdk/test/java/lang/invoke/lambda/LambdaSerialization.java @@ -25,7 +25,6 @@ @test @bug 8004970 @summary Lambda serialization -@run main/othervm LambdaSerialization */ import java.io.*; From 18e1157d3b503b95087723b1475cb0ba624c190b Mon Sep 17 00:00:00 2001 From: Alan Bateman <alanb@openjdk.org> Date: Tue, 26 Feb 2013 22:39:50 +0000 Subject: [PATCH 110/180] 8009029: SunEC provider classes ending up in rt.jar after Nashorn build changes Reviewed-by: mduigou --- jdk/makefiles/CreateJars.gmk | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/jdk/makefiles/CreateJars.gmk b/jdk/makefiles/CreateJars.gmk index 857e0d5e9a4..82b85dc97f3 100644 --- a/jdk/makefiles/CreateJars.gmk +++ b/jdk/makefiles/CreateJars.gmk @@ -213,28 +213,28 @@ RT_JAR_EXCLUDES += \ org/relaxng/datatype \ sun/awt/HKSCS.class \ sun/awt/motif/X11GB2312.class \ - sun/awt/motif/X11GB2312\$$$$Decoder.class \ - sun/awt/motif/X11GB2312\$$$$Encoder.class \ + sun/awt/motif/X11GB2312\$$Decoder.class \ + sun/awt/motif/X11GB2312\$$Encoder.class \ sun/awt/motif/X11GBK.class \ - sun/awt/motif/X11GBK\$$$$Encoder.class \ + sun/awt/motif/X11GBK\$$Encoder.class \ sun/awt/motif/X11KSC5601.class \ - sun/awt/motif/X11KSC5601\$$$$Decoder.class \ - sun/awt/motif/X11KSC5601\$$$$Encoder.class \ + sun/awt/motif/X11KSC5601\$$Decoder.class \ + sun/awt/motif/X11KSC5601\$$Encoder.class \ sun/jvmstat \ sun/net/spi/nameservice/dns \ sun/nio/cs/ext \ sun/rmi/rmic \ sun/security/ec/ECDHKeyAgreement.class \ sun/security/ec/ECDSASignature.class \ - sun/security/ec/ECDSASignature\$$$$Raw.class \ - sun/security/ec/ECDSASignature\$$$$SHA1.class \ - sun/security/ec/ECDSASignature\$$$$SHA224.class \ - sun/security/ec/ECDSASignature\$$$$SHA256.class \ - sun/security/ec/ECDSASignature\$$$$SHA384.class \ - sun/security/ec/ECDSASignature\$$$$SHA512.class \ + sun/security/ec/ECDSASignature\$$Raw.class \ + sun/security/ec/ECDSASignature\$$SHA1.class \ + sun/security/ec/ECDSASignature\$$SHA224.class \ + sun/security/ec/ECDSASignature\$$SHA256.class \ + sun/security/ec/ECDSASignature\$$SHA384.class \ + sun/security/ec/ECDSASignature\$$SHA512.class \ sun/security/ec/ECKeyFactory.class \ sun/security/ec/ECKeyPairGenerator.class \ - sun/security/ec/SunEC\$$$$1.class \ + sun/security/ec/SunEC\$$1.class \ sun/security/ec/SunEC.class \ sun/security/ec/SunECEntries.class \ sun/security/internal \ From a26b355e8b589745204fa0d21486428af22ca725 Mon Sep 17 00:00:00 2001 From: Joe Darcy <darcy@openjdk.org> Date: Tue, 26 Feb 2013 17:01:04 -0800 Subject: [PATCH 111/180] 8009102: Several docs warnings in Project Lambda APIs Reviewed-by: mduigou --- .../java/lang/invoke/LambdaMetafactory.java | 19 +++---------------- .../java/util/function/BinaryOperator.java | 2 +- .../util/function/ToDoubleBiFunction.java | 2 +- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java b/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java index 24c0c72c71c..d179d438e8a 100644 --- a/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java +++ b/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -220,24 +220,11 @@ public class LambdaMetafactory { * of the caller. * @param invokedName Stacked automatically by VM; the name of the invoked method as it appears at the call site. * Currently unused. - * @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the + * @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes thefu * expected static type of the returned lambda object, and the static types of the captured * arguments for the lambda. In the event that the implementation method is an instance method, * the first argument in the invocation signature will correspond to the receiver. - * @param samMethod The primary method in the functional interface to which the lambda or method reference is - * being converted, represented as a method handle. - * @param implMethod The implementation method which should be called (with suitable adaptation of argument - * types, return types, and adjustment for captured arguments) when methods of the resulting - * functional interface instance are invoked. - * @param instantiatedMethodType The signature of the primary functional interface method after type variables - * are substituted with their instantiation from the capture site - * @param flags A bitmask containing flags that may influence the translation of this lambda expression. Defined - * fields include FLAG_SERIALIZABLE and FLAG_MARKERS. - * @param markerInterfaceCount If the FLAG_MARKERS flag is set, this is a count of the number of additional - * marker interfaces - * @param markerInterfaces If the FLAG_MARKERS flag is set, this consists of Class objects identifying additional - * marker interfaces which the lambda object should implement, whose count equals - * markerInterfaceCount + * @param args argument to pass, flags, marker interface count, and marker interfaces as described above * @return a CallSite, which, when invoked, will return an instance of the functional interface * @throws ReflectiveOperationException * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated diff --git a/jdk/src/share/classes/java/util/function/BinaryOperator.java b/jdk/src/share/classes/java/util/function/BinaryOperator.java index 5f1d5a41d83..e81bce8c553 100644 --- a/jdk/src/share/classes/java/util/function/BinaryOperator.java +++ b/jdk/src/share/classes/java/util/function/BinaryOperator.java @@ -30,7 +30,7 @@ package java.util.function; * * @param <T> the type of operands to {@code apply} and of the result * - * @see BiFunction. + * @see BiFunction * @since 1.8 */ @FunctionalInterface diff --git a/jdk/src/share/classes/java/util/function/ToDoubleBiFunction.java b/jdk/src/share/classes/java/util/function/ToDoubleBiFunction.java index df299aa58d7..8826e12dad7 100644 --- a/jdk/src/share/classes/java/util/function/ToDoubleBiFunction.java +++ b/jdk/src/share/classes/java/util/function/ToDoubleBiFunction.java @@ -33,7 +33,7 @@ package java.util.function; * @param <U> the type of the second argument to the {@code applyAsDouble} * operation. * - * @see BiFunction. + * @see BiFunction * @since 1.8 */ @FunctionalInterface From 1caebc408da0517842f79a6304c96b1322242718 Mon Sep 17 00:00:00 2001 From: Joe Darcy <darcy@openjdk.org> Date: Tue, 26 Feb 2013 17:38:29 -0800 Subject: [PATCH 112/180] 8008279: Remove InvalidContainerAnnotationError.java Reviewed-by: jfranck --- .../InvalidContainerAnnotationError.java | 128 ------------------ .../java/lang/reflect/AnnotatedElement.java | 8 +- .../reflect/annotation/AnnotationSupport.java | 16 +-- 3 files changed, 10 insertions(+), 142 deletions(-) delete mode 100644 jdk/src/share/classes/java/lang/annotation/InvalidContainerAnnotationError.java diff --git a/jdk/src/share/classes/java/lang/annotation/InvalidContainerAnnotationError.java b/jdk/src/share/classes/java/lang/annotation/InvalidContainerAnnotationError.java deleted file mode 100644 index 37d00a98b40..00000000000 --- a/jdk/src/share/classes/java/lang/annotation/InvalidContainerAnnotationError.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package java.lang.annotation; - -import java.util.Objects; - -/** - * Thrown to indicate that an annotation type expected to act as a - * container for another annotation type by virture of an @Repeatable - * annotation, does not act as a container. - * - * @see java.lang.reflect.AnnotatedElement - * @since 1.8 - * @jls 9.6 Annotation Types - * @jls 9.7 Annotations - */ -public class InvalidContainerAnnotationError extends AnnotationFormatError { - private static final long serialVersionUID = 5023L; - - /** - * The instance of the erroneous container. - */ - private transient Annotation container; - - /** - * The type of the annotation that should be contained in the - * container. - */ - private transient Class<? extends Annotation> annotationType; - - /** - * Constructs a new InvalidContainerAnnotationError with the - * specified detail message. - * - * @param message the detail message. - */ - public InvalidContainerAnnotationError(String message) { - super(message); - } - - /** - * Constructs a new InvalidContainerAnnotationError with the specified - * detail message and cause. Note that the detail message associated - * with {@code cause} is <i>not</i> automatically incorporated in - * this error's detail message. - * - * @param message the detail message - * @param cause the cause, may be {@code null} - */ - public InvalidContainerAnnotationError(String message, Throwable cause) { - super(message, cause); - } - - /** - * Constructs a new InvalidContainerAnnotationError with the - * specified cause and a detail message of {@code (cause == null ? - * null : cause.toString())} (which typically contains the class - * and detail message of {@code cause}). - * - * @param cause the cause, may be {@code null} - */ - public InvalidContainerAnnotationError(Throwable cause) { - super(cause); - } - - /** - * Constructs InvalidContainerAnnotationError for the specified - * container instance and contained annotation type. - * - * @param message the detail message - * @param cause the cause, may be {@code null} - * @param container the erroneous container instance, may be - * {@code null} - * @param annotationType the annotation type intended to be - * contained, may be {@code null} - */ - public InvalidContainerAnnotationError(String message, - Throwable cause, - Annotation container, - Class<? extends Annotation> annotationType) { - super(message, cause); - this.container = container; - this.annotationType = annotationType; - } - - /** - * Returns the erroneous container. - * - * @return the erroneous container, may return {@code null} - */ - public Annotation getContainer() { - return container; - } - - /** - * Returns the annotation type intended to be contained. Returns - * {@code null} if the annotation type intended to be contained - * could not be determined. - * - * @return the annotation type intended to be contained, or {@code - * null} if unknown - */ - public Class<? extends Annotation> getAnnotationType() { - return annotationType; - } -} diff --git a/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java b/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java index d6cffec2f28..b2c43de3d7b 100644 --- a/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java @@ -26,6 +26,7 @@ package java.lang.reflect; import java.lang.annotation.Annotation; +import java.lang.annotation.AnnotationFormatError; /** * Represents an annotated element of the program currently running in this @@ -86,8 +87,8 @@ import java.lang.annotation.Annotation; * * <p>Attempting to read annotations of a repeatable annotation type T * that are contained in an annotation whose type is not, in fact, the - * containing annotation type of T will result in an - * InvalidContainerAnnotationError. + * containing annotation type of T, will result in an {@link + * AnnotationFormatError}. * * <p>Finally, attempting to read a member whose definition has evolved * incompatibly will result in a {@link @@ -96,10 +97,9 @@ import java.lang.annotation.Annotation; * * @see java.lang.EnumConstantNotPresentException * @see java.lang.TypeNotPresentException - * @see java.lang.annotation.AnnotationFormatError + * @see AnnotationFormatError * @see java.lang.annotation.AnnotationTypeMismatchException * @see java.lang.annotation.IncompleteAnnotationException - * @see java.lang.annotation.InvalidContainerAnnotationError * @since 1.5 * @author Josh Bloch */ diff --git a/jdk/src/share/classes/sun/reflect/annotation/AnnotationSupport.java b/jdk/src/share/classes/sun/reflect/annotation/AnnotationSupport.java index 5ca88f90202..ed1443a5c5a 100644 --- a/jdk/src/share/classes/sun/reflect/annotation/AnnotationSupport.java +++ b/jdk/src/share/classes/sun/reflect/annotation/AnnotationSupport.java @@ -86,11 +86,11 @@ public final class AnnotationSupport { Class<? extends Annotation> containerClass = containerInstance.annotationType(); AnnotationType annoType = AnnotationType.getInstance(containerClass); if (annoType == null) - throw new InvalidContainerAnnotationError(containerInstance + " is an invalid container for repeating annotations"); + throw new AnnotationFormatError(containerInstance + " is an invalid container for repeating annotations"); Method m = annoType.members().get("value"); if (m == null) - throw new InvalidContainerAnnotationError(containerInstance + + throw new AnnotationFormatError(containerInstance + " is an invalid container for repeating annotations"); m.setAccessible(true); @@ -103,11 +103,9 @@ public final class AnnotationSupport { IllegalArgumentException | // parameters doesn't match InvocationTargetException | // the value method threw an exception ClassCastException e) { // well, a cast failed ... - throw new InvalidContainerAnnotationError( + throw new AnnotationFormatError( containerInstance + " is an invalid container for repeating annotations", - e, - containerInstance, - null); + e); } } @@ -129,12 +127,10 @@ public final class AnnotationSupport { return l; } catch (ClassCastException | NullPointerException e) { - throw new InvalidContainerAnnotationError( + throw new AnnotationFormatError( String.format("%s is an invalid container for repeating annotations of type: %s", containerInstance, annotationClass), - e, - containerInstance, - annotationClass); + e); } } } From b097b0d23423f887bd5ef2f3a19e28c50fad62dc Mon Sep 17 00:00:00 2001 From: Denis Fokin <denis@openjdk.org> Date: Wed, 27 Feb 2013 19:38:36 +0400 Subject: [PATCH 113/180] 7178079: REGRESSION: Some AWT Drag-n-Drop tests fail since JDK 7u6 b13 Reviewed-by: serb, anthony --- .../classes/sun/lwawt/macosx/CDropTargetContextPeer.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CDropTargetContextPeer.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CDropTargetContextPeer.java index 181d0847225..0f32d3178fd 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CDropTargetContextPeer.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CDropTargetContextPeer.java @@ -128,6 +128,15 @@ final class CDropTargetContextPeer extends SunDropTargetContextPeer { } } + @Override + protected int postDropTargetEvent(Component component, int x, int y, int dropAction, + int actions, long[] formats, long nativeCtxt, int eventID, + boolean dispatchType) { + // On MacOS X all the DnD events should be synchronous + return super.postDropTargetEvent(component, x, y, dropAction, actions, formats, nativeCtxt, + eventID, SunDropTargetContextPeer.DISPATCH_SYNC); + } + // Signal drop complete: protected void doDropDone(boolean success, int dropAction, boolean isLocal) { long nativeDropTarget = this.getNativeDragContext(); From e19091b0b1943c67c5ac538e05ae0db133a59e5e Mon Sep 17 00:00:00 2001 From: Denis Fokin <denis@openjdk.org> Date: Wed, 27 Feb 2013 20:34:04 +0400 Subject: [PATCH 114/180] 8009158: Incomplete fix for 7178079 Reviewed-by: serb, anthony --- jdk/src/share/classes/sun/awt/dnd/SunDropTargetContextPeer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/share/classes/sun/awt/dnd/SunDropTargetContextPeer.java b/jdk/src/share/classes/sun/awt/dnd/SunDropTargetContextPeer.java index 302a6dbc62e..360bb9a63a6 100644 --- a/jdk/src/share/classes/sun/awt/dnd/SunDropTargetContextPeer.java +++ b/jdk/src/share/classes/sun/awt/dnd/SunDropTargetContextPeer.java @@ -498,7 +498,7 @@ public abstract class SunDropTargetContextPeer implements DropTargetContextPeer, postDropTargetEvent(component, x, y, dropAction, actions, formats, nativeCtxt, SunDropTargetEvent.MOUSE_DROPPED, - SunDropTargetContextPeer.DISPATCH_SYNC); + !SunDropTargetContextPeer.DISPATCH_SYNC); } /** From 526214260178077be6a0bedac46f66f1ea147c5d Mon Sep 17 00:00:00 2001 From: Mike Duigou <mduigou@openjdk.org> Date: Wed, 27 Feb 2013 11:00:20 -0800 Subject: [PATCH 115/180] 8008785: IdentityHashMap.values().toArray(V[]) broken by JDK-8008167 Reviewed-by: alanb --- .../classes/java/util/IdentityHashMap.java | 4 +- jdk/test/java/util/Map/ToArray.java | 187 ++++++++++++++++++ 2 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 jdk/test/java/util/Map/ToArray.java diff --git a/jdk/src/share/classes/java/util/IdentityHashMap.java b/jdk/src/share/classes/java/util/IdentityHashMap.java index f05bd144e04..49bb9943ff6 100644 --- a/jdk/src/share/classes/java/util/IdentityHashMap.java +++ b/jdk/src/share/classes/java/util/IdentityHashMap.java @@ -1106,12 +1106,12 @@ public class IdentityHashMap<K,V> Object[] tab = table; int ti = 0; for (int si = 0; si < tab.length; si += 2) { - if (tab[si++] != null) { // key present ? + if (tab[si] != null) { // key present ? // more elements than expected -> concurrent modification from other thread if (ti >= size) { throw new ConcurrentModificationException(); } - a[ti++] = (T) tab[si]; // copy value + a[ti++] = (T) tab[si+1]; // copy value } } // fewer elements than expected or concurrent modification from other thread detected diff --git a/jdk/test/java/util/Map/ToArray.java b/jdk/test/java/util/Map/ToArray.java new file mode 100644 index 00000000000..f7a8de716cf --- /dev/null +++ b/jdk/test/java/util/Map/ToArray.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2013, 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 8008785 + * @summary Ensure toArray() implementations return correct results. + * @author Mike Duigou + */ +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListMap; + +public class ToArray { + + /** + * Number of elements per map. + */ + private static final int TEST_SIZE = 5000; + + private static void realMain(String[] args) throws Throwable { + Map<Integer, Long>[] maps = (Map<Integer, Long>[]) new Map[]{ + new HashMap<>(), + new Hashtable<>(), + new IdentityHashMap<>(), + new LinkedHashMap<>(), + new TreeMap<>(), + new WeakHashMap<>(), + new ConcurrentHashMap<>(), + new ConcurrentSkipListMap<>() + }; + + // for each map type. + for (Map<Integer, Long> map : maps) { + try { + testMap(map); + } catch(Exception all) { + unexpected("Failed for " + map.getClass().getName(), all); + } + } + } + + private static final Integer[] KEYS = new Integer[TEST_SIZE]; + + private static final Long[] VALUES = new Long[TEST_SIZE]; + + static { + for (int each = 0; each < TEST_SIZE; each++) { + KEYS[each] = Integer.valueOf(each); + VALUES[each] = Long.valueOf(each + TEST_SIZE); + } + } + + + private static void testMap(Map<Integer, Long> map) { + System.out.println("Testing " + map.getClass()); + System.out.flush(); + + // Fill the map + for (int each = 0; each < TEST_SIZE; each++) { + map.put(KEYS[each], VALUES[each]); + } + + // check the keys + Object[] keys = map.keySet().toArray(); + Arrays.sort(keys); + + for(int each = 0; each < TEST_SIZE; each++) { + check( "unexpected key", keys[each] == KEYS[each]); + } + + // check the values + Object[] values = map.values().toArray(); + Arrays.sort(values); + + for(int each = 0; each < TEST_SIZE; each++) { + check( "unexpected value", values[each] == VALUES[each]); + } + + // check the entries + Map.Entry<Integer,Long>[] entries = map.entrySet().toArray(new Map.Entry[TEST_SIZE]); + Arrays.sort( entries,new Comparator<Map.Entry<Integer,Long>>() { + public int compare(Map.Entry<Integer,Long> o1, Map.Entry<Integer,Long> o2) { + return o1.getKey().compareTo(o2.getKey()); + }}); + + for(int each = 0; each < TEST_SIZE; each++) { + check( "unexpected entry", entries[each].getKey() == KEYS[each] && entries[each].getValue() == VALUES[each]); + } + } + + //--------------------- Infrastructure --------------------------- + static volatile int passed = 0, failed = 0; + + static void pass() { + passed++; + } + + static void fail() { + failed++; + (new Error("Failure")).printStackTrace(System.err); + } + + static void fail(String msg) { + failed++; + (new Error("Failure: " + msg)).printStackTrace(System.err); + } + + static void abort() { + fail(); + System.exit(1); + } + + static void abort(String msg) { + fail(msg); + System.exit(1); + } + + static void unexpected(String msg, Throwable t) { + System.err.println("Unexpected: " + msg); + unexpected(t); + } + + static void unexpected(Throwable t) { + failed++; + t.printStackTrace(System.err); + } + + static void check(boolean cond) { + if (cond) { + pass(); + } else { + fail(); + } + } + + static void check(String desc, boolean cond) { + if (cond) { + pass(); + } else { + fail(desc); + } + } + + static void equal(Object x, Object y) { + if (Objects.equals(x, y)) { + pass(); + } else { + fail(x + " not equal to " + y); + } + } + + public static void main(String[] args) throws Throwable { + Thread.currentThread().setName(ToArray.class.getName()); +// Thread.currentThread().setPriority(Thread.MAX_PRIORITY); + try { + realMain(args); + } catch (Throwable t) { + unexpected(t); + } + + System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); + if (failed > 0) { + throw new Error("Some tests failed"); + } + } +} From e161c78dc39ea4dff8b93e495ae6ecdb1f707bf5 Mon Sep 17 00:00:00 2001 From: Chris Hegarty <chegar@openjdk.org> Date: Thu, 28 Feb 2013 12:39:29 +0000 Subject: [PATCH 116/180] 8006409: ThreadLocalRandom should dropping padding fields from its serialized form Reviewed-by: dl, martin, alanb, shade --- .../util/concurrent/ThreadLocalRandom.java | 78 +++++++------------ 1 file changed, 30 insertions(+), 48 deletions(-) diff --git a/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java b/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java index 08c870f0c22..c19d5128574 100644 --- a/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java +++ b/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java @@ -83,22 +83,20 @@ public class ThreadLocalRandom extends Random { * programs. * * Because this class is in a different package than class Thread, - * field access methods must use Unsafe to bypass access control - * rules. The base functionality of Random methods is - * conveniently isolated in method next(bits), that just reads and - * writes the Thread field rather than its own field. However, to - * conform to the requirements of the Random constructor, during - * construction, the common static ThreadLocalRandom must maintain - * initialization and value fields, mainly for the sake of - * disabling user calls to setSeed while still allowing a call - * from constructor. For serialization compatibility, these - * fields are left with the same declarations as used in the - * previous ThreadLocal-based version of this class, that used - * them differently. Note that serialization is completely - * unnecessary because there is only a static singleton. But these - * mechanics still ensure compatibility across versions. + * field access methods use Unsafe to bypass access control rules. + * The base functionality of Random methods is conveniently + * isolated in method next(bits), that just reads and writes the + * Thread field rather than its own field. However, to conform to + * the requirements of the Random superclass constructor, the + * common static ThreadLocalRandom maintains an "initialized" + * field for the sake of rejecting user calls to setSeed while + * still allowing a call from constructor. Note that + * serialization is completely unnecessary because there is only a + * static singleton. But we generate a serial form containing + * "rnd" and "initialized" fields to ensure compatibility across + * versions. * - * Per-instance initialization is similar to that in the no-arg + * Per-thread initialization is similar to that in the no-arg * Random constructor, but we avoid correlation among not only * initial seeds of those created in different threads, but also * those created using class Random itself; while at the same time @@ -132,10 +130,11 @@ public class ThreadLocalRandom extends Random { private static final ThreadLocal<Double> nextLocalGaussian = new ThreadLocal<Double>(); - /* - * Field used only during singleton initialization + /** + * Field used only during singleton initialization. + * True when constructor completes. */ - boolean initialized; // true when constructor completes + boolean initialized; /** Constructor used only for static singleton */ private ThreadLocalRandom() { @@ -184,7 +183,8 @@ public class ThreadLocalRandom extends Random { * @throws UnsupportedOperationException always */ public void setSeed(long seed) { - if (initialized) // allow call from super() constructor + // only allow call from super() constructor + if (initialized) throw new UnsupportedOperationException(); } @@ -357,39 +357,29 @@ public class ThreadLocalRandom extends Random { r ^= r >>> 17; r ^= r << 5; } - else if ((r = (int)UNSAFE.getLong(t, SEED)) == 0) - r = 1; // avoid zero + else { + localInit(); + if ((r = (int)UNSAFE.getLong(t, SEED)) == 0) + r = 1; // avoid zero + } UNSAFE.putInt(t, SECONDARY, r); return r; } - // Serialization support, maintains original persistent form. + // Serialization support private static final long serialVersionUID = -5851777807851030925L; /** * @serialField rnd long + * seed for random computations * @serialField initialized boolean - * @serialField pad0 long - * @serialField pad1 long - * @serialField pad2 long - * @serialField pad3 long - * @serialField pad4 long - * @serialField pad5 long - * @serialField pad6 long - * @serialField pad7 long + * always true */ private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("rnd", long.class), - new ObjectStreamField("initialized", boolean.class), - new ObjectStreamField("pad0", long.class), - new ObjectStreamField("pad1", long.class), - new ObjectStreamField("pad2", long.class), - new ObjectStreamField("pad3", long.class), - new ObjectStreamField("pad4", long.class), - new ObjectStreamField("pad5", long.class), - new ObjectStreamField("pad6", long.class), - new ObjectStreamField("pad7", long.class) }; + new ObjectStreamField("initialized", boolean.class) + }; /** * Saves the {@code ThreadLocalRandom} to a stream (that is, serializes it). @@ -398,16 +388,8 @@ public class ThreadLocalRandom extends Random { throws java.io.IOException { java.io.ObjectOutputStream.PutField fields = out.putFields(); - fields.put("rnd", 0L); + fields.put("rnd", UNSAFE.getLong(Thread.currentThread(), SEED)); fields.put("initialized", true); - fields.put("pad0", 0L); - fields.put("pad1", 0L); - fields.put("pad2", 0L); - fields.put("pad3", 0L); - fields.put("pad4", 0L); - fields.put("pad5", 0L); - fields.put("pad6", 0L); - fields.put("pad7", 0L); out.writeFields(); } From f5f12c7995f0cca756485456826479f0af899c55 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov <serb@openjdk.org> Date: Thu, 28 Feb 2013 17:04:19 +0400 Subject: [PATCH 117/180] 8008660: Failure in 2D Queue Flusher thread on Mac Reviewed-by: swingler, bae --- .../classes/sun/awt/CGraphicsConfig.java | 2 +- .../classes/sun/awt/CGraphicsDevice.java | 9 +++-- .../sun/java2d/opengl/CGLGraphicsConfig.java | 29 ++++++++-------- .../classes/sun/lwawt/macosx/CRobot.java | 8 ++--- .../classes/sun/lwawt/macosx/LWCToolkit.java | 2 +- jdk/src/macosx/native/sun/awt/CRobot.m | 4 +-- jdk/src/macosx/native/sun/awt/LWCToolkit.h | 2 -- jdk/src/macosx/native/sun/awt/LWCToolkit.m | 33 ------------------- .../sun/java2d/opengl/CGLGraphicsConfig.m | 26 +++------------ 9 files changed, 32 insertions(+), 83 deletions(-) diff --git a/jdk/src/macosx/classes/sun/awt/CGraphicsConfig.java b/jdk/src/macosx/classes/sun/awt/CGraphicsConfig.java index fb37d01209c..055af2edb22 100644 --- a/jdk/src/macosx/classes/sun/awt/CGraphicsConfig.java +++ b/jdk/src/macosx/classes/sun/awt/CGraphicsConfig.java @@ -53,7 +53,7 @@ public abstract class CGraphicsConfig extends GraphicsConfiguration @Override public Rectangle getBounds() { - final Rectangle2D nativeBounds = nativeGetBounds(device.getCoreGraphicsScreen()); + final Rectangle2D nativeBounds = nativeGetBounds(device.getCGDisplayID()); return nativeBounds.getBounds(); // does integer rounding } diff --git a/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java b/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java index bcb24ea46f7..c4786eebcce 100644 --- a/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java +++ b/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java @@ -25,11 +25,11 @@ package sun.awt; +import java.awt.AWTPermission; +import java.awt.DisplayMode; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.Window; -import java.awt.AWTPermission; -import java.awt.DisplayMode; import java.util.Objects; import sun.java2d.opengl.CGLGraphicsConfig; @@ -58,9 +58,12 @@ public final class CGraphicsDevice extends GraphicsDevice { } /** + * Returns CGDirectDisplayID, which is the same id as @"NSScreenNumber" in + * NSScreen. + * * @return CoreGraphics display id. */ - public int getCoreGraphicsScreen() { + public int getCGDisplayID() { return displayID; } diff --git a/jdk/src/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java b/jdk/src/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java index 230f7057927..c8539a8e3f6 100644 --- a/jdk/src/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java +++ b/jdk/src/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java @@ -80,10 +80,8 @@ public final class CGLGraphicsConfig extends CGraphicsConfig private ContextCapabilities oglCaps; private OGLContext context; private final Object disposerReferent = new Object(); - - public static native int getDefaultPixFmt(int screennum); private static native boolean initCGL(); - private static native long getCGLConfigInfo(int screennum, int visualnum, + private static native long getCGLConfigInfo(int displayID, int visualnum, int swapInterval); private static native int getOGLCapabilities(long configInfo); @@ -137,15 +135,16 @@ public final class CGLGraphicsConfig extends CGraphicsConfig // Java-level context and flush the queue... OGLContext.invalidateCurrentContext(); - cfginfo = getCGLConfigInfo(device.getCoreGraphicsScreen(), pixfmt, + cfginfo = getCGLConfigInfo(device.getCGDisplayID(), pixfmt, kOpenGLSwapInterval); - - OGLContext.setScratchSurface(cfginfo); - rq.flushAndInvokeNow(new Runnable() { - public void run() { - ids[0] = OGLContext.getOGLIdString(); - } - }); + if (cfginfo != 0L) { + OGLContext.setScratchSurface(cfginfo); + rq.flushAndInvokeNow(new Runnable() { + public void run() { + ids[0] = OGLContext.getOGLIdString(); + } + }); + } } finally { rq.unlock(); } @@ -253,8 +252,8 @@ public final class CGLGraphicsConfig extends CGraphicsConfig @Override public String toString() { - int screen = getDevice().getCoreGraphicsScreen(); - return ("CGLGraphicsConfig[dev="+screen+",pixfmt="+pixfmt+"]"); + int displayID = getDevice().getCGDisplayID(); + return ("CGLGraphicsConfig[dev="+displayID+",pixfmt="+pixfmt+"]"); } @Override @@ -413,8 +412,8 @@ public final class CGLGraphicsConfig extends CGraphicsConfig @Override public void addDeviceEventListener(AccelDeviceEventListener l) { - int screen = getDevice().getCoreGraphicsScreen(); - AccelDeviceEventNotifier.addListener(l, screen); + int displayID = getDevice().getCGDisplayID(); + AccelDeviceEventNotifier.addListener(l, displayID); } @Override diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CRobot.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CRobot.java index e04a45fd579..c74a589a328 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CRobot.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CRobot.java @@ -65,7 +65,7 @@ class CRobot implements RobotPeer { mouseLastX = x; mouseLastY = y; - mouseEvent(fDevice.getCoreGraphicsScreen(), mouseLastX, mouseLastY, + mouseEvent(fDevice.getCGDisplayID(), mouseLastX, mouseLastY, mouseButtonsState, true, true); } @@ -79,7 +79,7 @@ class CRobot implements RobotPeer { public void mousePress(int buttons) { mouseButtonsState |= buttons; - mouseEvent(fDevice.getCoreGraphicsScreen(), mouseLastX, mouseLastY, + mouseEvent(fDevice.getCGDisplayID(), mouseLastX, mouseLastY, buttons, true, false); } @@ -93,7 +93,7 @@ class CRobot implements RobotPeer { public void mouseRelease(int buttons) { mouseButtonsState &= ~buttons; - mouseEvent(fDevice.getCoreGraphicsScreen(), mouseLastX, mouseLastY, + mouseEvent(fDevice.getCGDisplayID(), mouseLastX, mouseLastY, buttons, false, false); } @@ -163,7 +163,7 @@ class CRobot implements RobotPeer { } private native void initRobot(); - private native void mouseEvent(int screen, int lastX, int lastY, + private native void mouseEvent(int displayID, int lastX, int lastY, int buttonsState, boolean isButtonsDownState, boolean isMouseMove); diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java index 83bc9f1f700..579468601e2 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java @@ -352,7 +352,7 @@ public final class LWCToolkit extends LWToolkit { @Override public Insets getScreenInsets(final GraphicsConfiguration gc) { final CGraphicsConfig cgc = (CGraphicsConfig) gc; - final int displayId = cgc.getDevice().getCoreGraphicsScreen(); + final int displayId = cgc.getDevice().getCGDisplayID(); Rectangle fullScreen, workArea; final long screen = CWrapper.NSScreen.screenByDisplayId(displayId); try { diff --git a/jdk/src/macosx/native/sun/awt/CRobot.m b/jdk/src/macosx/native/sun/awt/CRobot.m index c04d5685a56..056fd19e29f 100644 --- a/jdk/src/macosx/native/sun/awt/CRobot.m +++ b/jdk/src/macosx/native/sun/awt/CRobot.m @@ -135,7 +135,7 @@ Java_sun_lwawt_macosx_CRobot_initRobot JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CRobot_mouseEvent (JNIEnv *env, jobject peer, - jint screenIndex, jint mouseLastX, jint mouseLastY, jint buttonsState, + jint displayID, jint mouseLastX, jint mouseLastY, jint buttonsState, jboolean isButtonsDownState, jboolean isMouseMove) { JNF_COCOA_ENTER(env); @@ -149,8 +149,6 @@ Java_sun_lwawt_macosx_CRobot_mouseEvent CGError err = kCGErrorSuccess; - CGDirectDisplayID displayID = - FindCGDirectDisplayIDForScreenIndex(screenIndex); CGRect globalDeviceBounds = CGDisplayBounds(displayID); // Set unknown mouse location, if needed. diff --git a/jdk/src/macosx/native/sun/awt/LWCToolkit.h b/jdk/src/macosx/native/sun/awt/LWCToolkit.h index c318421c2e1..8df2c553996 100644 --- a/jdk/src/macosx/native/sun/awt/LWCToolkit.h +++ b/jdk/src/macosx/native/sun/awt/LWCToolkit.h @@ -44,8 +44,6 @@ extern jint* gButtonDownMasks; + (void) eventCountPlusPlus; @end -CGDirectDisplayID FindCGDirectDisplayIDForScreenIndex(jint screenIndex); - /* * Utility Macros */ diff --git a/jdk/src/macosx/native/sun/awt/LWCToolkit.m b/jdk/src/macosx/native/sun/awt/LWCToolkit.m index ec4870eba69..47c72abbfa5 100644 --- a/jdk/src/macosx/native/sun/awt/LWCToolkit.m +++ b/jdk/src/macosx/native/sun/awt/LWCToolkit.m @@ -177,39 +177,6 @@ Java_sun_lwawt_macosx_LWCToolkit_beep NSBeep(); // produces both sound and visual flash, if configured in System Preferences } -CGDirectDisplayID -FindCGDirectDisplayIDForScreenIndex(jint screenIndex) -{ - // most common case - just one monitor - CGDirectDisplayID screenID = CGMainDisplayID(); - - CGDisplayCount displayCount = 0; - CGGetOnlineDisplayList(0, NULL, &displayCount); - - if ((displayCount > 1) && - (screenIndex >= 0) && - (screenIndex < (jint)displayCount)) - { - if (displayCount < 10) { - // stack allocated optimization for less than 10 monitors - CGDirectDisplayID onlineDisplays[displayCount]; - CGGetOnlineDisplayList(displayCount, onlineDisplays, &displayCount); - screenID = (CGDirectDisplayID)onlineDisplays[screenIndex]; - } else { - CGDirectDisplayID *onlineDisplays = - malloc(displayCount*sizeof(CGDirectDisplayID)); - if (onlineDisplays != NULL) { - CGGetOnlineDisplayList(displayCount, onlineDisplays, - &displayCount); - screenID = (CGDirectDisplayID)onlineDisplays[screenIndex]; - free(onlineDisplays); - } - } - } - - return screenID; -} - /* * Class: sun_lwawt_macosx_LWCToolkit * Method: initIDs diff --git a/jdk/src/macosx/native/sun/java2d/opengl/CGLGraphicsConfig.m b/jdk/src/macosx/native/sun/java2d/opengl/CGLGraphicsConfig.m index 0bc58ec6ad3..a9de285758d 100644 --- a/jdk/src/macosx/native/sun/java2d/opengl/CGLGraphicsConfig.m +++ b/jdk/src/macosx/native/sun/java2d/opengl/CGLGraphicsConfig.m @@ -192,12 +192,12 @@ Java_sun_java2d_opengl_CGLGraphicsConfig_initCGL JNIEXPORT jlong JNICALL Java_sun_java2d_opengl_CGLGraphicsConfig_getCGLConfigInfo (JNIEnv *env, jclass cglgc, - jint screennum, jint pixfmt, jint swapInterval) + jint displayID, jint pixfmt, jint swapInterval) { jlong ret = 0L; JNF_COCOA_ENTER(env); NSMutableArray * retArray = [NSMutableArray arrayWithCapacity:3]; - [retArray addObject: [NSNumber numberWithInt: (int)screennum]]; + [retArray addObject: [NSNumber numberWithInt: (int)displayID]]; [retArray addObject: [NSNumber numberWithInt: (int)pixfmt]]; [retArray addObject: [NSNumber numberWithInt: (int)swapInterval]]; if ([NSThread isMainThread]) { @@ -217,7 +217,7 @@ Java_sun_java2d_opengl_CGLGraphicsConfig_getCGLConfigInfo + (void) _getCGLConfigInfo: (NSMutableArray *)argValue { AWT_ASSERT_APPKIT_THREAD; - jint screennum = (jint)[(NSNumber *)[argValue objectAtIndex: 0] intValue]; + jint displayID = (jint)[(NSNumber *)[argValue objectAtIndex: 0] intValue]; jint pixfmt = (jint)[(NSNumber *)[argValue objectAtIndex: 1] intValue]; jint swapInterval = (jint)[(NSNumber *)[argValue objectAtIndex: 2] intValue]; JNIEnv *env = [ThreadUtilities getJNIEnvUncached]; @@ -230,16 +230,11 @@ Java_sun_java2d_opengl_CGLGraphicsConfig_getCGLConfigInfo CGOpenGLDisplayMask glMask = (CGOpenGLDisplayMask)pixfmt; if (sharedContext == NULL) { if (glMask == 0) { - CGDirectDisplayID id = - FindCGDirectDisplayIDForScreenIndex(screennum); - glMask = CGDisplayIDToOpenGLDisplayMask(id); + glMask = CGDisplayIDToOpenGLDisplayMask(displayID); } NSOpenGLPixelFormatAttribute attrs[] = { NSOpenGLPFAClosestPolicy, - NSOpenGLPFANoRecovery, - NSOpenGLPFAAccelerated, - NSOpenGLPFAFullScreen, NSOpenGLPFAWindow, NSOpenGLPFAPixelBuffer, NSOpenGLPFADoubleBuffer, @@ -412,7 +407,7 @@ Java_sun_java2d_opengl_CGLGraphicsConfig_getCGLConfigInfo return; } memset(cglinfo, 0, sizeof(CGLGraphicsConfigInfo)); - cglinfo->screen = screennum; + cglinfo->screen = displayID; cglinfo->pixfmt = sharedPixelFormat; cglinfo->context = oglc; @@ -422,17 +417,6 @@ Java_sun_java2d_opengl_CGLGraphicsConfig_getCGLConfigInfo } @end //GraphicsConfigUtil - -JNIEXPORT jint JNICALL -Java_sun_java2d_opengl_CGLGraphicsConfig_getDefaultPixFmt - (JNIEnv *env, jclass cglgc, jint screennum) -{ - J2dTraceLn(J2D_TRACE_INFO, "CGLGraphicsConfig_getDefaultPixFmt"); - - CGDirectDisplayID id = FindCGDirectDisplayIDForScreenIndex(screennum); - return (jint)CGDisplayIDToOpenGLDisplayMask(id); -} - JNIEXPORT jint JNICALL Java_sun_java2d_opengl_CGLGraphicsConfig_getOGLCapabilities (JNIEnv *env, jclass cglgc, jlong configInfo) From 1270c690887e3b58d90b3a4a09a363f782d70dde Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov <serb@openjdk.org> Date: Thu, 28 Feb 2013 20:27:38 +0400 Subject: [PATCH 118/180] 8003169: [macosx] JVM crash after disconnecting from projector Reviewed-by: anthony, alexsch --- .../classes/sun/awt/CGraphicsDevice.java | 20 +++++--- .../classes/sun/lwawt/macosx/LWCToolkit.java | 19 +------- .../macosx/native/sun/awt/CGraphicsDevice.m | 46 ++++++++++++++++++- 3 files changed, 60 insertions(+), 25 deletions(-) diff --git a/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java b/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java index c4786eebcce..1a5e22af582 100644 --- a/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java +++ b/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -29,6 +29,7 @@ import java.awt.AWTPermission; import java.awt.DisplayMode; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; +import java.awt.Insets; import java.awt.Window; import java.util.Objects; @@ -110,8 +111,9 @@ public final class CGraphicsDevice extends GraphicsDevice { return nativeGetYResolution(displayID); } - private static native double nativeGetXResolution(int displayID); - private static native double nativeGetYResolution(int displayID); + public Insets getScreenInsets() { + return nativeGetScreenInsets(displayID); + } /** * Enters full-screen mode, or returns to windowed mode. @@ -217,9 +219,15 @@ public final class CGraphicsDevice extends GraphicsDevice { return nativeGetDisplayModes(displayID); } - private native void nativeSetDisplayMode(int displayID, int w, int h, int bpp, int refrate); + private static native void nativeSetDisplayMode(int displayID, int w, int h, int bpp, int refrate); - private native DisplayMode nativeGetDisplayMode(int displayID); + private static native DisplayMode nativeGetDisplayMode(int displayID); - private native DisplayMode[] nativeGetDisplayModes(int displayID); + private static native DisplayMode[] nativeGetDisplayModes(int displayID); + + private static native double nativeGetXResolution(int displayID); + + private static native double nativeGetYResolution(int displayID); + + private static native Insets nativeGetScreenInsets(int displayID); } diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java index 579468601e2..a15eb46a1d1 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, 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 @@ -351,22 +351,7 @@ public final class LWCToolkit extends LWToolkit { @Override public Insets getScreenInsets(final GraphicsConfiguration gc) { - final CGraphicsConfig cgc = (CGraphicsConfig) gc; - final int displayId = cgc.getDevice().getCGDisplayID(); - Rectangle fullScreen, workArea; - final long screen = CWrapper.NSScreen.screenByDisplayId(displayId); - try { - fullScreen = CWrapper.NSScreen.frame(screen).getBounds(); - workArea = CWrapper.NSScreen.visibleFrame(screen).getBounds(); - } finally { - CWrapper.NSObject.release(screen); - } - // Convert between Cocoa's coordinate system and Java. - int bottom = workArea.y - fullScreen.y; - int top = fullScreen.height - workArea.height - bottom; - int left = workArea.x - fullScreen.x; - int right = fullScreen.width - workArea.width - left; - return new Insets(top, left, bottom, right); + return ((CGraphicsConfig) gc).getDevice().getScreenInsets(); } @Override diff --git a/jdk/src/macosx/native/sun/awt/CGraphicsDevice.m b/jdk/src/macosx/native/sun/awt/CGraphicsDevice.m index 9bc5393d765..1e2df28dd56 100644 --- a/jdk/src/macosx/native/sun/awt/CGraphicsDevice.m +++ b/jdk/src/macosx/native/sun/awt/CGraphicsDevice.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -23,7 +23,8 @@ * questions. */ -#include "LWCToolkit.h" +#import "LWCToolkit.h" +#import "ThreadUtilities.h" /* * Convert the mode string to the more convinient bits per pixel value @@ -146,6 +147,47 @@ Java_sun_awt_CGraphicsDevice_nativeGetYResolution return dpi; } +/* + * Class: sun_awt_CGraphicsDevice + * Method: nativeGetScreenInsets + * Signature: (I)D + */ +JNIEXPORT jobject JNICALL +Java_sun_awt_CGraphicsDevice_nativeGetScreenInsets + (JNIEnv *env, jclass class, jint displayID) +{ + jobject ret = NULL; + __block NSRect frame = NSZeroRect; + __block NSRect visibleFrame = NSZeroRect; +JNF_COCOA_ENTER(env); + + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ + NSArray *screens = [NSScreen screens]; + for (NSScreen *screen in screens) { + NSDictionary *screenInfo = [screen deviceDescription]; + NSNumber *screenID = [screenInfo objectForKey:@"NSScreenNumber"]; + if ([screenID pointerValue] == displayID){ + frame = [screen frame]; + visibleFrame = [screen visibleFrame]; + break; + } + } + }]; + // Convert between Cocoa's coordinate system and Java. + jint bottom = visibleFrame.origin.y - frame.origin.y; + jint top = frame.size.height - visibleFrame.size.height - bottom; + jint left = visibleFrame.origin.x - frame.origin.x; + jint right = frame.size.width - visibleFrame.size.width - left; + + static JNF_CLASS_CACHE(jc_Insets, "java/awt/Insets"); + static JNF_CTOR_CACHE(jc_Insets_ctor, jc_Insets, "(IIII)V"); + ret = JNFNewObject(env, jc_Insets_ctor, top, left, bottom, right); + +JNF_COCOA_EXIT(env); + + return ret; +} + /* * Class: sun_awt_CGraphicsDevice * Method: nativeSetDisplayMode From 618b36f5eb7a53831bde58ae8b9ca82b6dfa8433 Mon Sep 17 00:00:00 2001 From: Jason Uh <juh@openjdk.org> Date: Thu, 28 Feb 2013 16:36:01 -0800 Subject: [PATCH 119/180] 8006853: OCSP timeout set to wrong value if com.sun.security.ocsp.timeout < 0 Reviewed-by: mullan --- jdk/src/share/classes/sun/security/provider/certpath/OCSP.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/share/classes/sun/security/provider/certpath/OCSP.java b/jdk/src/share/classes/sun/security/provider/certpath/OCSP.java index f57c832bfa5..03c910b8897 100644 --- a/jdk/src/share/classes/sun/security/provider/certpath/OCSP.java +++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSP.java @@ -89,7 +89,7 @@ public final class OCSP { new GetIntegerAction("com.sun.security.ocsp.timeout", DEFAULT_CONNECT_TIMEOUT)); if (tmp < 0) { - tmp = DEFAULT_CONNECT_TIMEOUT; + return DEFAULT_CONNECT_TIMEOUT; } // Convert to milliseconds, as the system property will be // specified in seconds From 19bc54290f90b10094a7ab4b82bb50278fbbdcc8 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov <malenkov@openjdk.org> Date: Fri, 1 Mar 2013 14:30:52 +0400 Subject: [PATCH 120/180] 7163696: JCK Swing interactive test JScrollBarTest0013 fails with Nimbus and GTK L&Fs Reviewed-by: alexsch --- .../classes/java/beans/PropertyDescriptor.java | 7 +------ jdk/test/java/beans/Introspector/Test7192955.java | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/jdk/src/share/classes/java/beans/PropertyDescriptor.java b/jdk/src/share/classes/java/beans/PropertyDescriptor.java index c03149c0574..0abdcad972b 100644 --- a/jdk/src/share/classes/java/beans/PropertyDescriptor.java +++ b/jdk/src/share/classes/java/beans/PropertyDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, 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 @@ -109,10 +109,6 @@ public class PropertyDescriptor extends FeatureDescriptor { if (writeMethodName != null && getWriteMethod() == null) { throw new IntrospectionException("Method not found: " + writeMethodName); } - boundInitialization(beanClass); - } - - private void boundInitialization(Class<?> beanClass) { // If this class or one of its base classes allow PropertyChangeListener, // then we assume that any properties we discover are "bound". // See Introspector.getTargetPropertyInfo() method. @@ -163,7 +159,6 @@ public class PropertyDescriptor extends FeatureDescriptor { setReadMethod(read); setWriteMethod(write); this.baseName = base; - boundInitialization(bean); } /** diff --git a/jdk/test/java/beans/Introspector/Test7192955.java b/jdk/test/java/beans/Introspector/Test7192955.java index 13e874ba719..afce427bf30 100644 --- a/jdk/test/java/beans/Introspector/Test7192955.java +++ b/jdk/test/java/beans/Introspector/Test7192955.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -23,17 +23,20 @@ /* * @test - * @bug 7192955 + * @bug 7192955 8000183 * @summary Tests that all properties are bound * @author Sergey Malenkov */ +import java.beans.IntrospectionException; +import java.beans.Introspector; import java.beans.PropertyChangeListener; +import java.beans.PropertyDescriptor; import java.util.List; public class Test7192955 { - public static void main(String[] args) { + public static void main(String[] args) throws IntrospectionException { if (!BeanUtils.findPropertyDescriptor(MyBean.class, "test").isBound()) { throw new Error("a simple property is not bound"); } @@ -43,6 +46,12 @@ public class Test7192955 { if (!BeanUtils.findPropertyDescriptor(MyBean.class, "readOnly").isBound()) { throw new Error("a read-only property is not bound"); } + PropertyDescriptor[] pds = Introspector.getBeanInfo(MyBean.class, BaseBean.class).getPropertyDescriptors(); + for (PropertyDescriptor pd : pds) { + if (pd.getName().equals("test") && pd.isBound()) { + throw new Error("a simple property is bound without superclass"); + } + } } public static class BaseBean { From 9abb185430387da7ce01e32b9c63014f09720aea Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan <xuelei@openjdk.org> Date: Fri, 1 Mar 2013 02:34:34 -0800 Subject: [PATCH 121/180] 7030966: Support AEAD CipherSuites Reviewed-by: weijun, wetmore, valeriep --- .../provider/TlsKeyMaterialGenerator.java | 28 +- .../spec/TlsKeyMaterialParameterSpec.java | 8 +- .../internal/spec/TlsKeyMaterialSpec.java | 26 +- .../pkcs11/P11TlsKeyMaterialGenerator.java | 18 +- .../sun/security/ssl/Authenticator.java | 161 +++++ .../classes/sun/security/ssl/CipherBox.java | 582 +++++++++++++----- .../classes/sun/security/ssl/CipherSuite.java | 230 +++++-- .../sun/security/ssl/EngineInputRecord.java | 148 ++--- .../sun/security/ssl/EngineOutputRecord.java | 160 +++-- .../sun/security/ssl/EngineWriter.java | 12 +- .../classes/sun/security/ssl/Handshaker.java | 80 ++- .../classes/sun/security/ssl/InputRecord.java | 108 +++- .../classes/sun/security/ssl/JsseJce.java | 7 +- .../share/classes/sun/security/ssl/MAC.java | 124 +--- .../sun/security/ssl/OutputRecord.java | 149 +++-- .../classes/sun/security/ssl/Record.java | 35 +- .../sun/security/ssl/SSLEngineImpl.java | 53 +- .../sun/security/ssl/SSLSocketImpl.java | 44 +- jdk/test/sun/security/ec/TestEC.java | 7 +- .../sun/security/pkcs11/fips/CipherTest.java | 21 +- .../security/pkcs11/sslecc/CipherTest.java | 21 +- .../SSLEngineBadBufferArrayAccess.java | 8 +- .../javax/net/ssl/TLSv12/ShortRSAKeyGCM.java | 445 +++++++++++++ .../ciphersuites/CipherSuitesInOrder.java | 27 +- .../ssl/sanity/interop/CipherTest.java | 21 +- .../templates/SSLSocketSSLEngineTemplate.java | 11 +- 26 files changed, 1828 insertions(+), 706 deletions(-) create mode 100644 jdk/src/share/classes/sun/security/ssl/Authenticator.java create mode 100644 jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKeyGCM.java diff --git a/jdk/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java b/jdk/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java index 4146f190875..d1255d42164 100644 --- a/jdk/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java +++ b/jdk/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -165,16 +165,18 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi { // partition keyblock into individual secrets int ofs = 0; - byte[] tmp = new byte[macLength]; + if (macLength != 0) { + byte[] tmp = new byte[macLength]; - // mac keys - System.arraycopy(keyBlock, ofs, tmp, 0, macLength); - ofs += macLength; - clientMacKey = new SecretKeySpec(tmp, "Mac"); + // mac keys + System.arraycopy(keyBlock, ofs, tmp, 0, macLength); + ofs += macLength; + clientMacKey = new SecretKeySpec(tmp, "Mac"); - System.arraycopy(keyBlock, ofs, tmp, 0, macLength); - ofs += macLength; - serverMacKey = new SecretKeySpec(tmp, "Mac"); + System.arraycopy(keyBlock, ofs, tmp, 0, macLength); + ofs += macLength; + serverMacKey = new SecretKeySpec(tmp, "Mac"); + } if (keyLength == 0) { // SSL_RSA_WITH_NULL_* ciphersuites return new TlsKeyMaterialSpec(clientMacKey, serverMacKey); @@ -198,7 +200,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi { // IV keys if needed. if (ivLength != 0) { - tmp = new byte[ivLength]; + byte[] tmp = new byte[ivLength]; System.arraycopy(keyBlock, ofs, tmp, 0, ivLength); ofs += ivLength; @@ -220,8 +222,8 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi { // TLS 1.0 byte[] seed = concat(clientRandom, serverRandom); - tmp = doTLS10PRF(clientKeyBytes, LABEL_CLIENT_WRITE_KEY, seed, - expandedKeyLength, md5, sha); + byte[] tmp = doTLS10PRF(clientKeyBytes, + LABEL_CLIENT_WRITE_KEY, seed, expandedKeyLength, md5, sha); clientCipherKey = new SecretKeySpec(tmp, alg); tmp = doTLS10PRF(serverKeyBytes, LABEL_SERVER_WRITE_KEY, seed, @@ -239,7 +241,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi { } } else { // SSLv3 - tmp = new byte[expandedKeyLength]; + byte[] tmp = new byte[expandedKeyLength]; md5.update(clientKeyBytes); md5.update(clientRandom); diff --git a/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java b/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java index 80aa79a2596..71388b79718 100644 --- a/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java +++ b/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -212,12 +212,6 @@ public class TlsKeyMaterialParameterSpec implements AlgorithmParameterSpec { * generated. */ public int getIvLength() { - // TLS v1.1 or later uses an explicit IV to protect against - // the CBC attacks. - if (majorVersion >= 0x03 && minorVersion >= 0x02) { - return 0; - } - return ivLength; } diff --git a/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialSpec.java b/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialSpec.java index d1204962881..2dd8a93765b 100644 --- a/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialSpec.java +++ b/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -58,9 +58,8 @@ public class TlsKeyMaterialSpec implements KeySpec, SecretKey { * <code>new TlsKeymaterialSpec(clientMacKey, serverMacKey, * null, null, null, null)</code>. * - * @param clientMacKey the client MAC key - * @param serverMacKey the server MAC key - * @throws NullPointerException if clientMacKey or serverMacKey is null + * @param clientMacKey the client MAC key (or null) + * @param serverMacKey the server MAC key (or null) */ public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey) { this(clientMacKey, serverMacKey, null, null, null, null); @@ -73,11 +72,10 @@ public class TlsKeyMaterialSpec implements KeySpec, SecretKey { * <code>new TlsKeymaterialSpec(clientMacKey, serverMacKey, * clientCipherKey, serverCipherKey, null, null)</code>. * - * @param clientMacKey the client MAC key - * @param serverMacKey the server MAC key + * @param clientMacKey the client MAC key (or null) + * @param serverMacKey the server MAC key (or null) * @param clientCipherKey the client cipher key (or null) * @param serverCipherKey the server cipher key (or null) - * @throws NullPointerException if clientMacKey or serverMacKey is null */ public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey, SecretKey clientCipherKey, SecretKey serverCipherKey) { @@ -90,21 +88,17 @@ public class TlsKeyMaterialSpec implements KeySpec, SecretKey { * keys, client and server cipher keys, and client and server * initialization vectors. * - * @param clientMacKey the client MAC key - * @param serverMacKey the server MAC key + * @param clientMacKey the client MAC key (or null) + * @param serverMacKey the server MAC key (or null) * @param clientCipherKey the client cipher key (or null) * @param clientIv the client initialization vector (or null) * @param serverCipherKey the server cipher key (or null) * @param serverIv the server initialization vector (or null) - * - * @throws NullPointerException if clientMacKey or serverMacKey is null */ public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey, SecretKey clientCipherKey, IvParameterSpec clientIv, SecretKey serverCipherKey, IvParameterSpec serverIv) { - if ((clientMacKey == null) || (serverMacKey == null)) { - throw new NullPointerException("MAC keys must not be null"); - } + this.clientMacKey = clientMacKey; this.serverMacKey = serverMacKey; this.clientCipherKey = clientCipherKey; @@ -143,7 +137,7 @@ public class TlsKeyMaterialSpec implements KeySpec, SecretKey { /** * Returns the client MAC key. * - * @return the client MAC key. + * @return the client MAC key (or null). */ public SecretKey getClientMacKey() { return clientMacKey; @@ -152,7 +146,7 @@ public class TlsKeyMaterialSpec implements KeySpec, SecretKey { /** * Return the server MAC key. * - * @return the server MAC key. + * @return the server MAC key (or null). */ public SecretKey getServerMacKey() { return serverMacKey; diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java b/jdk/src/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java index 94e731b01f9..14d1708537a 100644 --- a/jdk/src/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java +++ b/jdk/src/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -168,10 +168,22 @@ public final class P11TlsKeyMaterialGenerator extends KeyGeneratorSpi { // Note that the MAC keys do not inherit all attributes from the // template, but they do inherit the sensitive/extractable/token // flags, which is all P11Key cares about. - SecretKey clientMacKey = P11Key.secretKey + SecretKey clientMacKey, serverMacKey; + + // The MAC size may be zero for GCM mode. + // + // PKCS11 does not support GCM mode as the author made the comment, + // so the macBits is unlikely to be zero. It's only a place holder. + if (macBits != 0) { + clientMacKey = P11Key.secretKey (session, out.hClientMacSecret, "MAC", macBits, attributes); - SecretKey serverMacKey = P11Key.secretKey + serverMacKey = P11Key.secretKey (session, out.hServerMacSecret, "MAC", macBits, attributes); + } else { + clientMacKey = null; + serverMacKey = null; + } + SecretKey clientCipherKey, serverCipherKey; if (keyBits != 0) { clientCipherKey = P11Key.secretKey(session, out.hClientKey, diff --git a/jdk/src/share/classes/sun/security/ssl/Authenticator.java b/jdk/src/share/classes/sun/security/ssl/Authenticator.java new file mode 100644 index 00000000000..a97ce7d5f0c --- /dev/null +++ b/jdk/src/share/classes/sun/security/ssl/Authenticator.java @@ -0,0 +1,161 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.util.Arrays; + +/** + * This class represents an SSL/TLS message authentication token, + * which encapsulates a sequence number and ensures that attempts to + * delete or reorder messages can be detected. + * + * Each SSL/TLS connection state contains a sequence number, which + * is maintained separately for read and write states. The sequence + * number MUST be set to zero whenever a connection state is made the + * active state. Sequence numbers are of type uint64 and may not + * exceed 2^64-1. Sequence numbers do not wrap. If a SSL/TLS + * implementation would need to wrap a sequence number, it must + * renegotiate instead. A sequence number is incremented after each + * record: specifically, the first record transmitted under a + * particular connection state MUST use sequence number 0. + */ +class Authenticator { + + // byte array containing the additional authentication information for + // each record + private final byte[] block; + + // the block size of SSL v3.0: + // sequence number + record type + + record length + private static final int BLOCK_SIZE_SSL = 8 + 1 + 2; + + // the block size of TLS v1.0 and later: + // sequence number + record type + protocol version + record length + private static final int BLOCK_SIZE_TLS = 8 + 1 + 2 + 2; + + /** + * Default construct, no message authentication token is initialized. + * + * Note that this construct can only be called for null MAC + */ + Authenticator() { + block = new byte[0]; + } + + /** + * Constructs the message authentication token for the specified + * SSL/TLS protocol. + */ + Authenticator(ProtocolVersion protocolVersion) { + if (protocolVersion.v >= ProtocolVersion.TLS10.v) { + block = new byte[BLOCK_SIZE_TLS]; + block[9] = protocolVersion.major; + block[10] = protocolVersion.minor; + } else { + block = new byte[BLOCK_SIZE_SSL]; + } + } + + /** + * Checks whether the sequence number is close to wrap. + * + * Sequence numbers are of type uint64 and may not exceed 2^64-1. + * Sequence numbers do not wrap. When the sequence number is near + * to wrap, we need to close the connection immediately. + * + * @return true if the sequence number is close to wrap + */ + final boolean seqNumOverflow() { + /* + * Conservatively, we don't allow more records to be generated + * when there are only 2^8 sequence numbers left. + */ + return (block.length != 0 && + block[0] == (byte)0xFF && block[1] == (byte)0xFF && + block[2] == (byte)0xFF && block[3] == (byte)0xFF && + block[4] == (byte)0xFF && block[5] == (byte)0xFF && + block[6] == (byte)0xFF); + } + + /** + * Checks whether the sequence number close to renew. + * + * Sequence numbers are of type uint64 and may not exceed 2^64-1. + * Sequence numbers do not wrap. If a TLS + * implementation would need to wrap a sequence number, it must + * renegotiate instead. + * + * @return true if the sequence number is huge enough to renew + */ + final boolean seqNumIsHuge() { + /* + * Conservatively, we should ask for renegotiation when there are + * only 2^48 sequence numbers left. + */ + return (block.length != 0 && + block[0] == (byte)0xFF && block[1] == (byte)0xFF); + } + + /** + * Gets the current sequence number. + * + * @return the byte array of the current sequence number + */ + final byte[] sequenceNumber() { + return Arrays.copyOf(block, 8); + } + + /** + * Acquires the current message authentication information with the + * specified record type and fragment length, and then increases the + * sequence number. + * + * @param type the record type + * @param length the fragment of the record + * @return the byte array of the current message authentication information + */ + final byte[] acquireAuthenticationBytes(byte type, int length) { + byte[] copy = block.clone(); + + if (block.length != 0) { + copy[8] = type; + copy[copy.length - 2] = (byte)(length >> 8); + copy[copy.length - 1] = (byte)(length); + + /* + * Increase the sequence number in the block array + * it is a 64-bit number stored in big-endian format + */ + int k = 7; + while ((k >= 0) && (++block[k] == 0)) { + k--; + } + } + + return copy; + } + +} diff --git a/jdk/src/share/classes/sun/security/ssl/CipherBox.java b/jdk/src/share/classes/sun/security/ssl/CipherBox.java index 362f9b5d904..bce44dabda3 100644 --- a/jdk/src/share/classes/sun/security/ssl/CipherBox.java +++ b/jdk/src/share/classes/sun/security/ssl/CipherBox.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -29,15 +29,18 @@ package sun.security.ssl; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Hashtable; +import java.util.Arrays; import java.security.*; import javax.crypto.*; import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.GCMParameterSpec; import java.nio.*; import sun.security.ssl.CipherSuite.*; import static sun.security.ssl.CipherSuite.*; +import static sun.security.ssl.CipherSuite.CipherType.*; import sun.misc.HexDumpEncoder; @@ -101,20 +104,41 @@ final class CipherBox { // cipher object private final Cipher cipher; - /** - * Cipher blocksize, 0 for stream ciphers - */ - private int blockSize; - /** * secure random */ private SecureRandom random; /** - * Is the cipher of CBC mode? + * fixed IV, the implicit nonce of AEAD cipher suite, only apply to + * AEAD cipher suites */ - private final boolean isCBCMode; + private final byte[] fixedIv; + + /** + * the key, reserved only for AEAD cipher initialization + */ + private final Key key; + + /** + * the operation mode, reserved for AEAD cipher initialization + */ + private final int mode; + + /** + * the authentication tag size, only apply to AEAD cipher suites + */ + private final int tagSize; + + /** + * the record IV length, only apply to AEAD cipher suites + */ + private final int recordIvSize; + + /** + * cipher type + */ + private final CipherType cipherType; /** * Fixed masks of various block size, as the initial decryption IVs @@ -132,7 +156,13 @@ final class CipherBox { private CipherBox() { this.protocolVersion = ProtocolVersion.DEFAULT; this.cipher = null; - this.isCBCMode = false; + this.cipherType = STREAM_CIPHER; + this.fixedIv = new byte[0]; + this.key = null; + this.mode = Cipher.ENCRYPT_MODE; // choose at random + this.random = null; + this.tagSize = 0; + this.recordIvSize = 0; } /** @@ -147,13 +177,13 @@ final class CipherBox { try { this.protocolVersion = protocolVersion; this.cipher = JsseJce.getCipher(bulkCipher.transformation); - int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; + this.mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; if (random == null) { random = JsseJce.getSecureRandom(); } this.random = random; - this.isCBCMode = bulkCipher.isCBCMode; + this.cipherType = bulkCipher.cipherType; /* * RFC 4346 recommends two algorithms used to generated the @@ -171,14 +201,40 @@ final class CipherBox { iv = getFixedMask(bulkCipher.ivSize); } - cipher.init(mode, key, iv, random); + if (cipherType == AEAD_CIPHER) { + // AEAD must completely initialize the cipher for each packet, + // and so we save initialization parameters for packet + // processing time. - // Do not call getBlockSize until after init() - // otherwise we would disrupt JCE delayed provider selection - blockSize = cipher.getBlockSize(); - // some providers implement getBlockSize() incorrectly - if (blockSize == 1) { - blockSize = 0; + // Set the tag size for AEAD cipher + tagSize = bulkCipher.tagSize; + + // Reserve the key for AEAD cipher initialization + this.key = key; + + fixedIv = iv.getIV(); + if (fixedIv == null || + fixedIv.length != bulkCipher.fixedIvSize) { + throw new RuntimeException("Improper fixed IV for AEAD"); + } + + // Set the record IV length for AEAD cipher + recordIvSize = bulkCipher.ivSize - bulkCipher.fixedIvSize; + + // DON'T initialize the cipher for AEAD! + } else { + // CBC only requires one initialization during its lifetime + // (future packets/IVs set the proper CBC state), so we can + // initialize now. + + // Zeroize the variables that only apply to AEAD cipher + this.tagSize = 0; + this.fixedIv = new byte[0]; + this.recordIvSize = 0; + this.key = null; + + // Initialize the cipher + cipher.init(mode, key, iv, random); } } catch (NoSuchAlgorithmException e) { throw e; @@ -235,26 +291,11 @@ final class CipherBox { } try { - if (blockSize != 0) { - // TLSv1.1 needs a IV block - if (protocolVersion.v >= ProtocolVersion.TLS11.v) { - // generate a random number - byte[] prefix = new byte[blockSize]; - random.nextBytes(prefix); - - // move forward the plaintext - System.arraycopy(buf, offset, - buf, offset + prefix.length, len); - - // prefix the plaintext - System.arraycopy(prefix, 0, - buf, offset, prefix.length); - - len += prefix.length; - } - + int blockSize = cipher.getBlockSize(); + if (cipherType == BLOCK_CIPHER) { len = addPadding(buf, offset, len, blockSize); } + if (debug != null && Debug.isOn("plaintext")) { try { HexDumpEncoder hd = new HexDumpEncoder(); @@ -267,14 +308,28 @@ final class CipherBox { System.out); } catch (IOException e) { } } - int newLen = cipher.update(buf, offset, len, buf, offset); - if (newLen != len) { - // catch BouncyCastle buffering error - throw new RuntimeException("Cipher buffering error " + - "in JCE provider " + cipher.getProvider().getName()); + + + if (cipherType == AEAD_CIPHER) { + try { + return cipher.doFinal(buf, offset, len, buf, offset); + } catch (IllegalBlockSizeException | BadPaddingException ibe) { + // unlikely to happen + throw new RuntimeException( + "Cipher error in AEAD mode in JCE provider " + + cipher.getProvider().getName(), ibe); + } + } else { + int newLen = cipher.update(buf, offset, len, buf, offset); + if (newLen != len) { + // catch BouncyCastle buffering error + throw new RuntimeException("Cipher buffering error " + + "in JCE provider " + cipher.getProvider().getName()); + } + return newLen; } - return newLen; } catch (ShortBufferException e) { + // unlikely to happen, we should have enough buffer space here throw new ArrayIndexOutOfBoundsException(e.toString()); } } @@ -288,7 +343,7 @@ final class CipherBox { * set to last position padded/encrypted. The limit may have changed * because of the added padding bytes. */ - int encrypt(ByteBuffer bb) { + int encrypt(ByteBuffer bb, int outLimit) { int len = bb.remaining(); @@ -297,66 +352,71 @@ final class CipherBox { return len; } - try { - int pos = bb.position(); + int pos = bb.position(); - if (blockSize != 0) { - // TLSv1.1 needs a IV block - if (protocolVersion.v >= ProtocolVersion.TLS11.v) { - // generate a random number - byte[] prefix = new byte[blockSize]; - random.nextBytes(prefix); + int blockSize = cipher.getBlockSize(); + if (cipherType == BLOCK_CIPHER) { + // addPadding adjusts pos/limit + len = addPadding(bb, blockSize); + bb.position(pos); + } - // move forward the plaintext - byte[] buf = null; - int limit = bb.limit(); - if (bb.hasArray()) { - int arrayOffset = bb.arrayOffset(); - buf = bb.array(); - System.arraycopy(buf, arrayOffset + pos, - buf, arrayOffset + pos + prefix.length, - limit - pos); - bb.limit(limit + prefix.length); - } else { - buf = new byte[limit - pos]; - bb.get(buf, 0, limit - pos); - bb.position(pos + prefix.length); - bb.limit(limit + prefix.length); - bb.put(buf); + if (debug != null && Debug.isOn("plaintext")) { + try { + HexDumpEncoder hd = new HexDumpEncoder(); + + System.out.println( + "Padded plaintext before ENCRYPTION: len = " + + len); + hd.encodeBuffer(bb.duplicate(), System.out); + + } catch (IOException e) { } + } + + /* + * Encrypt "in-place". This does not add its own padding. + */ + ByteBuffer dup = bb.duplicate(); + if (cipherType == AEAD_CIPHER) { + try { + int outputSize = cipher.getOutputSize(dup.remaining()); + if (outputSize > bb.remaining()) { + // need to expand the limit of the output buffer for + // the authentication tag. + // + // DON'T worry about the buffer's capacity, we have + // reserved space for the authentication tag. + if (outLimit < pos + outputSize) { + // unlikely to happen + throw new ShortBufferException( + "need more space in output buffer"); } - bb.position(pos); - - // prefix the plaintext - bb.put(prefix); - bb.position(pos); + bb.limit(pos + outputSize); } - - // addPadding adjusts pos/limit - len = addPadding(bb, blockSize); - bb.position(pos); + int newLen = cipher.doFinal(dup, bb); + if (newLen != outputSize) { + throw new RuntimeException( + "Cipher buffering error in JCE provider " + + cipher.getProvider().getName()); + } + return newLen; + } catch (IllegalBlockSizeException | + BadPaddingException | ShortBufferException ibse) { + // unlikely to happen + throw new RuntimeException( + "Cipher error in AEAD mode in JCE provider " + + cipher.getProvider().getName(), ibse); } - if (debug != null && Debug.isOn("plaintext")) { - try { - HexDumpEncoder hd = new HexDumpEncoder(); - - System.out.println( - "Padded plaintext before ENCRYPTION: len = " - + len); - hd.encodeBuffer(bb, System.out); - - } catch (IOException e) { } - /* - * reset back to beginning - */ - bb.position(pos); + } else { + int newLen; + try { + newLen = cipher.update(dup, bb); + } catch (ShortBufferException sbe) { + // unlikely to happen + throw new RuntimeException("Cipher buffering error " + + "in JCE provider " + cipher.getProvider().getName()); } - /* - * Encrypt "in-place". This does not add its own padding. - */ - ByteBuffer dup = bb.duplicate(); - int newLen = cipher.update(dup, bb); - if (bb.position() != dup.position()) { throw new RuntimeException("bytebuffer padding error"); } @@ -367,10 +427,6 @@ final class CipherBox { "in JCE provider " + cipher.getProvider().getName()); } return newLen; - } catch (ShortBufferException e) { - RuntimeException exc = new RuntimeException(e.toString()); - exc.initCause(e); - throw exc; } } @@ -398,11 +454,23 @@ final class CipherBox { } try { - int newLen = cipher.update(buf, offset, len, buf, offset); - if (newLen != len) { - // catch BouncyCastle buffering error - throw new RuntimeException("Cipher buffering error " + - "in JCE provider " + cipher.getProvider().getName()); + int newLen; + if (cipherType == AEAD_CIPHER) { + try { + newLen = cipher.doFinal(buf, offset, len, buf, offset); + } catch (IllegalBlockSizeException ibse) { + // unlikely to happen + throw new RuntimeException( + "Cipher error in AEAD mode in JCE provider " + + cipher.getProvider().getName(), ibse); + } + } else { + newLen = cipher.update(buf, offset, len, buf, offset); + if (newLen != len) { + // catch BouncyCastle buffering error + throw new RuntimeException("Cipher buffering error " + + "in JCE provider " + cipher.getProvider().getName()); + } } if (debug != null && Debug.isOn("plaintext")) { try { @@ -416,7 +484,9 @@ final class CipherBox { System.out); } catch (IOException e) { } } - if (blockSize != 0) { + + if (cipherType == BLOCK_CIPHER) { + int blockSize = cipher.getBlockSize(); newLen = removePadding(buf, offset, newLen, blockSize, protocolVersion); @@ -424,16 +494,11 @@ final class CipherBox { if (newLen < blockSize) { throw new BadPaddingException("invalid explicit IV"); } - - // discards the first cipher block, the IV component. - System.arraycopy(buf, offset + blockSize, - buf, offset, newLen - blockSize); - - newLen -= blockSize; } } return newLen; } catch (ShortBufferException e) { + // unlikely to happen, we should have enough buffer space here throw new ArrayIndexOutOfBoundsException(e.toString()); } } @@ -463,15 +528,29 @@ final class CipherBox { */ int pos = bb.position(); ByteBuffer dup = bb.duplicate(); - int newLen = cipher.update(dup, bb); - if (newLen != len) { - // catch BouncyCastle buffering error - throw new RuntimeException("Cipher buffering error " + - "in JCE provider " + cipher.getProvider().getName()); + int newLen; + if (cipherType == AEAD_CIPHER) { + try { + newLen = cipher.doFinal(dup, bb); + } catch (IllegalBlockSizeException ibse) { + // unlikely to happen + throw new RuntimeException( + "Cipher error in AEAD mode \"" + ibse.getMessage() + + " \"in JCE provider " + cipher.getProvider().getName()); + } + } else { + newLen = cipher.update(dup, bb); + if (newLen != len) { + // catch BouncyCastle buffering error + throw new RuntimeException("Cipher buffering error " + + "in JCE provider " + cipher.getProvider().getName()); + } } + // reset the limit to the end of the decryted data + bb.limit(pos + newLen); + if (debug != null && Debug.isOn("plaintext")) { - bb.position(pos); try { HexDumpEncoder hd = new HexDumpEncoder(); @@ -479,50 +558,33 @@ final class CipherBox { "Padded plaintext after DECRYPTION: len = " + newLen); - hd.encodeBuffer(bb, System.out); + hd.encodeBuffer( + (ByteBuffer)bb.duplicate().position(pos), System.out); } catch (IOException e) { } } /* * Remove the block padding. */ - if (blockSize != 0) { + if (cipherType == BLOCK_CIPHER) { + int blockSize = cipher.getBlockSize(); bb.position(pos); newLen = removePadding(bb, blockSize, protocolVersion); + // check the explicit IV of TLS v1.1 or later if (protocolVersion.v >= ProtocolVersion.TLS11.v) { if (newLen < blockSize) { throw new BadPaddingException("invalid explicit IV"); } - // discards the first cipher block, the IV component. - byte[] buf = null; - int limit = bb.limit(); - if (bb.hasArray()) { - int arrayOffset = bb.arrayOffset(); - buf = bb.array(); - System.arraycopy(buf, arrayOffset + pos + blockSize, - buf, arrayOffset + pos, limit - pos - blockSize); - bb.limit(limit - blockSize); - } else { - buf = new byte[limit - pos - blockSize]; - bb.position(pos + blockSize); - bb.get(buf); - bb.position(pos); - bb.put(buf); - bb.limit(limit - blockSize); - } - // reset the position to the end of the decrypted data - limit = bb.limit(); - bb.position(limit); + bb.position(bb.limit()); } } return newLen; } catch (ShortBufferException e) { - RuntimeException exc = new RuntimeException(e.toString()); - exc.initCause(e); - throw exc; + // unlikely to happen, we should have enough buffer space here + throw new ArrayIndexOutOfBoundsException(e.toString()); } } @@ -695,8 +757,8 @@ final class CipherBox { // ignore return value. cipher.doFinal(); } - } catch (GeneralSecurityException e) { - // swallow for now. + } catch (Exception e) { + // swallow all types of exceptions. } } @@ -706,6 +768,234 @@ final class CipherBox { * @return true if the cipher use CBC mode, false otherwise. */ boolean isCBCMode() { - return isCBCMode; + return cipherType == BLOCK_CIPHER; + } + + /* + * Does the cipher use AEAD mode? + * + * @return true if the cipher use AEAD mode, false otherwise. + */ + boolean isAEADMode() { + return cipherType == AEAD_CIPHER; + } + + /* + * Is the cipher null? + * + * @return true if the cipher is null, false otherwise. + */ + boolean isNullCipher() { + return cipher == null; + } + + /* + * Gets the explicit nonce/IV size of the cipher. + * + * The returned value is the SecurityParameters.record_iv_length in + * RFC 4346/5246. It is the size of explicit IV for CBC mode, and the + * size of explicit nonce for AEAD mode. + * + * @return the explicit nonce size of the cipher. + */ + int getExplicitNonceSize() { + switch (cipherType) { + case BLOCK_CIPHER: + // For block ciphers, the explicit IV length is of length + // SecurityParameters.record_iv_length, which is equal to + // the SecurityParameters.block_size. + if (protocolVersion.v >= ProtocolVersion.TLS11.v) { + return cipher.getBlockSize(); + } + break; + case AEAD_CIPHER: + return recordIvSize; + // It is also the length of sequence number, which is + // used as the nonce_explicit for AEAD cipher suites. + } + + return 0; + } + + /* + * Applies the explicit nonce/IV to this cipher. This method is used to + * decrypt an SSL/TLS input record. + * + * The returned value is the SecurityParameters.record_iv_length in + * RFC 4346/5246. It is the size of explicit IV for CBC mode, and the + * size of explicit nonce for AEAD mode. + * + * @param authenticator the authenticator to get the additional + * authentication data + * @param contentType the content type of the input record + * @param bb the byte buffer to get the explicit nonce from + * + * @return the explicit nonce size of the cipher. + */ + int applyExplicitNonce(Authenticator authenticator, byte contentType, + ByteBuffer bb) throws BadPaddingException { + switch (cipherType) { + case BLOCK_CIPHER: + // For block ciphers, the explicit IV length is of length + // SecurityParameters.record_iv_length, which is equal to + // the SecurityParameters.block_size. + if (protocolVersion.v >= ProtocolVersion.TLS11.v) { + return cipher.getBlockSize(); + } + break; + case AEAD_CIPHER: + if (bb.remaining() < (recordIvSize + tagSize)) { + throw new BadPaddingException( + "invalid AEAD cipher fragment"); + } + + // initialize the AEAD cipher for the unique IV + byte[] iv = Arrays.copyOf(fixedIv, + fixedIv.length + recordIvSize); + bb.get(iv, fixedIv.length, recordIvSize); + bb.position(bb.position() - recordIvSize); + GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv); + try { + cipher.init(mode, key, spec, random); + } catch (InvalidKeyException | + InvalidAlgorithmParameterException ikae) { + // unlikely to happen + throw new RuntimeException( + "invalid key or spec in GCM mode", ikae); + } + + // update the additional authentication data + byte[] aad = authenticator.acquireAuthenticationBytes( + contentType, bb.remaining() - recordIvSize - tagSize); + cipher.updateAAD(aad); + + return recordIvSize; + // It is also the length of sequence number, which is + // used as the nonce_explicit for AEAD cipher suites. + } + + return 0; + } + + /* + * Applies the explicit nonce/IV to this cipher. This method is used to + * decrypt an SSL/TLS input record. + * + * The returned value is the SecurityParameters.record_iv_length in + * RFC 4346/5246. It is the size of explicit IV for CBC mode, and the + * size of explicit nonce for AEAD mode. + * + * @param authenticator the authenticator to get the additional + * authentication data + * @param contentType the content type of the input record + * @param buf the byte array to get the explicit nonce from + * @param offset the offset of the byte buffer + * @param cipheredLength the ciphered fragment length of the output + * record, it is the TLSCiphertext.length in RFC 4346/5246. + * + * @return the explicit nonce size of the cipher. + */ + int applyExplicitNonce(Authenticator authenticator, + byte contentType, byte[] buf, int offset, + int cipheredLength) throws BadPaddingException { + + ByteBuffer bb = ByteBuffer.wrap(buf, offset, cipheredLength); + + return applyExplicitNonce(authenticator, contentType, bb); + } + + /* + * Creates the explicit nonce/IV to this cipher. This method is used to + * encrypt an SSL/TLS output record. + * + * The size of the returned array is the SecurityParameters.record_iv_length + * in RFC 4346/5246. It is the size of explicit IV for CBC mode, and the + * size of explicit nonce for AEAD mode. + * + * @param authenticator the authenticator to get the additional + * authentication data + * @param contentType the content type of the input record + * @param fragmentLength the fragment length of the output record, it is + * the TLSCompressed.length in RFC 4346/5246. + * + * @return the explicit nonce of the cipher. + */ + byte[] createExplicitNonce(Authenticator authenticator, + byte contentType, int fragmentLength) { + + byte[] nonce = new byte[0]; + switch (cipherType) { + case BLOCK_CIPHER: + if (protocolVersion.v >= ProtocolVersion.TLS11.v) { + // For block ciphers, the explicit IV length is of length + // SecurityParameters.record_iv_length, which is equal to + // the SecurityParameters.block_size. + // + // Generate a random number as the explicit IV parameter. + nonce = new byte[cipher.getBlockSize()]; + random.nextBytes(nonce); + } + break; + case AEAD_CIPHER: + // To be unique and aware of overflow-wrap, sequence number + // is used as the nonce_explicit of AEAD cipher suites. + nonce = authenticator.sequenceNumber(); + + // initialize the AEAD cipher for the unique IV + byte[] iv = Arrays.copyOf(fixedIv, + fixedIv.length + nonce.length); + System.arraycopy(nonce, 0, iv, fixedIv.length, nonce.length); + GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv); + try { + cipher.init(mode, key, spec, random); + } catch (InvalidKeyException | + InvalidAlgorithmParameterException ikae) { + // unlikely to happen + throw new RuntimeException( + "invalid key or spec in GCM mode", ikae); + } + + // update the additional authentication data + byte[] aad = authenticator.acquireAuthenticationBytes( + contentType, fragmentLength); + cipher.updateAAD(aad); + break; + } + + return nonce; + } + + /* + * Is this cipher available? + * + * This method can only be called by CipherSuite.BulkCipher.isAvailable() + * to test the availability of a cipher suites. Please DON'T use it in + * other places, otherwise, the behavior may be unexpected because we may + * initialize AEAD cipher improperly in the method. + */ + Boolean isAvailable() { + // We won't know whether a cipher for a particular key size is + // available until the cipher is successfully initialized. + // + // We do not initialize AEAD cipher in the constructor. Need to + // initialize the cipher to ensure that the AEAD mode for a + // particular key size is supported. + if (cipherType == AEAD_CIPHER) { + try { + Authenticator authenticator = + new Authenticator(protocolVersion); + byte[] nonce = authenticator.sequenceNumber(); + byte[] iv = Arrays.copyOf(fixedIv, + fixedIv.length + nonce.length); + System.arraycopy(nonce, 0, iv, fixedIv.length, nonce.length); + GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv); + + cipher.init(mode, key, spec, random); + } catch (Exception e) { + return Boolean.FALSE; + } + } // Otherwise, we have initialized the cipher in the constructor. + + return Boolean.TRUE; } } diff --git a/jdk/src/share/classes/sun/security/ssl/CipherSuite.java b/jdk/src/share/classes/sun/security/ssl/CipherSuite.java index 555304880b7..435693751c7 100644 --- a/jdk/src/share/classes/sun/security/ssl/CipherSuite.java +++ b/jdk/src/share/classes/sun/security/ssl/CipherSuite.java @@ -33,12 +33,14 @@ import java.security.InvalidKeyException; import java.security.SecureRandom; import java.security.KeyManagementException; +import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import static sun.security.ssl.CipherSuite.KeyExchange.*; import static sun.security.ssl.CipherSuite.PRF.*; +import static sun.security.ssl.CipherSuite.CipherType.*; import static sun.security.ssl.JsseJce.*; /** @@ -135,7 +137,9 @@ final class CipherSuite implements Comparable<CipherSuite> { this.keyExchange = keyExchange; this.cipher = cipher; this.exportable = cipher.exportable; - if (name.endsWith("_MD5")) { + if (cipher.cipherType == CipherType.AEAD_CIPHER) { + macAlg = M_NULL; + } else if (name.endsWith("_MD5")) { macAlg = M_MD5; } else if (name.endsWith("_SHA")) { macAlg = M_SHA; @@ -385,6 +389,12 @@ final class CipherSuite implements Comparable<CipherSuite> { } } + static enum CipherType { + STREAM_CIPHER, // null or stream cipher + BLOCK_CIPHER, // block cipher in CBC mode + AEAD_CIPHER // AEAD cipher + } + /** * An SSL/TLS bulk cipher algorithm. One instance per combination of * cipher and key length. @@ -417,14 +427,26 @@ final class CipherSuite implements Comparable<CipherSuite> { // for non-exportable ciphers, this is the same as keySize final int expandedKeySize; - // size of the IV (also block size) + // size of the IV final int ivSize; + // size of fixed IV + // + // record_iv_length = ivSize - fixedIvSize + final int fixedIvSize; + // exportable under 512/40 bit rules final boolean exportable; // Is the cipher algorithm of Cipher Block Chaining (CBC) mode? - final boolean isCBCMode; + final CipherType cipherType; + + // size of the authentication tag, only applicable to cipher suites in + // Galois Counter Mode (GCM) + // + // As far as we know, all supported GCM cipher suites use 128-bits + // authentication tags. + final int tagSize = 16; // The secure random used to detect the cipher availability. private final static SecureRandom secureRandom; @@ -437,32 +459,34 @@ final class CipherSuite implements Comparable<CipherSuite> { } } - BulkCipher(String transformation, int keySize, - int expandedKeySize, int ivSize, boolean allowed) { + BulkCipher(String transformation, CipherType cipherType, int keySize, + int expandedKeySize, int ivSize, + int fixedIvSize, boolean allowed) { + this.transformation = transformation; String[] splits = transformation.split("/"); this.algorithm = splits[0]; - this.isCBCMode = - splits.length <= 1 ? false : "CBC".equalsIgnoreCase(splits[1]); + this.cipherType = cipherType; this.description = this.algorithm + "/" + (keySize << 3); this.keySize = keySize; this.ivSize = ivSize; + this.fixedIvSize = fixedIvSize; this.allowed = allowed; this.expandedKeySize = expandedKeySize; this.exportable = true; } - BulkCipher(String transformation, int keySize, - int ivSize, boolean allowed) { + BulkCipher(String transformation, CipherType cipherType, int keySize, + int ivSize, int fixedIvSize, boolean allowed) { this.transformation = transformation; String[] splits = transformation.split("/"); this.algorithm = splits[0]; - this.isCBCMode = - splits.length <= 1 ? false : "CBC".equalsIgnoreCase(splits[1]); + this.cipherType = cipherType; this.description = this.algorithm + "/" + (keySize << 3); this.keySize = keySize; this.ivSize = ivSize; + this.fixedIvSize = fixedIvSize; this.allowed = allowed; this.expandedKeySize = keySize; @@ -486,16 +510,20 @@ final class CipherSuite implements Comparable<CipherSuite> { * Test if this bulk cipher is available. For use by CipherSuite. * * Currently all supported ciphers except AES are always available - * via the JSSE internal implementations. We also assume AES/128 - * is always available since it is shipped with the SunJCE provider. - * However, AES/256 is unavailable when the default JCE policy - * jurisdiction files are installed because of key length restrictions. + * via the JSSE internal implementations. We also assume AES/128 of + * CBC mode is always available since it is shipped with the SunJCE + * provider. However, AES/256 is unavailable when the default JCE + * policy jurisdiction files are installed because of key length + * restrictions, and AEAD is unavailable when the underlying providers + * do not support AEAD/GCM mode. */ boolean isAvailable() { if (allowed == false) { return false; } - if (this == B_AES_256) { + + if ((this == B_AES_256) || + (this.cipherType == CipherType.AEAD_CIPHER)) { return isAvailable(this); } @@ -513,19 +541,50 @@ final class CipherSuite implements Comparable<CipherSuite> { private static synchronized boolean isAvailable(BulkCipher cipher) { Boolean b = availableCache.get(cipher); if (b == null) { - try { - SecretKey key = new SecretKeySpec - (new byte[cipher.expandedKeySize], cipher.algorithm); - IvParameterSpec iv = - new IvParameterSpec(new byte[cipher.ivSize]); - cipher.newCipher(ProtocolVersion.DEFAULT, - key, iv, secureRandom, true); - b = Boolean.TRUE; - } catch (NoSuchAlgorithmException e) { - b = Boolean.FALSE; + int keySizeInBits = cipher.keySize * 8; + if (keySizeInBits > 128) { // need the JCE unlimited + // strength jurisdiction policy + try { + if (Cipher.getMaxAllowedKeyLength( + cipher.transformation) < keySizeInBits) { + b = Boolean.FALSE; + } + } catch (Exception e) { + b = Boolean.FALSE; + } } + + if (b == null) { + b = Boolean.FALSE; // may be reset to TRUE if + // the cipher is available + CipherBox temporary = null; + try { + SecretKey key = new SecretKeySpec( + new byte[cipher.expandedKeySize], + cipher.algorithm); + IvParameterSpec iv; + if (cipher.cipherType == CipherType.AEAD_CIPHER) { + iv = new IvParameterSpec( + new byte[cipher.fixedIvSize]); + } else { + iv = new IvParameterSpec(new byte[cipher.ivSize]); + } + temporary = cipher.newCipher( + ProtocolVersion.DEFAULT, + key, iv, secureRandom, true); + b = temporary.isAvailable(); + } catch (NoSuchAlgorithmException e) { + // not available + } finally { + if (temporary != null) { + temporary.dispose(); + } + } + } + availableCache.put(cipher, b); } + return b.booleanValue(); } @@ -573,27 +632,31 @@ final class CipherSuite implements Comparable<CipherSuite> { // export strength ciphers final static BulkCipher B_NULL = - new BulkCipher("NULL", 0, 0, 0, true); + new BulkCipher("NULL", STREAM_CIPHER, 0, 0, 0, 0, true); final static BulkCipher B_RC4_40 = - new BulkCipher(CIPHER_RC4, 5, 16, 0, true); + new BulkCipher(CIPHER_RC4, STREAM_CIPHER, 5, 16, 0, 0, true); final static BulkCipher B_RC2_40 = - new BulkCipher("RC2", 5, 16, 8, false); + new BulkCipher("RC2", BLOCK_CIPHER, 5, 16, 8, 0, false); final static BulkCipher B_DES_40 = - new BulkCipher(CIPHER_DES, 5, 8, 8, true); + new BulkCipher(CIPHER_DES, BLOCK_CIPHER, 5, 8, 8, 0, true); // domestic strength ciphers final static BulkCipher B_RC4_128 = - new BulkCipher(CIPHER_RC4, 16, 0, true); + new BulkCipher(CIPHER_RC4, STREAM_CIPHER, 16, 0, 0, true); final static BulkCipher B_DES = - new BulkCipher(CIPHER_DES, 8, 8, true); + new BulkCipher(CIPHER_DES, BLOCK_CIPHER, 8, 8, 0, true); final static BulkCipher B_3DES = - new BulkCipher(CIPHER_3DES, 24, 8, true); + new BulkCipher(CIPHER_3DES, BLOCK_CIPHER, 24, 8, 0, true); final static BulkCipher B_IDEA = - new BulkCipher("IDEA", 16, 8, false); + new BulkCipher("IDEA", BLOCK_CIPHER, 16, 8, 0, false); final static BulkCipher B_AES_128 = - new BulkCipher(CIPHER_AES, 16, 16, true); + new BulkCipher(CIPHER_AES, BLOCK_CIPHER, 16, 16, 0, true); final static BulkCipher B_AES_256 = - new BulkCipher(CIPHER_AES, 32, 16, true); + new BulkCipher(CIPHER_AES, BLOCK_CIPHER, 32, 16, 0, true); + final static BulkCipher B_AES_128_GCM = + new BulkCipher(CIPHER_AES_GCM, AEAD_CIPHER, 16, 12, 4, true); + final static BulkCipher B_AES_256_GCM = + new BulkCipher(CIPHER_AES_GCM, AEAD_CIPHER, 32, 12, 4, true); // MACs final static MacAlg M_NULL = new MacAlg("NULL", 0); @@ -893,11 +956,12 @@ final class CipherSuite implements Comparable<CipherSuite> { * Definition of the CipherSuites that are enabled by default. * They are listed in preference order, most preferred first, using * the following criteria: - * 1. Prefer the stronger buld cipher, in the order of AES_256, - * AES_128, RC-4, 3DES-EDE. - * 2. Prefer the stronger MAC algorithm, in the order of SHA384, + * 1. Prefer Suite B compliant cipher suites, see RFC6460. + * 2. Prefer the stronger bulk cipher, in the order of AES_256(GCM), + * AES_128(GCM), AES_256, AES_128, RC-4, 3DES-EDE. + * 3. Prefer the stronger MAC algorithm, in the order of SHA384, * SHA256, SHA, MD5. - * 3. Prefer the better performance of key exchange and digital + * 4. Prefer the better performance of key exchange and digital * signature algorithm, in the order of ECDHE-ECDSA, ECDHE-RSA, * RSA, ECDH-ECDSA, ECDH-RSA, DHE-RSA, DHE-DSS. */ @@ -910,6 +974,16 @@ final class CipherSuite implements Comparable<CipherSuite> { // ID Key Exchange Cipher A obs suprt PRF // ====== ============ ========= = === ===== ======== + + + // Placeholder for cipher suites in GCM mode. + // + // For better compatibility and interoperability, we decrease the + // priority of cipher suites in GCM mode for a while as GCM + // technologies mature in the industry. Eventually we'll move + // the GCM suites here. + + // AES_256(CBC) add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", 0xc024, --p, K_ECDHE_ECDSA, B_AES_256, T, max, tls12, P_SHA384); add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", @@ -940,6 +1014,7 @@ final class CipherSuite implements Comparable<CipherSuite> { add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", 0x0038, --p, K_DHE_DSS, B_AES_256, T); + // AES_128(CBC) add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 0xc023, --p, K_ECDHE_ECDSA, B_AES_128, T, max, tls12, P_SHA256); add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", @@ -970,6 +1045,7 @@ final class CipherSuite implements Comparable<CipherSuite> { add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", 0x0032, --p, K_DHE_DSS, B_AES_128, T); + // RC-4 add("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 0xC007, --p, K_ECDHE_ECDSA, B_RC4_128, N); add("TLS_ECDHE_RSA_WITH_RC4_128_SHA", @@ -981,6 +1057,51 @@ final class CipherSuite implements Comparable<CipherSuite> { add("TLS_ECDH_RSA_WITH_RC4_128_SHA", 0xC00C, --p, K_ECDH_RSA, B_RC4_128, N); + // Cipher suites in GCM mode, see RFC 5288/5289. + // + // We may increase the priority of cipher suites in GCM mode when + // GCM technologies become mature in the industry. + + // Suite B compliant cipher suites, see RFC 6460. + // + // Note that, at present this provider is not Suite B compliant. The + // preference order of the GCM cipher suites does not follow the spec + // of RFC 6460. + add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + 0xc02c, --p, K_ECDHE_ECDSA, B_AES_256_GCM, T, max, tls12, P_SHA384); + add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + 0xc02b, --p, K_ECDHE_ECDSA, B_AES_128_GCM, T, max, tls12, P_SHA256); + + // AES_256(GCM) + add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + 0xc030, --p, K_ECDHE_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); + add("TLS_RSA_WITH_AES_256_GCM_SHA384", + 0x009d, --p, K_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); + add("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", + 0xc02e, --p, K_ECDH_ECDSA, B_AES_256_GCM, T, max, tls12, P_SHA384); + add("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", + 0xc032, --p, K_ECDH_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); + add("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", + 0x009f, --p, K_DHE_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); + add("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", + 0x00a3, --p, K_DHE_DSS, B_AES_256_GCM, T, max, tls12, P_SHA384); + + // AES_128(GCM) + add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + 0xc02f, --p, K_ECDHE_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); + add("TLS_RSA_WITH_AES_128_GCM_SHA256", + 0x009c, --p, K_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); + add("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", + 0xc02d, --p, K_ECDH_ECDSA, B_AES_128_GCM, T, max, tls12, P_SHA256); + add("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", + 0xc031, --p, K_ECDH_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); + add("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", + 0x009e, --p, K_DHE_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); + add("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", + 0x00a2, --p, K_DHE_DSS, B_AES_128_GCM, T, max, tls12, P_SHA256); + // End of cipher suites in GCM mode. + + // 3DES_EDE add("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xC008, --p, K_ECDHE_ECDSA, B_3DES, T); add("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", @@ -1024,17 +1145,22 @@ final class CipherSuite implements Comparable<CipherSuite> { */ p = DEFAULT_SUITES_PRIORITY; + add("TLS_DH_anon_WITH_AES_256_GCM_SHA384", + 0x00a7, --p, K_DH_ANON, B_AES_256_GCM, N, max, tls12, P_SHA384); + add("TLS_DH_anon_WITH_AES_128_GCM_SHA256", + 0x00a6, --p, K_DH_ANON, B_AES_128_GCM, N, max, tls12, P_SHA256); + add("TLS_DH_anon_WITH_AES_256_CBC_SHA256", 0x006d, --p, K_DH_ANON, B_AES_256, N, max, tls12, P_SHA256); add("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", - 0xC019, --p, K_ECDH_ANON, B_AES_256, T); + 0xC019, --p, K_ECDH_ANON, B_AES_256, N); add("TLS_DH_anon_WITH_AES_256_CBC_SHA", 0x003a, --p, K_DH_ANON, B_AES_256, N); add("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x006c, --p, K_DH_ANON, B_AES_128, N, max, tls12, P_SHA256); add("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", - 0xC018, --p, K_ECDH_ANON, B_AES_128, T); + 0xC018, --p, K_ECDH_ANON, B_AES_128, N); add("TLS_DH_anon_WITH_AES_128_CBC_SHA", 0x0034, --p, K_DH_ANON, B_AES_128, N); @@ -1044,7 +1170,7 @@ final class CipherSuite implements Comparable<CipherSuite> { 0x0018, --p, K_DH_ANON, B_RC4_128, N); add("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", - 0xC017, --p, K_ECDH_ANON, B_3DES, T); + 0xC017, --p, K_ECDH_ANON, B_3DES, N); add("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", 0x001b, --p, K_DH_ANON, B_3DES, N); @@ -1199,18 +1325,10 @@ final class CipherSuite implements Comparable<CipherSuite> { add("TLS_DH_RSA_WITH_AES_256_CBC_SHA256", 0x0069); // Unsupported cipher suites from RFC 5288 - add("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x009c); - add("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x009d); - add("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x009e); - add("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x009f); add("TLS_DH_RSA_WITH_AES_128_GCM_SHA256", 0x00a0); add("TLS_DH_RSA_WITH_AES_256_GCM_SHA384", 0x00a1); - add("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x00a2); - add("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x00a3); add("TLS_DH_DSS_WITH_AES_128_GCM_SHA256", 0x00a4); add("TLS_DH_DSS_WITH_AES_256_GCM_SHA384", 0x00a5); - add("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x00a6); - add("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x00a7); // Unsupported cipher suites from RFC 5487 add("TLS_PSK_WITH_AES_128_GCM_SHA256", 0x00a8); @@ -1269,16 +1387,6 @@ final class CipherSuite implements Comparable<CipherSuite> { add("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", 0xc021); add("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", 0xc022); - // Unsupported cipher suites from RFC 5289 - add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02b); - add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02c); - add("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02d); - add("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02e); - add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0xc02f); - add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0xc030); - add("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0xc031); - add("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0xc032); - // Unsupported cipher suites from RFC 5489 add("TLS_ECDHE_PSK_WITH_RC4_128_SHA", 0xc033); add("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", 0xc034); diff --git a/jdk/src/share/classes/sun/security/ssl/EngineInputRecord.java b/jdk/src/share/classes/sun/security/ssl/EngineInputRecord.java index 6b064385203..0464d5b5de9 100644 --- a/jdk/src/share/classes/sun/security/ssl/EngineInputRecord.java +++ b/jdk/src/share/classes/sun/security/ssl/EngineInputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -177,71 +177,6 @@ final class EngineInputRecord extends InputRecord { return len; } - /* - * Verifies and removes the MAC value. Returns true if - * the MAC checks out OK. - * - * On entry: - * position = beginning of app/MAC data - * limit = end of MAC data. - * - * On return: - * position = beginning of app data - * limit = end of app data - */ - boolean checkMAC(MAC signer, ByteBuffer bb) { - if (internalData) { - return checkMAC(signer); - } - - int len = signer.MAClen(); - if (len == 0) { // no mac - return true; - } - - /* - * Grab the original limit - */ - int lim = bb.limit(); - - /* - * Delineate the area to apply a MAC on. - */ - int macData = lim - len; - bb.limit(macData); - - byte[] mac = signer.compute(contentType(), bb); - - if (len != mac.length) { - throw new RuntimeException("Internal MAC error"); - } - - /* - * Delineate the MAC values, position was already set - * by doing the compute above. - * - * We could zero the MAC area, but not much useful information - * there anyway. - */ - bb.position(macData); - bb.limit(lim); - - try { - for (int i = 0; i < len; i++) { - if (bb.get() != mac[i]) { // No BB.equals(byte []); ! - return false; - } - } - return true; - } finally { - /* - * Position to the data. - */ - bb.rewind(); - bb.limit(macData); - } - } - /* * Pass the data down if it's internally cached, otherwise * do it here. @@ -251,16 +186,85 @@ final class EngineInputRecord extends InputRecord { * If external data(app), return a new ByteBuffer with data to * process. */ - ByteBuffer decrypt(CipherBox box, ByteBuffer bb) - throws BadPaddingException { + ByteBuffer decrypt(Authenticator authenticator, + CipherBox box, ByteBuffer bb) throws BadPaddingException { if (internalData) { - decrypt(box); + decrypt(authenticator, box); // MAC is checked during decryption return tmpBB; } - box.decrypt(bb); - bb.rewind(); + BadPaddingException bpe = null; + if (!box.isNullCipher()) { + try { + // apply explicit nonce for AEAD/CBC cipher suites if needed + int nonceSize = + box.applyExplicitNonce(authenticator, contentType(), bb); + + // decrypt the content + if (box.isAEADMode()) { + // DON'T encrypt the nonce_explicit for AEAD mode + bb.position(bb.position() + nonceSize); + } // The explicit IV for CBC mode can be decrypted. + + box.decrypt(bb); + bb.position(nonceSize); // We don't actually remove the nonce. + } catch (BadPaddingException e) { + // RFC 2246 states that decryption_failed should be used + // for this purpose. However, that allows certain attacks, + // so we just send bad record MAC. We also need to make + // sure to always check the MAC to avoid a timing attack + // for the same issue. See paper by Vaudenay et al and the + // update in RFC 4346/5246. + // + // Failover to message authentication code checking. + bpe = new BadPaddingException("invalid padding"); + } + } + + // Requires message authentication code for null, stream and block + // cipher suites. + if (authenticator instanceof MAC) { + MAC signer = (MAC)authenticator; + int macLen = signer.MAClen(); + if (macLen != 0) { + if (bb.remaining() < macLen) { + // negative data length, something is wrong + throw new BadPaddingException("bad record"); + } + + int position = bb.position(); + int limit = bb.limit(); + int macOffset = limit - macLen; + + bb.limit(macOffset); + byte[] hash = signer.compute(contentType(), bb); + if (hash == null || macLen != hash.length) { + // something is wrong with MAC implementation + throw new RuntimeException("Internal MAC error"); + } + + bb.position(macOffset); + bb.limit(limit); + + try { + for (byte b : hash) { // No BB.equals(byte []); ! + if (bb.get() != b) { + throw new BadPaddingException("bad record MAC"); + } + } + } finally { + // reset to the data + bb.position(position); + bb.limit(macOffset); + } + } + } + + // Is it a failover? + if (bpe != null) { + throw bpe; + } return bb.slice(); } @@ -338,8 +342,8 @@ final class EngineInputRecord extends InputRecord { if (debug != null && Debug.isOn("packet")) { try { HexDumpEncoder hd = new HexDumpEncoder(); - srcBB.limit(srcPos + len); ByteBuffer bb = srcBB.duplicate(); // Use copy of BB + bb.limit(srcPos + len); System.out.println("[Raw read (bb)]: length = " + len); hd.encodeBuffer(bb, System.out); diff --git a/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java b/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java index e9d39805b36..a46a88bf708 100644 --- a/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java +++ b/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java @@ -29,7 +29,6 @@ package sun.security.ssl; import java.io.*; import java.nio.*; - /** * A OutputRecord class extension which uses external ByteBuffers * or the internal ByteArrayOutputStream for data manipulations. @@ -101,51 +100,6 @@ final class EngineOutputRecord extends OutputRecord { return finishedMsg; } - - /** - * Calculate the MAC value, storing the result either in - * the internal buffer, or at the end of the destination - * ByteBuffer. - * <P> - * We assume that the higher levels have assured us enough - * room, otherwise we'll indirectly throw a - * BufferOverFlowException runtime exception. - * - * position should equal limit, and points to the next - * free spot. - */ - private void addMAC(MAC signer, ByteBuffer bb) - throws IOException { - - if (signer.MAClen() != 0) { - byte[] hash = signer.compute(contentType(), bb); - - /* - * position was advanced to limit in compute above. - * - * Mark next area as writable (above layers should have - * established that we have plenty of room), then write - * out the hash. - */ - bb.limit(bb.limit() + hash.length); - bb.put(hash); - } - } - - /* - * Encrypt a ByteBuffer. - * - * We assume that the higher levels have assured us enough - * room for the encryption (plus padding), otherwise we'll - * indirectly throw a BufferOverFlowException runtime exception. - * - * position and limit will be the same, and points to the - * next free spot. - */ - void encrypt(CipherBox box, ByteBuffer bb) { - box.encrypt(bb); - } - /* * Override the actual write below. We do things this way to be * consistent with InputRecord. InputRecord may try to write out @@ -160,7 +114,8 @@ final class EngineOutputRecord extends OutputRecord { * Copy data out of buffer, it's ready to go. */ ByteBuffer netBB = (ByteBuffer) - ByteBuffer.allocate(len).put(buf, 0, len).flip(); + ByteBuffer.allocate(len).put(buf, off, len).flip(); + writer.putOutboundData(netBB); } @@ -168,17 +123,19 @@ final class EngineOutputRecord extends OutputRecord { * Main method for writing non-application data. * We MAC/encrypt, then send down for processing. */ - void write(MAC writeMAC, CipherBox writeCipher) throws IOException { + void write(Authenticator authenticator, CipherBox writeCipher) + throws IOException { + /* * Sanity check. */ switch (contentType()) { - case ct_change_cipher_spec: - case ct_alert: - case ct_handshake: - break; - default: - throw new RuntimeException("unexpected byte buffers"); + case ct_change_cipher_spec: + case ct_alert: + case ct_handshake: + break; + default: + throw new RuntimeException("unexpected byte buffers"); } /* @@ -193,10 +150,10 @@ final class EngineOutputRecord extends OutputRecord { */ if (!isEmpty()) { // compress(); // eventually - addMAC(writeMAC); - encrypt(writeCipher); - write((OutputStream)null, false, // send down for processing - (ByteArrayOutputStream)null); + encrypt(authenticator, writeCipher); + + // send down for processing + write((OutputStream)null, false, (ByteArrayOutputStream)null); } return; } @@ -204,8 +161,8 @@ final class EngineOutputRecord extends OutputRecord { /** * Main wrap/write driver. */ - void write(EngineArgs ea, MAC writeMAC, CipherBox writeCipher) - throws IOException { + void write(EngineArgs ea, Authenticator authenticator, + CipherBox writeCipher) throws IOException { /* * sanity check to make sure someone didn't inadvertantly * send us an impossible combination we don't know how @@ -217,7 +174,7 @@ final class EngineOutputRecord extends OutputRecord { * Have we set the MAC's yet? If not, we're not ready * to process application data yet. */ - if (writeMAC == MAC.NULL) { + if (authenticator == MAC.NULL) { return; } @@ -255,7 +212,7 @@ final class EngineOutputRecord extends OutputRecord { */ int length; if (engine.needToSplitPayload(writeCipher, protocolVersion)) { - write(ea, writeMAC, writeCipher, 0x01); + write(ea, authenticator, writeCipher, 0x01); ea.resetLim(); // reset application data buffer limit length = Math.min(ea.getAppRemaining(), maxDataSizeMinusOneByteRecord); @@ -265,14 +222,14 @@ final class EngineOutputRecord extends OutputRecord { // Don't bother to really write empty records. if (length > 0) { - write(ea, writeMAC, writeCipher, length); + write(ea, authenticator, writeCipher, length); } return; } - void write(EngineArgs ea, MAC writeMAC, CipherBox writeCipher, - int length) throws IOException { + void write(EngineArgs ea, Authenticator authenticator, + CipherBox writeCipher, int length) throws IOException { /* * Copy out existing buffer values. */ @@ -286,39 +243,76 @@ final class EngineOutputRecord extends OutputRecord { * Don't need to worry about SSLv2 rewrites, if we're here, * that's long since done. */ - int dstData = dstPos + headerSize; + int dstData = dstPos + headerSize + writeCipher.getExplicitNonceSize(); dstBB.position(dstData); + /* + * transfer application data into the network data buffer + */ ea.gather(length); + dstBB.limit(dstBB.position()); + dstBB.position(dstData); /* * "flip" but skip over header again, add MAC & encrypt - * addMAC will expand the limit to reflect the new - * data. */ - dstBB.limit(dstBB.position()); - dstBB.position(dstData); - addMAC(writeMAC, dstBB); + if (authenticator instanceof MAC) { + MAC signer = (MAC)authenticator; + if (signer.MAClen() != 0) { + byte[] hash = signer.compute(contentType(), dstBB); - /* - * Encrypt may pad, so again the limit may have changed. - */ - dstBB.limit(dstBB.position()); - dstBB.position(dstData); - encrypt(writeCipher, dstBB); + /* + * position was advanced to limit in compute above. + * + * Mark next area as writable (above layers should have + * established that we have plenty of room), then write + * out the hash. + */ + dstBB.limit(dstBB.limit() + hash.length); + dstBB.put(hash); - if (debug != null - && (Debug.isOn("record") || Debug.isOn("handshake"))) { - if ((debug != null && Debug.isOn("record")) - || contentType() == ct_change_cipher_spec) + // reset the position and limit + dstBB.limit(dstBB.position()); + dstBB.position(dstData); + } + } + + if (!writeCipher.isNullCipher()) { + /* + * Requires explicit IV/nonce for CBC/AEAD cipher suites for TLS 1.1 + * or later. + */ + if (protocolVersion.v >= ProtocolVersion.TLS11.v && + (writeCipher.isCBCMode() || writeCipher.isAEADMode())) { + byte[] nonce = writeCipher.createExplicitNonce( + authenticator, contentType(), dstBB.remaining()); + dstBB.position(dstPos + headerSize); + dstBB.put(nonce); + if (!writeCipher.isAEADMode()) { + // The explicit IV in TLS 1.1 and later can be encrypted. + dstBB.position(dstPos + headerSize); + } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode + } + + /* + * Encrypt may pad, so again the limit may have changed. + */ + writeCipher.encrypt(dstBB, dstLim); + + if ((debug != null) && (Debug.isOn("record") || + (Debug.isOn("handshake") && + (contentType() == ct_change_cipher_spec)))) { System.out.println(Thread.currentThread().getName() // v3.0/v3.1 ... + ", WRITE: " + protocolVersion + " " + InputRecord.contentName(contentType()) + ", length = " + length); + } + } else { + dstBB.position(dstBB.limit()); } - int packetLength = dstBB.limit() - dstData; + int packetLength = dstBB.limit() - dstPos - headerSize; /* * Finish out the record header. @@ -333,7 +327,5 @@ final class EngineOutputRecord extends OutputRecord { * Position was already set by encrypt() above. */ dstBB.limit(dstLim); - - return; } } diff --git a/jdk/src/share/classes/sun/security/ssl/EngineWriter.java b/jdk/src/share/classes/sun/security/ssl/EngineWriter.java index e08dbb06069..c6a26562606 100644 --- a/jdk/src/share/classes/sun/security/ssl/EngineWriter.java +++ b/jdk/src/share/classes/sun/security/ssl/EngineWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -99,7 +99,8 @@ final class EngineWriter { * other writeRecord. */ synchronized void writeRecord(EngineOutputRecord outputRecord, - MAC writeMAC, CipherBox writeCipher) throws IOException { + Authenticator authenticator, + CipherBox writeCipher) throws IOException { /* * Only output if we're still open. @@ -108,7 +109,7 @@ final class EngineWriter { throw new IOException("writer side was already closed."); } - outputRecord.write(writeMAC, writeCipher); + outputRecord.write(authenticator, writeCipher); /* * Did our handshakers notify that we just sent the @@ -151,7 +152,8 @@ final class EngineWriter { * Return any determined status. */ synchronized HandshakeStatus writeRecord( - EngineOutputRecord outputRecord, EngineArgs ea, MAC writeMAC, + EngineOutputRecord outputRecord, EngineArgs ea, + Authenticator authenticator, CipherBox writeCipher) throws IOException { /* @@ -181,7 +183,7 @@ final class EngineWriter { throw new IOException("The write side was already closed"); } - outputRecord.write(ea, writeMAC, writeCipher); + outputRecord.write(ea, authenticator, writeCipher); if (debug != null && Debug.isOn("packet")) { dumpPacket(ea, false); diff --git a/jdk/src/share/classes/sun/security/ssl/Handshaker.java b/jdk/src/share/classes/sun/security/ssl/Handshaker.java index 828b60bcab6..d03b8f7e5ac 100644 --- a/jdk/src/share/classes/sun/security/ssl/Handshaker.java +++ b/jdk/src/share/classes/sun/security/ssl/Handshaker.java @@ -49,6 +49,7 @@ import sun.security.ssl.HandshakeMessage.*; import sun.security.ssl.CipherSuite.*; import static sun.security.ssl.CipherSuite.PRF.*; +import static sun.security.ssl.CipherSuite.CipherType.*; /** * Handshaker ... processes handshake records from an SSL V3.0 @@ -714,33 +715,47 @@ abstract class Handshaker { /** * Create a new read MAC and return it to caller. */ - MAC newReadMAC() throws NoSuchAlgorithmException, InvalidKeyException { - MacAlg macAlg = cipherSuite.macAlg; - MAC mac; - if (isClient) { - mac = macAlg.newMac(protocolVersion, svrMacSecret); - svrMacSecret = null; + Authenticator newReadAuthenticator() + throws NoSuchAlgorithmException, InvalidKeyException { + + Authenticator authenticator = null; + if (cipherSuite.cipher.cipherType == AEAD_CIPHER) { + authenticator = new Authenticator(protocolVersion); } else { - mac = macAlg.newMac(protocolVersion, clntMacSecret); - clntMacSecret = null; + MacAlg macAlg = cipherSuite.macAlg; + if (isClient) { + authenticator = macAlg.newMac(protocolVersion, svrMacSecret); + svrMacSecret = null; + } else { + authenticator = macAlg.newMac(protocolVersion, clntMacSecret); + clntMacSecret = null; + } } - return mac; + + return authenticator; } /** * Create a new write MAC and return it to caller. */ - MAC newWriteMAC() throws NoSuchAlgorithmException, InvalidKeyException { - MacAlg macAlg = cipherSuite.macAlg; - MAC mac; - if (isClient) { - mac = macAlg.newMac(protocolVersion, clntMacSecret); - clntMacSecret = null; + Authenticator newWriteAuthenticator() + throws NoSuchAlgorithmException, InvalidKeyException { + + Authenticator authenticator = null; + if (cipherSuite.cipher.cipherType == AEAD_CIPHER) { + authenticator = new Authenticator(protocolVersion); } else { - mac = macAlg.newMac(protocolVersion, svrMacSecret); - svrMacSecret = null; + MacAlg macAlg = cipherSuite.macAlg; + if (isClient) { + authenticator = macAlg.newMac(protocolVersion, clntMacSecret); + clntMacSecret = null; + } else { + authenticator = macAlg.newMac(protocolVersion, svrMacSecret); + svrMacSecret = null; + } } - return mac; + + return authenticator; } /* @@ -1189,11 +1204,23 @@ abstract class Handshaker { int prfHashLength = prf.getPRFHashLength(); int prfBlockSize = prf.getPRFBlockSize(); + // TLS v1.1 or later uses an explicit IV in CBC cipher suites to + // protect against the CBC attacks. AEAD/GCM cipher suites in TLS + // v1.2 or later use a fixed IV as the implicit part of the partially + // implicit nonce technique described in RFC 5116. + int ivSize = cipher.ivSize; + if (cipher.cipherType == AEAD_CIPHER) { + ivSize = cipher.fixedIvSize; + } else if (protocolVersion.v >= ProtocolVersion.TLS11.v && + cipher.cipherType == BLOCK_CIPHER) { + ivSize = 0; + } + TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec( masterKey, protocolVersion.major, protocolVersion.minor, clnt_random.random_bytes, svr_random.random_bytes, cipher.algorithm, cipher.keySize, expandedKeySize, - cipher.ivSize, hashSize, + ivSize, hashSize, prfHashAlg, prfHashLength, prfBlockSize); try { @@ -1201,14 +1228,15 @@ abstract class Handshaker { kg.init(spec); TlsKeyMaterialSpec keySpec = (TlsKeyMaterialSpec)kg.generateKey(); + // Return null if cipher keys are not supposed to be generated. clntWriteKey = keySpec.getClientCipherKey(); svrWriteKey = keySpec.getServerCipherKey(); // Return null if IVs are not supposed to be generated. - // e.g. TLS 1.1+. clntWriteIV = keySpec.getClientIv(); svrWriteIV = keySpec.getServerIv(); + // Return null if MAC keys are not supposed to be generated. clntMacSecret = keySpec.getClientMacKey(); svrMacSecret = keySpec.getServerMacKey(); } catch (GeneralSecurityException e) { @@ -1233,10 +1261,14 @@ abstract class Handshaker { printHex(dump, masterKey.getEncoded()); // Outputs: - System.out.println("Client MAC write Secret:"); - printHex(dump, clntMacSecret.getEncoded()); - System.out.println("Server MAC write Secret:"); - printHex(dump, svrMacSecret.getEncoded()); + if (clntMacSecret != null) { + System.out.println("Client MAC write Secret:"); + printHex(dump, clntMacSecret.getEncoded()); + System.out.println("Server MAC write Secret:"); + printHex(dump, svrMacSecret.getEncoded()); + } else { + System.out.println("... no MAC keys used for this cipher"); + } if (clntWriteKey != null) { System.out.println("Client write key:"); diff --git a/jdk/src/share/classes/sun/security/ssl/InputRecord.java b/jdk/src/share/classes/sun/security/ssl/InputRecord.java index 78e866a07ca..74d88f9b81b 100644 --- a/jdk/src/share/classes/sun/security/ssl/InputRecord.java +++ b/jdk/src/share/classes/sun/security/ssl/InputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -77,6 +77,17 @@ class InputRecord extends ByteArrayInputStream implements Record { /* * Construct the record to hold the maximum sized input record. * Data will be filled in separately. + * + * The structure of the byte buffer looks like: + * + * |--------+---------+---------------------------------| + * | header | IV | content, MAC/TAG, padding, etc. | + * | headerPlusIVSize | + * + * header: the header of an SSL records + * IV: the optional IV/nonce field, it is only required for block + * (TLS 1.1 or later) and AEAD cipher suites. + * */ InputRecord() { super(new byte[maxRecordSize]); @@ -133,43 +144,82 @@ class InputRecord extends ByteArrayInputStream implements Record { return handshakeHash; } - /* - * Verify and remove the MAC ... used for all records. - */ - boolean checkMAC(MAC signer) { - int len = signer.MAClen(); - if (len == 0) { // no mac - return true; - } + void decrypt(Authenticator authenticator, + CipherBox box) throws BadPaddingException { - int offset = count - len; + BadPaddingException bpe = null; + if (!box.isNullCipher()) { + try { + int cipheredLength = count - headerSize; - if (offset < headerSize) { - // data length would be negative, something is wrong - return false; - } + // apply explicit nonce for AEAD/CBC cipher suites if needed + int nonceSize = box.applyExplicitNonce(authenticator, + contentType(), buf, headerSize, cipheredLength); + pos = headerSize + nonceSize; + lastHashed = pos; // don't digest the explicit nonce - byte[] mac = signer.compute(contentType(), buf, - headerSize, offset - headerSize); + // decrypt the content + int offset = headerSize; + if (box.isAEADMode()) { + // DON'T encrypt the nonce_explicit for AEAD mode + offset += nonceSize; + } // The explicit IV for CBC mode can be decrypted. - if (len != mac.length) { - throw new RuntimeException("Internal MAC error"); - } + count = offset + box.decrypt(buf, offset, count - offset); - for (int i = 0; i < len; i++) { - if (buf[offset + i] != mac[i]) { - return false; + // Note that we don't remove the nonce from the buffer. + } catch (BadPaddingException e) { + // RFC 2246 states that decryption_failed should be used + // for this purpose. However, that allows certain attacks, + // so we just send bad record MAC. We also need to make + // sure to always check the MAC to avoid a timing attack + // for the same issue. See paper by Vaudenay et al and the + // update in RFC 4346/5246. + // + // Failover to message authenticatoin code checking. + bpe = new BadPaddingException("invalid padding"); } } - count -= len; - return true; - } - void decrypt(CipherBox box) throws BadPaddingException { - int len = count - headerSize; - count = headerSize + box.decrypt(buf, headerSize, len); - } + // Requires message authentication code for null, stream and block + // cipher suites. + if (authenticator instanceof MAC) { + MAC signer = (MAC)authenticator; + int macLen = signer.MAClen(); + if (macLen != 0) { + int macOffset = count - macLen; + int contentLen = macOffset - pos; + if (contentLen < 0) { + // negative data length, something is wrong + throw new BadPaddingException("bad record"); + } + count -= macLen; // Set the count before any MAC checking + // exception occurs, so that the following + // process can read the actual decrypted + // content (minus the MAC) in the fragment + // if necessary. + byte[] hash = signer.compute(contentType(), + buf, pos, contentLen); + if (hash == null || macLen != hash.length) { + // something is wrong with MAC implementation + throw new RuntimeException("Internal MAC error"); + } + + int offset = macOffset; + for (byte b : hash) { + if (buf[offset++] != b) { + throw new BadPaddingException("bad record MAC"); + } + } + } + } + + // Is it a failover? + if (bpe != null) { + throw bpe; + } + } /* * Well ... hello_request messages are _never_ hashed since we can't diff --git a/jdk/src/share/classes/sun/security/ssl/JsseJce.java b/jdk/src/share/classes/sun/security/ssl/JsseJce.java index e22caece0e2..49e89c6028e 100644 --- a/jdk/src/share/classes/sun/security/ssl/JsseJce.java +++ b/jdk/src/share/classes/sun/security/ssl/JsseJce.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -154,6 +154,11 @@ final class JsseJce { * without padding. */ final static String CIPHER_AES = "AES/CBC/NoPadding"; + /** + * JCE transformation string for AES in GCM mode + * without padding. + */ + final static String CIPHER_AES_GCM = "AES/GCM/NoPadding"; /** * JCA identifier string for DSA, i.e. a DSA with SHA-1. */ diff --git a/jdk/src/share/classes/sun/security/ssl/MAC.java b/jdk/src/share/classes/sun/security/ssl/MAC.java index 753a8c57ac4..30bf2e2e50f 100644 --- a/jdk/src/share/classes/sun/security/ssl/MAC.java +++ b/jdk/src/share/classes/sun/security/ssl/MAC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -39,19 +39,15 @@ import static sun.security.ssl.CipherSuite.*; /** * This class computes the "Message Authentication Code" (MAC) for each - * SSL message. This is essentially a shared-secret signature, used to - * provide integrity protection for SSL messages. The MAC is actually - * one of several keyed hashes, as associated with the cipher suite and - * protocol version. (SSL v3.0 uses one construct, TLS uses another.) - * - * <P>NOTE: MAC computation is the only place in the SSL protocol that the - * sequence number is used. It's also reset to zero with each change of - * a cipher spec, so this is the only place this state is needed. + * SSL stream and block cipher message. This is essentially a shared-secret + * signature, used to provide integrity protection for SSL messages. The + * MAC is actually one of several keyed hashes, as associated with the cipher + * suite and protocol version. (SSL v3.0 uses one construct, TLS uses another.) * * @author David Brownell * @author Andreas Sterbenz */ -final class MAC { +final class MAC extends Authenticator { final static MAC NULL = new MAC(); @@ -64,26 +60,9 @@ final class MAC { // JCE Mac object private final Mac mac; - // byte array containing the additional information we MAC in each record - // (see below) - private final byte[] block; - - // sequence number + record type + + record length - private static final int BLOCK_SIZE_SSL = 8 + 1 + 2; - - // sequence number + record type + protocol version + record length - private static final int BLOCK_SIZE_TLS = 8 + 1 + 2 + 2; - - // offset of record type in block - private static final int BLOCK_OFFSET_TYPE = 8; - - // offset of protocol version number in block (TLS only) - private static final int BLOCK_OFFSET_VERSION = 8 + 1; - private MAC() { macSize = 0; mac = null; - block = null; } /** @@ -91,6 +70,8 @@ final class MAC { */ MAC(MacAlg macAlg, ProtocolVersion protocolVersion, SecretKey key) throws NoSuchAlgorithmException, InvalidKeyException { + super(protocolVersion); + this.macSize = macAlg.size; String algorithm; @@ -110,14 +91,6 @@ final class MAC { mac = JsseJce.getMac(algorithm); mac.init(key); - - if (tls) { - block = new byte[BLOCK_SIZE_TLS]; - block[BLOCK_OFFSET_VERSION] = protocolVersion.major; - block[BLOCK_OFFSET_VERSION+1] = protocolVersion.minor; - } else { - block = new byte[BLOCK_SIZE_SSL]; - } } /** @@ -136,7 +109,15 @@ final class MAC { * @param len the size of the compressed record */ final byte[] compute(byte type, byte buf[], int offset, int len) { - return compute(type, null, buf, offset, len); + if (macSize == 0) { + return nullMAC; + } + + byte[] additional = acquireAuthenticationBytes(type, len); + mac.update(additional); + mac.update(buf, offset, len); + + return mac.doFinal(); } /** @@ -151,78 +132,13 @@ final class MAC { * demarcate the data to be MAC'd. */ final byte[] compute(byte type, ByteBuffer bb) { - return compute(type, bb, null, 0, bb.remaining()); - } - - /** - * Check whether the sequence number is close to wrap - * - * Sequence numbers are of type uint64 and may not exceed 2^64-1. - * Sequence numbers do not wrap. When the sequence number is near - * to wrap, we need to close the connection immediately. - */ - final boolean seqNumOverflow() { - /* - * Conservatively, we don't allow more records to be generated - * when there are only 2^8 sequence numbers left. - */ - return (block != null && mac != null && - block[0] == (byte)0xFF && block[1] == (byte)0xFF && - block[2] == (byte)0xFF && block[3] == (byte)0xFF && - block[4] == (byte)0xFF && block[5] == (byte)0xFF && - block[6] == (byte)0xFF); - } - - /* - * Check whether to renew the sequence number - * - * Sequence numbers are of type uint64 and may not exceed 2^64-1. - * Sequence numbers do not wrap. If a TLS - * implementation would need to wrap a sequence number, it must - * renegotiate instead. - */ - final boolean seqNumIsHuge() { - /* - * Conservatively, we should ask for renegotiation when there are - * only 2^48 sequence numbers left. - */ - return (block != null && mac != null && - block[0] == (byte)0xFF && block[1] == (byte)0xFF); - } - - // increment the sequence number in the block array - // it is a 64-bit number stored in big-endian format - private void incrementSequenceNumber() { - int k = 7; - while ((k >= 0) && (++block[k] == 0)) { - k--; - } - } - - /* - * Compute based on either buffer type, either bb.position/limit - * or buf/offset/len. - */ - private byte[] compute(byte type, ByteBuffer bb, byte[] buf, - int offset, int len) { - if (macSize == 0) { return nullMAC; } - block[BLOCK_OFFSET_TYPE] = type; - block[block.length - 2] = (byte)(len >> 8); - block[block.length - 1] = (byte)(len ); - - mac.update(block); - incrementSequenceNumber(); - - // content - if (bb != null) { - mac.update(bb); - } else { - mac.update(buf, offset, len); - } + byte[] additional = acquireAuthenticationBytes(type, bb.remaining()); + mac.update(additional); + mac.update(bb); return mac.doFinal(); } diff --git a/jdk/src/share/classes/sun/security/ssl/OutputRecord.java b/jdk/src/share/classes/sun/security/ssl/OutputRecord.java index 900003dfd0f..d07c779f75e 100644 --- a/jdk/src/share/classes/sun/security/ssl/OutputRecord.java +++ b/jdk/src/share/classes/sun/security/ssl/OutputRecord.java @@ -54,6 +54,7 @@ class OutputRecord extends ByteArrayOutputStream implements Record { private int lastHashed; private boolean firstMessage; final private byte contentType; + private int headerOffset; // current protocol version, sent as record version ProtocolVersion protocolVersion; @@ -70,6 +71,23 @@ class OutputRecord extends ByteArrayOutputStream implements Record { * Default constructor makes a record supporting the maximum * SSL record size. It allocates the header bytes directly. * + * The structure of the byte buffer looks like: + * + * |---------+--------+-------+---------------------------------| + * | unused | header | IV | content, MAC/TAG, padding, etc. | + * | headerPlusMaxIVSize | + * + * unused: unused part of the buffer of size + * + * headerPlusMaxIVSize - header size - IV size + * + * When this object is created, we don't know the protocol + * version number, IV length, etc., so reserve space in front + * to avoid extra data movement (copies). + * header: the header of an SSL record + * IV: the optional IV/nonce field, it is only required for block + * (TLS 1.1 or later) and AEAD cipher suites. + * * @param type the content type for the record */ OutputRecord(byte type, int size) { @@ -77,9 +95,10 @@ class OutputRecord extends ByteArrayOutputStream implements Record { this.protocolVersion = ProtocolVersion.DEFAULT; this.helloVersion = ProtocolVersion.DEFAULT_HELLO; firstMessage = true; - count = headerSize; + count = headerPlusMaxIVSize; contentType = type; lastHashed = count; + headerOffset = headerPlusMaxIVSize - headerSize; } OutputRecord(byte type) { @@ -119,8 +138,9 @@ class OutputRecord extends ByteArrayOutputStream implements Record { @Override public synchronized void reset() { super.reset(); - count = headerSize; + count = headerPlusMaxIVSize; lastHashed = count; + headerOffset = headerPlusMaxIVSize - headerSize; } /* @@ -173,58 +193,84 @@ class OutputRecord extends ByteArrayOutputStream implements Record { * of sending empty records over the network. */ boolean isEmpty() { - return count == headerSize; + return count == headerPlusMaxIVSize; } /* - * Return true if the record is of a given alert. + * Return true if the record is of an alert of the given description. + * + * Per SSL/TLS specifications, alert messages convey the severity of the + * message (warning or fatal) and a description of the alert. An alert + * is defined with a two bytes struct, {byte level, byte description}, + * following after the header bytes. */ boolean isAlert(byte description) { - // An alert is defined with a two bytes struct, - // {byte level, byte description}, following after the header bytes. - if (count > (headerSize + 1) && contentType == ct_alert) { - return buf[headerSize + 1] == description; + if ((count > (headerPlusMaxIVSize + 1)) && (contentType == ct_alert)) { + return buf[headerPlusMaxIVSize + 1] == description; } return false; } /* - * Compute the MAC and append it to this record. In case we - * are automatically flushing a handshake stream, make sure we - * have hashed the message first. + * Encrypt ... length may grow due to block cipher padding, or + * message authentication code or tag. */ - void addMAC(MAC signer) throws IOException { + void encrypt(Authenticator authenticator, CipherBox box) + throws IOException { + + // In case we are automatically flushing a handshake stream, make + // sure we have hashed the message first. // // when we support compression, hashing can't go here // since it'll need to be done on the uncompressed data, // and the MAC applies to the compressed data. - // if (contentType == ct_handshake) { doHashes(); } - if (signer.MAClen() != 0) { - byte[] hash = signer.compute(contentType, buf, - headerSize, count - headerSize); - write(hash); + + // Requires message authentication code for stream and block + // cipher suites. + if (authenticator instanceof MAC) { + MAC signer = (MAC)authenticator; + if (signer.MAClen() != 0) { + byte[] hash = signer.compute(contentType, buf, + headerPlusMaxIVSize, count - headerPlusMaxIVSize); + write(hash); + } + } + + if (!box.isNullCipher()) { + // Requires explicit IV/nonce for CBC/AEAD cipher suites for + // TLS 1.1 or later. + if ((protocolVersion.v >= ProtocolVersion.TLS11.v) && + (box.isCBCMode() || box.isAEADMode())) { + byte[] nonce = box.createExplicitNonce(authenticator, + contentType, count - headerPlusMaxIVSize); + int offset = headerPlusMaxIVSize - nonce.length; + System.arraycopy(nonce, 0, buf, offset, nonce.length); + headerOffset = offset - headerSize; + } else { + headerOffset = headerPlusMaxIVSize - headerSize; + } + + // encrypt the content + int offset = headerPlusMaxIVSize; + if (!box.isAEADMode()) { + // The explicit IV can be encrypted. + offset = headerOffset + headerSize; + } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode + + count = offset + box.encrypt(buf, offset, count - offset); } } - /* - * Encrypt ... length may grow due to block cipher padding - */ - void encrypt(CipherBox box) { - int len = count - headerSize; - count = headerSize + box.encrypt(buf, headerSize, len); - } - - /* * Tell how full the buffer is ... for filling it with application or * handshake data. */ final int availableDataBytes() { - int dataSize = count - headerSize; + int dataSize = count - headerPlusMaxIVSize; return maxDataSize - dataSize; } @@ -270,11 +316,11 @@ class OutputRecord extends ByteArrayOutputStream implements Record { * Don't emit content-free records. (Even change cipher spec * messages have a byte of data!) */ - if (count == headerSize) { + if (count == headerPlusMaxIVSize) { return; } - int length = count - headerSize; + int length = count - headerOffset - headerSize; // "should" really never write more than about 14 Kb... if (length < 0) { throw new SSLException("output record size too small: " @@ -299,7 +345,9 @@ class OutputRecord extends ByteArrayOutputStream implements Record { */ if (firstMessage && useV2Hello()) { byte[] v3Msg = new byte[length - 4]; - System.arraycopy(buf, headerSize + 4, v3Msg, 0, v3Msg.length); + System.arraycopy(buf, headerPlusMaxIVSize + 4, + v3Msg, 0, v3Msg.length); + headerOffset = 0; // reset the header offset V3toV2ClientHello(v3Msg); handshakeHash.reset(); lastHashed = 2; @@ -314,11 +362,11 @@ class OutputRecord extends ByteArrayOutputStream implements Record { /* * Fill out the header, write it and the message. */ - buf[0] = contentType; - buf[1] = protocolVersion.major; - buf[2] = protocolVersion.minor; - buf[3] = (byte)(length >> 8); - buf[4] = (byte)(length); + buf[headerOffset + 0] = contentType; + buf[headerOffset + 1] = protocolVersion.major; + buf[headerOffset + 2] = protocolVersion.minor; + buf[headerOffset + 3] = (byte)(length >> 8); + buf[headerOffset + 4] = (byte)(length); } firstMessage = false; @@ -338,7 +386,8 @@ class OutputRecord extends ByteArrayOutputStream implements Record { * when holdRecord is true, the implementation in this class * will be used. */ - writeBuffer(heldRecordBuffer, buf, 0, count, debugOffset); + writeBuffer(heldRecordBuffer, + buf, headerOffset, count - headerOffset, debugOffset); } else { // It's time to send, do we have buffered data? // May or may not have a heldRecordBuffer. @@ -346,15 +395,18 @@ class OutputRecord extends ByteArrayOutputStream implements Record { int heldLen = heldRecordBuffer.size(); // Ensure the capacity of this buffer. - ensureCapacity(count + heldLen); + int newCount = count + heldLen - headerOffset; + ensureCapacity(newCount); // Slide everything in the buffer to the right. - System.arraycopy(buf, 0, buf, heldLen, count); + System.arraycopy(buf, headerOffset, + buf, heldLen, count - headerOffset); // Prepend the held record to the buffer. System.arraycopy( heldRecordBuffer.toByteArray(), 0, buf, 0, heldLen); - count += heldLen; + count = newCount; + headerOffset = 0; // Clear the held buffer. heldRecordBuffer.reset(); @@ -362,7 +414,8 @@ class OutputRecord extends ByteArrayOutputStream implements Record { // The held buffer has been dumped, set the debug dump offset. debugOffset = heldLen; } - writeBuffer(s, buf, 0, count, debugOffset); + writeBuffer(s, buf, headerOffset, + count - headerOffset, debugOffset); } reset(); @@ -382,12 +435,11 @@ class OutputRecord extends ByteArrayOutputStream implements Record { if (debug != null && Debug.isOn("packet")) { try { HexDumpEncoder hd = new HexDumpEncoder(); - ByteBuffer bb = ByteBuffer.wrap( - buf, off + debugOffset, len - debugOffset); System.out.println("[Raw write]: length = " + - bb.remaining()); - hd.encodeBuffer(bb, System.out); + (len - debugOffset)); + hd.encodeBuffer(new ByteArrayInputStream(buf, + off + debugOffset, len - debugOffset), System.out); } catch (IOException e) { } } } @@ -400,8 +452,13 @@ class OutputRecord extends ByteArrayOutputStream implements Record { return firstMessage && (helloVersion == ProtocolVersion.SSL20Hello) && (contentType == ct_handshake) - && (buf[5] == HandshakeMessage.ht_client_hello) - && (buf[headerSize + 4+2+32] == 0); // V3 session ID is empty + && (buf[headerOffset + 5] == HandshakeMessage.ht_client_hello) + // 5: recode header size + && (buf[headerPlusMaxIVSize + 4 + 2 + 32] == 0); + // V3 session ID is empty + // 4: handshake header size + // 2: client_version in ClientHello + // 32: random in ClientHello } /* diff --git a/jdk/src/share/classes/sun/security/ssl/Record.java b/jdk/src/share/classes/sun/security/ssl/Record.java index 0494d9a4583..ca85a067ae3 100644 --- a/jdk/src/share/classes/sun/security/ssl/Record.java +++ b/jdk/src/share/classes/sun/security/ssl/Record.java @@ -52,20 +52,29 @@ interface Record { static final int trailerSize = 20; // SHA1 hash size static final int maxDataSize = 16384; // 2^14 bytes of data static final int maxPadding = 256; // block cipher padding - static final int maxIVLength = 256; // block length + static final int maxIVLength = 256; // IV length + + /* + * The size of the header plus the max IV length + */ + static final int headerPlusMaxIVSize = + headerSize // header + + maxIVLength; // iv /* * SSL has a maximum record size. It's header, (compressed) data, - * padding, and a trailer for the MAC. + * padding, and a trailer for the message authentication information (MAC + * for block and stream ciphers, and message authentication tag for AEAD + * ciphers). + * * Some compression algorithms have rare cases where they expand the data. * As we don't support compression at this time, leave that out. */ static final int maxRecordSize = - headerSize // header - + maxIVLength // iv - + maxDataSize // data - + maxPadding // padding - + trailerSize; // MAC + headerPlusMaxIVSize // header + iv + + maxDataSize // data + + maxPadding // padding + + trailerSize; // MAC or AEAD tag static final boolean enableCBCProtection = Debug.getBooleanProperty("jsse.enableCBCProtection", true); @@ -77,8 +86,7 @@ interface Record { static final int maxDataSizeMinusOneByteRecord = maxDataSize // max data size - ( // max one byte record size - headerSize // header - + maxIVLength // iv + headerPlusMaxIVSize // header + iv + 1 // one byte data + maxPadding // padding + trailerSize // MAC @@ -104,11 +112,10 @@ interface Record { * Allocate a smaller array. */ static final int maxAlertRecordSize = - headerSize // header - + maxIVLength // iv - + 2 // alert - + maxPadding // padding - + trailerSize; // MAC + headerPlusMaxIVSize // header + iv + + 2 // alert + + maxPadding // padding + + trailerSize; // MAC /* * The overflow values of integers of 8, 16 and 24 bits. diff --git a/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java index 41415337ca1..2da58577c94 100644 --- a/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java @@ -280,7 +280,7 @@ final public class SSLEngineImpl extends SSLEngine { /* * Crypto state that's reinitialized when the session changes. */ - private MAC readMAC, writeMAC; + private Authenticator readAuthenticator, writeAuthenticator; private CipherBox readCipher, writeCipher; // NOTE: compression state would be saved here @@ -377,9 +377,9 @@ final public class SSLEngineImpl extends SSLEngine { * Note: compression support would go here too */ readCipher = CipherBox.NULL; - readMAC = MAC.NULL; + readAuthenticator = MAC.NULL; writeCipher = CipherBox.NULL; - writeMAC = MAC.NULL; + writeAuthenticator = MAC.NULL; // default security parameters for secure renegotiation secureRenegotiation = false; @@ -586,7 +586,7 @@ final public class SSLEngineImpl extends SSLEngine { try { readCipher = handshaker.newReadCipher(); - readMAC = handshaker.newReadMAC(); + readAuthenticator = handshaker.newReadAuthenticator(); } catch (GeneralSecurityException e) { // "can't happen" throw new SSLException("Algorithm missing: ", e); @@ -622,7 +622,7 @@ final public class SSLEngineImpl extends SSLEngine { try { writeCipher = handshaker.newWriteCipher(); - writeMAC = handshaker.newWriteMAC(); + writeAuthenticator = handshaker.newWriteAuthenticator(); } catch (GeneralSecurityException e) { // "can't happen" throw new SSLException("Algorithm missing: ", e); @@ -958,34 +958,15 @@ final public class SSLEngineImpl extends SSLEngine { * throw a fatal alert if the integrity check fails. */ try { - decryptedBB = inputRecord.decrypt(readCipher, readBB); + decryptedBB = inputRecord.decrypt( + readAuthenticator, readCipher, readBB); } catch (BadPaddingException e) { - // RFC 2246 states that decryption_failed should be used - // for this purpose. However, that allows certain attacks, - // so we just send bad record MAC. We also need to make - // sure to always check the MAC to avoid a timing attack - // for the same issue. See paper by Vaudenay et al. - // - // rewind the BB if necessary. - readBB.rewind(); - - inputRecord.checkMAC(readMAC, readBB); - // use the same alert types as for MAC failure below byte alertType = (inputRecord.contentType() == Record.ct_handshake) ? Alerts.alert_handshake_failure : Alerts.alert_bad_record_mac; - fatal(alertType, "Invalid padding", e); - } - - if (!inputRecord.checkMAC(readMAC, decryptedBB)) { - if (inputRecord.contentType() == Record.ct_handshake) { - fatal(Alerts.alert_handshake_failure, - "bad handshake record MAC"); - } else { - fatal(Alerts.alert_bad_record_mac, "bad record MAC"); - } + fatal(alertType, e.getMessage(), e); } // if (!inputRecord.decompress(c)) @@ -1137,7 +1118,7 @@ final public class SSLEngineImpl extends SSLEngine { hsStatus = getHSStatus(hsStatus); if (connectionState < cs_ERROR && !isInboundDone() && (hsStatus == HandshakeStatus.NOT_HANDSHAKING)) { - if (checkSequenceNumber(readMAC, + if (checkSequenceNumber(readAuthenticator, inputRecord.contentType())) { hsStatus = getHSStatus(null); } @@ -1290,7 +1271,7 @@ final public class SSLEngineImpl extends SSLEngine { // eventually compress as well. HandshakeStatus hsStatus = - writer.writeRecord(eor, ea, writeMAC, writeCipher); + writer.writeRecord(eor, ea, writeAuthenticator, writeCipher); /* * We only need to check the sequence number state for @@ -1307,7 +1288,7 @@ final public class SSLEngineImpl extends SSLEngine { hsStatus = getHSStatus(hsStatus); if (connectionState < cs_ERROR && !isOutboundDone() && (hsStatus == HandshakeStatus.NOT_HANDSHAKING)) { - if (checkSequenceNumber(writeMAC, eor.contentType())) { + if (checkSequenceNumber(writeAuthenticator, eor.contentType())) { hsStatus = getHSStatus(null); } } @@ -1346,7 +1327,7 @@ final public class SSLEngineImpl extends SSLEngine { */ void writeRecord(EngineOutputRecord eor) throws IOException { // eventually compress as well. - writer.writeRecord(eor, writeMAC, writeCipher); + writer.writeRecord(eor, writeAuthenticator, writeCipher); /* * Check the sequence number state @@ -1360,7 +1341,7 @@ final public class SSLEngineImpl extends SSLEngine { * of the last record cannot be wrapped. */ if ((connectionState < cs_ERROR) && !isOutboundDone()) { - checkSequenceNumber(writeMAC, eor.contentType()); + checkSequenceNumber(writeAuthenticator, eor.contentType()); } } @@ -1378,14 +1359,14 @@ final public class SSLEngineImpl extends SSLEngine { * * Return true if the handshake status may be changed. */ - private boolean checkSequenceNumber(MAC mac, byte type) + private boolean checkSequenceNumber(Authenticator authenticator, byte type) throws IOException { /* * Don't bother to check the sequence number for error or * closed connections, or NULL MAC */ - if (connectionState >= cs_ERROR || mac == MAC.NULL) { + if (connectionState >= cs_ERROR || authenticator == MAC.NULL) { return false; } @@ -1393,7 +1374,7 @@ final public class SSLEngineImpl extends SSLEngine { * Conservatively, close the connection immediately when the * sequence number is close to overflow */ - if (mac.seqNumOverflow()) { + if (authenticator.seqNumOverflow()) { /* * TLS protocols do not define a error alert for sequence * number overflow. We use handshake_failure error alert @@ -1416,7 +1397,7 @@ final public class SSLEngineImpl extends SSLEngine { * Don't bother to kickstart the renegotiation when the local is * asking for it. */ - if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) { + if ((type != Record.ct_handshake) && authenticator.seqNumIsHuge()) { if (debug != null && Debug.isOn("ssl")) { System.out.println(Thread.currentThread().getName() + ", request renegotiation " + diff --git a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java index f807c4c58ce..9c8b43f17ad 100644 --- a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -292,7 +292,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { /* * Crypto state that's reinitialized when the session changes. */ - private MAC readMAC, writeMAC; + private Authenticator readAuthenticator, writeAuthenticator; private CipherBox readCipher, writeCipher; // NOTE: compression state would be saved here @@ -586,9 +586,9 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * Note: compression support would go here too */ readCipher = CipherBox.NULL; - readMAC = MAC.NULL; + readAuthenticator = MAC.NULL; writeCipher = CipherBox.NULL; - writeMAC = MAC.NULL; + writeAuthenticator = MAC.NULL; // initial security parameters for secure renegotiation secureRenegotiation = false; @@ -829,8 +829,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { boolean holdRecord) throws IOException { // r.compress(c); - r.addMAC(writeMAC); - r.encrypt(writeCipher); + r.encrypt(writeAuthenticator, writeCipher); if (holdRecord) { // If we were requested to delay the record due to possibility @@ -861,7 +860,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * of the last record cannot be wrapped. */ if (connectionState < cs_ERROR) { - checkSequenceNumber(writeMAC, r.contentType()); + checkSequenceNumber(writeAuthenticator, r.contentType()); } // turn off the flag of the first application record @@ -986,29 +985,14 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * throw a fatal alert if the integrity check fails. */ try { - r.decrypt(readCipher); + r.decrypt(readAuthenticator, readCipher); } catch (BadPaddingException e) { - // RFC 2246 states that decryption_failed should be used - // for this purpose. However, that allows certain attacks, - // so we just send bad record MAC. We also need to make - // sure to always check the MAC to avoid a timing attack - // for the same issue. See paper by Vaudenay et al. - r.checkMAC(readMAC); // use the same alert types as for MAC failure below byte alertType = (r.contentType() == Record.ct_handshake) ? Alerts.alert_handshake_failure : Alerts.alert_bad_record_mac; - fatal(alertType, "Invalid padding", e); + fatal(alertType, e.getMessage(), e); } - if (!r.checkMAC(readMAC)) { - if (r.contentType() == Record.ct_handshake) { - fatal(Alerts.alert_handshake_failure, - "bad handshake record MAC"); - } else { - fatal(Alerts.alert_bad_record_mac, "bad record MAC"); - } - } - // if (!r.decompress(c)) // fatal(Alerts.alert_decompression_failure, @@ -1159,7 +1143,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * of the last record cannot be wrapped. */ if (connectionState < cs_ERROR) { - checkSequenceNumber(readMAC, r.contentType()); + checkSequenceNumber(readAuthenticator, r.contentType()); } return; @@ -1182,14 +1166,14 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * implementation would need to wrap a sequence number, it must * renegotiate instead." */ - private void checkSequenceNumber(MAC mac, byte type) + private void checkSequenceNumber(Authenticator authenticator, byte type) throws IOException { /* * Don't bother to check the sequence number for error or * closed connections, or NULL MAC. */ - if (connectionState >= cs_ERROR || mac == MAC.NULL) { + if (connectionState >= cs_ERROR || authenticator == MAC.NULL) { return; } @@ -1197,7 +1181,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * Conservatively, close the connection immediately when the * sequence number is close to overflow */ - if (mac.seqNumOverflow()) { + if (authenticator.seqNumOverflow()) { /* * TLS protocols do not define a error alert for sequence * number overflow. We use handshake_failure error alert @@ -1219,7 +1203,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * Don't bother to kickstart the renegotiation when the local is * asking for it. */ - if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) { + if ((type != Record.ct_handshake) && authenticator.seqNumIsHuge()) { if (debug != null && Debug.isOn("ssl")) { System.out.println(Thread.currentThread().getName() + ", request renegotiation " + @@ -2081,7 +2065,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { try { readCipher = handshaker.newReadCipher(); - readMAC = handshaker.newReadMAC(); + readAuthenticator = handshaker.newReadAuthenticator(); } catch (GeneralSecurityException e) { // "can't happen" throw new SSLException("Algorithm missing: ", e); @@ -2112,7 +2096,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { try { writeCipher = handshaker.newWriteCipher(); - writeMAC = handshaker.newWriteMAC(); + writeAuthenticator = handshaker.newWriteAuthenticator(); } catch (GeneralSecurityException e) { // "can't happen" throw new SSLException("Algorithm missing: ", e); diff --git a/jdk/test/sun/security/ec/TestEC.java b/jdk/test/sun/security/ec/TestEC.java index 41d0f0361da..77217cae467 100644 --- a/jdk/test/sun/security/ec/TestEC.java +++ b/jdk/test/sun/security/ec/TestEC.java @@ -21,6 +21,11 @@ * questions. */ +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + /** * @test * @bug 6840752 @@ -30,7 +35,7 @@ * @library ../pkcs11/sslecc * @library ../../../java/security/testlibrary * @compile -XDignore.symbol.file TestEC.java - * @run main TestEC + * @run main/othervm TestEC */ import java.security.NoSuchProviderException; diff --git a/jdk/test/sun/security/pkcs11/fips/CipherTest.java b/jdk/test/sun/security/pkcs11/fips/CipherTest.java index 32bc6df4e16..2fc81c49c54 100644 --- a/jdk/test/sun/security/pkcs11/fips/CipherTest.java +++ b/jdk/test/sun/security/pkcs11/fips/CipherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -147,6 +147,25 @@ public class CipherTest { CS_16("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x0303, 0xFFFF), CS_17("TLS_RSA_WITH_NULL_SHA256", 0x0303, 0xFFFF), + CS_20("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_21("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_22("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_23("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_24("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_25("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_26("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_27("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + + CS_28("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_29("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_30("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_31("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_32("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_33("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + + CS_34("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_35("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + // cipher suites obsoleted since TLS 1.2 CS_50("SSL_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303), CS_51("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303), diff --git a/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java b/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java index 64153f58d20..26ecec4df0f 100644 --- a/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java +++ b/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -147,6 +147,25 @@ public class CipherTest { CS_16("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x0303, 0xFFFF), CS_17("TLS_RSA_WITH_NULL_SHA256", 0x0303, 0xFFFF), + CS_20("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_21("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_22("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_23("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_24("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_25("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_26("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_27("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + + CS_28("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_29("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_30("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_31("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_32("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_33("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + + CS_34("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_35("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + // cipher suites obsoleted since TLS 1.2 CS_50("SSL_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303), CS_51("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303), diff --git a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java index aeaf5792cb9..564342b8ee6 100644 --- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java +++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java @@ -21,14 +21,16 @@ * questions. */ +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + /* * @test * @bug 7031830 * @summary bad_record_mac failure on TLSv1.2 enabled connection with SSLEngine * @run main/othervm SSLEngineBadBufferArrayAccess - * - * SunJSSE does not support dynamic system properties, no way to re-use - * system properties in samevm/agentvm mode. */ /** diff --git a/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKeyGCM.java b/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKeyGCM.java new file mode 100644 index 00000000000..ac78134f6d4 --- /dev/null +++ b/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKeyGCM.java @@ -0,0 +1,445 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + +/* + * @test + * @bug 7030966 + * @summary Support AEAD CipherSuites + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_RSA_WITH_AES_128_GCM_SHA256 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_DH_anon_WITH_AES_128_GCM_SHA256 + */ + +/* + * Need additional key materials to run the following cases. + * + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * + * Need unlimited JCE Unlimited Strength Jurisdiction Policy to run the + * following cases. + * + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_RSA_WITH_AES_256_GCM_SHA384 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * @run main/othervm ShortRSAKeyGCM PKIX TLS_DH_anon_WITH_AES_256_GCM_SHA384 + */ + +import java.net.*; +import java.util.*; +import java.io.*; +import javax.net.ssl.*; +import java.security.Security; +import java.security.KeyStore; +import java.security.KeyFactory; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.spec.*; +import java.security.interfaces.*; +import sun.misc.BASE64Decoder; + + +public class ShortRSAKeyGCM { + + /* + * ============================================================= + * Set the various variables needed for the tests, then + * specify what tests to run on each side. + */ + + /* + * Should we run the client or server in a separate thread? + * Both sides can throw exceptions, but do you have a preference + * as to which side should be the main thread. + */ + static boolean separateServerThread = true; + + /* + * Where do we find the keystores? + */ + // Certificates and key used in the test. + static String trustedCertStr = + "-----BEGIN CERTIFICATE-----\n" + + "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTEwODE5MDE1MjE5WhcNMzIwNzI5MDE1MjE5WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + + "KoZIhvcNAQEBBQADgY0AMIGJAoGBAM8orG08DtF98TMSscjGsidd1ZoN4jiDpi8U\n" + + "ICz+9dMm1qM1d7O2T+KH3/mxyox7Rc2ZVSCaUD0a3CkhPMnlAx8V4u0H+E9sqso6\n" + + "iDW3JpOyzMExvZiRgRG/3nvp55RMIUV4vEHOZ1QbhuqG4ebN0Vz2DkRft7+flthf\n" + + "vDld6f5JAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLl81dnfp0wDrv0OJ1sxlWzH83Xh\n" + + "MGMGA1UdIwRcMFqAFLl81dnfp0wDrv0OJ1sxlWzH83XhoT+kPTA7MQswCQYDVQQG\n" + + "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + + "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" + + "BQADgYEALlgaH1gWtoBZ84EW8Hu6YtGLQ/L9zIFmHonUPZwn3Pr//icR9Sqhc3/l\n" + + "pVTxOINuFHLRz4BBtEylzRIOPzK3tg8XwuLb1zd0db90x3KBCiAL6E6cklGEPwLe\n" + + "XYMHDn9eDsaq861Tzn6ZwzMgw04zotPMoZN0mVd/3Qca8UJFucE=\n" + + "-----END CERTIFICATE-----"; + + static String targetCertStr = + "-----BEGIN CERTIFICATE-----\n" + + "MIICNDCCAZ2gAwIBAgIBDDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + + "MTExMTA3MTM1NTUyWhcNMzEwNzI1MTM1NTUyWjBPMQswCQYDVQQGEwJVUzENMAsG\n" + + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + + "BAMTCWxvY2FsaG9zdDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3Pb49OSPfOD2G\n" + + "HSXFCFx1GJEZfqG9ZUf7xuIi/ra5dLjPGAaoY5QF2QOa8VnOriQCXDfyXHxsuRnE\n" + + "OomxL7EVAgMBAAGjeDB2MAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUXNCJK3/dtCIc\n" + + "xb+zlA/JINlvs/MwHwYDVR0jBBgwFoAUuXzV2d+nTAOu/Q4nWzGVbMfzdeEwJwYD\n" + + "VR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAzANBgkqhkiG9w0B\n" + + "AQQFAAOBgQB2qIDUxA2caMPpGtUACZAPRUtrGssCINIfItETXJZCx/cRuZ5sP4D9\n" + + "N1acoNDn0hCULe3lhXAeTC9NZ97680yJzregQMV5wATjo1FGsKY30Ma+sc/nfzQW\n" + + "+h/7RhYtoG0OTsiaDCvyhI6swkNJzSzrAccPY4+ZgU8HiDLzZTmM3Q==\n" + + "-----END CERTIFICATE-----"; + + // Private key in the format of PKCS#8, key size is 512 bits. + static String targetPrivateKey = + "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtz2+PTkj3zg9hh0l\n" + + "xQhcdRiRGX6hvWVH+8biIv62uXS4zxgGqGOUBdkDmvFZzq4kAlw38lx8bLkZxDqJ\n" + + "sS+xFQIDAQABAkByx/5Oo2hQ/w2q4L8z+NTRlJ3vdl8iIDtC/4XPnfYfnGptnpG6\n" + + "ZThQRvbMZiai0xHQPQMszvAHjZVme1eDl3EBAiEA3aKJHynPVCEJhpfCLWuMwX5J\n" + + "1LntwJO7NTOyU5m8rPECIQDTpzn5X44r2rzWBDna/Sx7HW9IWCxNgUD2Eyi2nA7W\n" + + "ZQIgJerEorw4aCAuzQPxiGu57PB6GRamAihEAtoRTBQlH0ECIQDN08FgTtnesgCU\n" + + "DFYLLcw1CiHvc7fZw4neBDHCrC8NtQIgA8TOUkGnpCZlQ0KaI8KfKWI+vxFcgFnH\n" + + "3fnqsTgaUs4="; + + static char passphrase[] = "passphrase".toCharArray(); + + /* + * Is the server ready to serve? + */ + volatile static boolean serverReady = false; + + /* + * Turn on SSL debugging? + */ + static boolean debug = false; + + /* + * Define the server side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + void doServerSide() throws Exception { + SSLContext context = generateSSLContext(null, targetCertStr, + targetPrivateKey); + SSLServerSocketFactory sslssf = context.getServerSocketFactory(); + SSLServerSocket sslServerSocket = + (SSLServerSocket)sslssf.createServerSocket(serverPort); + serverPort = sslServerSocket.getLocalPort(); + + /* + * Signal Client, we're ready for his connect. + */ + serverReady = true; + + SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept(); + sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites()); + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); + + sslIS.read(); + sslOS.write('A'); + sslOS.flush(); + + sslSocket.close(); + } + + /* + * Define the client side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + void doClientSide() throws Exception { + + /* + * Wait for server to get started. + */ + while (!serverReady) { + Thread.sleep(50); + } + + SSLContext context = generateSSLContext(trustedCertStr, null, null); + SSLSocketFactory sslsf = context.getSocketFactory(); + + SSLSocket sslSocket = + (SSLSocket)sslsf.createSocket("localhost", serverPort); + + // enable TLSv1.2 only + sslSocket.setEnabledProtocols(new String[] {"TLSv1.2"}); + + // enable a block cipher + sslSocket.setEnabledCipherSuites(new String[] {cipherSuite}); + + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); + + sslOS.write('B'); + sslOS.flush(); + sslIS.read(); + + sslSocket.close(); + } + + /* + * ============================================================= + * The remainder is just support stuff + */ + private static String tmAlgorithm; // trust manager + private static String cipherSuite; // cipher suite + + private static void parseArguments(String[] args) { + tmAlgorithm = args[0]; + cipherSuite = args[1]; + } + + private static SSLContext generateSSLContext(String trustedCertStr, + String keyCertStr, String keySpecStr) throws Exception { + + // generate certificate from cert string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + // create a key store + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(null, null); + + // import the trused cert + Certificate trusedCert = null; + ByteArrayInputStream is = null; + if (trustedCertStr != null) { + is = new ByteArrayInputStream(trustedCertStr.getBytes()); + trusedCert = cf.generateCertificate(is); + is.close(); + + ks.setCertificateEntry("RSA Export Signer", trusedCert); + } + + if (keyCertStr != null) { + // generate the private key. + PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( + new BASE64Decoder().decodeBuffer(keySpecStr)); + KeyFactory kf = KeyFactory.getInstance("RSA"); + RSAPrivateKey priKey = + (RSAPrivateKey)kf.generatePrivate(priKeySpec); + + // generate certificate chain + is = new ByteArrayInputStream(keyCertStr.getBytes()); + Certificate keyCert = cf.generateCertificate(is); + is.close(); + + Certificate[] chain = null; + if (trusedCert != null) { + chain = new Certificate[2]; + chain[0] = keyCert; + chain[1] = trusedCert; + } else { + chain = new Certificate[1]; + chain[0] = keyCert; + } + + // import the key entry. + ks.setKeyEntry("Whatever", priKey, passphrase, chain); + } + + // create SSL context + TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm); + tmf.init(ks); + + SSLContext ctx = SSLContext.getInstance("TLS"); + if (keyCertStr != null && !keyCertStr.isEmpty()) { + KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); + kmf.init(ks, passphrase); + + ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + ks = null; + } else { + ctx.init(null, tmf.getTrustManagers(), null); + } + + return ctx; + } + + + // use any free port by default + volatile int serverPort = 0; + + volatile Exception serverException = null; + volatile Exception clientException = null; + + public static void main(String[] args) throws Exception { + // reset the security property to make sure that the algorithms + // and keys used in this test are not disabled. + Security.setProperty("jdk.certpath.disabledAlgorithms", "MD2"); + + if (debug) { + System.setProperty("javax.net.debug", "all"); + } + + /* + * Get the customized arguments. + */ + parseArguments(args); + + /* + * Start the tests. + */ + new ShortRSAKeyGCM(); + } + + Thread clientThread = null; + Thread serverThread = null; + + /* + * Primary constructor, used to drive remainder of the test. + * + * Fork off the other side, then do your work. + */ + ShortRSAKeyGCM() throws Exception { + try { + if (separateServerThread) { + startServer(true); + startClient(false); + } else { + startClient(true); + startServer(false); + } + } catch (Exception e) { + // swallow for now. Show later + } + + /* + * Wait for other side to close down. + */ + if (separateServerThread) { + serverThread.join(); + } else { + clientThread.join(); + } + + /* + * When we get here, the test is pretty much over. + * Which side threw the error? + */ + Exception local; + Exception remote; + String whichRemote; + + if (separateServerThread) { + remote = serverException; + local = clientException; + whichRemote = "server"; + } else { + remote = clientException; + local = serverException; + whichRemote = "client"; + } + + /* + * If both failed, return the curthread's exception, but also + * print the remote side Exception + */ + if ((local != null) && (remote != null)) { + System.out.println(whichRemote + " also threw:"); + remote.printStackTrace(); + System.out.println(); + throw local; + } + + if (remote != null) { + throw remote; + } + + if (local != null) { + throw local; + } + } + + void startServer(boolean newThread) throws Exception { + if (newThread) { + serverThread = new Thread() { + public void run() { + try { + doServerSide(); + } catch (Exception e) { + /* + * Our server thread just died. + * + * Release the client, if not active already... + */ + System.err.println("Server died..." + e); + serverReady = true; + serverException = e; + } + } + }; + serverThread.start(); + } else { + try { + doServerSide(); + } catch (Exception e) { + serverException = e; + } finally { + serverReady = true; + } + } + } + + void startClient(boolean newThread) throws Exception { + if (newThread) { + clientThread = new Thread() { + public void run() { + try { + doClientSide(); + } catch (Exception e) { + /* + * Our client thread just died. + */ + System.err.println("Client died..." + e); + clientException = e; + } + } + }; + clientThread.start(); + } else { + try { + doClientSide(); + } catch (Exception e) { + clientException = e; + } + } + } +} diff --git a/jdk/test/sun/security/ssl/sanity/ciphersuites/CipherSuitesInOrder.java b/jdk/test/sun/security/ssl/sanity/ciphersuites/CipherSuitesInOrder.java index 3d081c1bd40..9dc1a923dc9 100644 --- a/jdk/test/sun/security/ssl/sanity/ciphersuites/CipherSuitesInOrder.java +++ b/jdk/test/sun/security/ssl/sanity/ciphersuites/CipherSuitesInOrder.java @@ -21,13 +21,15 @@ * questions. */ +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + /* * @test * @bug 7174244 * @summary NPE in Krb5ProxyImpl.getServerKeys() - * - * SunJSSE does not support dynamic system properties, no way to re-use - * system properties in samevm/agentvm mode. * @run main/othervm CipherSuitesInOrder */ @@ -72,6 +74,22 @@ public class CipherSuitesInOrder { "SSL_RSA_WITH_RC4_128_SHA", "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", "TLS_ECDH_RSA_WITH_RC4_128_SHA", + + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", + "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA", @@ -83,6 +101,9 @@ public class CipherSuitesInOrder { "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", + "TLS_DH_anon_WITH_AES_256_GCM_SHA384", + "TLS_DH_anon_WITH_AES_128_GCM_SHA256", + "TLS_DH_anon_WITH_AES_256_CBC_SHA256", "TLS_ECDH_anon_WITH_AES_256_CBC_SHA", "TLS_DH_anon_WITH_AES_256_CBC_SHA", diff --git a/jdk/test/sun/security/ssl/sanity/interop/CipherTest.java b/jdk/test/sun/security/ssl/sanity/interop/CipherTest.java index 9c5af7eda4a..106d4a75e53 100644 --- a/jdk/test/sun/security/ssl/sanity/interop/CipherTest.java +++ b/jdk/test/sun/security/ssl/sanity/interop/CipherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -148,6 +148,25 @@ public class CipherTest { CS_16("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x0303, 0xFFFF), CS_17("TLS_RSA_WITH_NULL_SHA256", 0x0303, 0xFFFF), + CS_20("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_21("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_22("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_23("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_24("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_25("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_26("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_27("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + + CS_28("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_29("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_30("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_31("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_32("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + CS_33("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + + CS_34("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), + CS_35("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), + // cipher suites obsoleted since TLS 1.2 CS_50("SSL_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303), CS_51("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303), diff --git a/jdk/test/sun/security/ssl/templates/SSLSocketSSLEngineTemplate.java b/jdk/test/sun/security/ssl/templates/SSLSocketSSLEngineTemplate.java index e31409a0f74..6bd63ae7104 100644 --- a/jdk/test/sun/security/ssl/templates/SSLSocketSSLEngineTemplate.java +++ b/jdk/test/sun/security/ssl/templates/SSLSocketSSLEngineTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -21,14 +21,15 @@ * questions. */ +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + /* * @test * @bug 7105780 * @summary Add SSLSocket client/SSLEngine server to templates directory. - * - * SunJSSE does not support dynamic system properties, no way to re-use - * system properties in samevm/agentvm mode. - * * @run main/othervm SSLSocketSSLEngineTemplate */ From b6a841d5a330404bd1e34ff3efdf9797b66ccaba Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov <serb@openjdk.org> Date: Fri, 1 Mar 2013 15:31:22 +0400 Subject: [PATCH 122/180] 7194902: [macosx] closed/java/awt/Button/DoubleActionEventTest/DoubleActionEventTest failed since jdk8b49 7181403: Invalid MouseEvent conversion with SwingUtilities.convertMouseEvent Reviewed-by: malenkov, alexsch --- .../macosx/classes/sun/lwawt/LWComponentPeer.java | 13 +++++++++---- .../share/classes/javax/swing/SwingUtilities.java | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java b/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java index 301fbb476d8..052b91726b6 100644 --- a/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java +++ b/jdk/src/macosx/classes/sun/lwawt/LWComponentPeer.java @@ -1227,10 +1227,10 @@ public abstract class LWComponentPeer<T extends Component, D extends JComponent> } protected void sendEventToDelegate(final AWTEvent e) { + if (getDelegate() == null || !isShowing() || !isEnabled()) { + return; + } synchronized (getDelegateLock()) { - if (getDelegate() == null || !isShowing() || !isEnabled()) { - return; - } AWTEvent delegateEvent = createDelegateEvent(e); if (delegateEvent != null) { AWTAccessor.getComponentAccessor() @@ -1244,7 +1244,12 @@ public abstract class LWComponentPeer<T extends Component, D extends JComponent> } } - protected AWTEvent createDelegateEvent(AWTEvent e) { + /** + * Changes the target of the AWTEvent from awt component to appropriate + * swing delegate. + */ + private AWTEvent createDelegateEvent(final AWTEvent e) { + // TODO modifiers should be changed to getModifiers()|getModifiersEx()? AWTEvent delegateEvent = null; if (e instanceof MouseWheelEvent) { MouseWheelEvent me = (MouseWheelEvent) e; diff --git a/jdk/src/share/classes/javax/swing/SwingUtilities.java b/jdk/src/share/classes/javax/swing/SwingUtilities.java index 956bb838be7..6bb308d2f1e 100644 --- a/jdk/src/share/classes/javax/swing/SwingUtilities.java +++ b/jdk/src/share/classes/javax/swing/SwingUtilities.java @@ -356,7 +356,7 @@ public class SwingUtilities implements SwingConstants sourceEvent.getYOnScreen(), sourceEvent.getClickCount(), sourceEvent.isPopupTrigger(), - MouseEvent.NOBUTTON ); + sourceEvent.getButton()); } return newEvent; } From 916da4ac2cb01f07f1f32d3977310bb917385464 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov <serb@openjdk.org> Date: Fri, 1 Mar 2013 21:50:00 +0400 Subject: [PATCH 123/180] 7184945: [macosx] NPE in AquaComboBoxUI since jdk7u6b17, jdk8b47 Reviewed-by: malenkov, alexsch --- .../classes/com/apple/laf/AquaComboBoxUI.java | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/jdk/src/macosx/classes/com/apple/laf/AquaComboBoxUI.java b/jdk/src/macosx/classes/com/apple/laf/AquaComboBoxUI.java index a4831d29ea9..8e8527f6541 100644 --- a/jdk/src/macosx/classes/com/apple/laf/AquaComboBoxUI.java +++ b/jdk/src/macosx/classes/com/apple/laf/AquaComboBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, 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 @@ -34,7 +34,6 @@ import javax.swing.border.Border; import javax.swing.event.*; import javax.swing.plaf.*; import javax.swing.plaf.basic.*; -import com.apple.laf.ClientPropertyApplicator; import com.apple.laf.ClientPropertyApplicator.Property; import apple.laf.JRSUIConstants.Size; @@ -142,35 +141,46 @@ public class AquaComboBoxUI extends BasicComboBoxUI implements Sizeable { return new AquaComboBoxEditor(); } - class AquaComboBoxEditor extends BasicComboBoxEditor implements UIResource, DocumentListener { - protected AquaComboBoxEditor() { + final class AquaComboBoxEditor extends BasicComboBoxEditor + implements UIResource, DocumentListener { + + AquaComboBoxEditor() { super(); editor = new AquaCustomComboTextField(); editor.addFocusListener(this); editor.getDocument().addDocumentListener(this); } + @Override public void focusGained(final FocusEvent e) { - arrowButton.repaint(); + if (arrowButton != null) { + arrowButton.repaint(); + } } + @Override public void focusLost(final FocusEvent e) { - arrowButton.repaint(); + if (arrowButton != null) { + arrowButton.repaint(); + } } + @Override public void changedUpdate(final DocumentEvent e) { editorTextChanged(); } + @Override public void insertUpdate(final DocumentEvent e) { editorTextChanged(); } + @Override public void removeUpdate(final DocumentEvent e) { editorTextChanged(); } - protected void editorTextChanged() { + private void editorTextChanged() { if (!popup.isVisible()) return; final Object text = editor.getText(); From 6cd495e473d8887edb1807fbd5b70442af66500a Mon Sep 17 00:00:00 2001 From: Sean Mullan <mullan@openjdk.org> Date: Fri, 1 Mar 2013 16:12:50 -0500 Subject: [PATCH 124/180] 8008908: Access denied when invoking Subject.doAsPrivileged() Wildcard principal names are not processed correctly Reviewed-by: xuelei --- .../sun/security/provider/PolicyFile.java | 22 ++++- .../PolicyFile/WildcardPrincipalName.java | 94 +++++++++++++++++++ .../provider/PolicyFile/wildcard.policy | 7 ++ 3 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 jdk/test/sun/security/provider/PolicyFile/WildcardPrincipalName.java create mode 100644 jdk/test/sun/security/provider/PolicyFile/wildcard.policy diff --git a/jdk/src/share/classes/sun/security/provider/PolicyFile.java b/jdk/src/share/classes/sun/security/provider/PolicyFile.java index 5ea389b51e9..f92e1d5905c 100644 --- a/jdk/src/share/classes/sun/security/provider/PolicyFile.java +++ b/jdk/src/share/classes/sun/security/provider/PolicyFile.java @@ -1336,10 +1336,9 @@ public class PolicyFile extends java.security.Policy { if (pppe.isWildcardName()) { // a wildcard name matches any principal with the same class - for (Principal p : principals) { - if (pppe.principalClass.equals(p.getClass().getName())) { - continue; - } + if (wildcardPrincipalNameImplies(pppe.principalClass, + principals)) { + continue; } if (debug != null) { debug.println("evaluation (principal name wildcard) failed"); @@ -1414,6 +1413,21 @@ public class PolicyFile extends java.security.Policy { addPerms(perms, principals, entry); } + /** + * Returns true if the array of principals contains at least one + * principal of the specified class. + */ + private static boolean wildcardPrincipalNameImplies(String principalClass, + Principal[] principals) + { + for (Principal p : principals) { + if (principalClass.equals(p.getClass().getName())) { + return true; + } + } + return false; + } + private void addPerms(Permissions perms, Principal[] accPs, PolicyEntry entry) { diff --git a/jdk/test/sun/security/provider/PolicyFile/WildcardPrincipalName.java b/jdk/test/sun/security/provider/PolicyFile/WildcardPrincipalName.java new file mode 100644 index 00000000000..d81149d036f --- /dev/null +++ b/jdk/test/sun/security/provider/PolicyFile/WildcardPrincipalName.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2013, 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 8008908 + * @summary wildcard principal names are not processed correctly + * @run main/othervm/policy=wildcard.policy WildcardPrincipalName + */ + +import java.security.AccessController; +import java.security.Permission; +import java.security.Principal; +import java.security.PrivilegedAction; +import java.util.HashSet; +import java.util.PropertyPermission; +import java.util.Set; +import javax.security.auth.Subject; +import javax.security.auth.x500.X500Principal; + +public class WildcardPrincipalName { + + public static void main(String[] args) throws Exception { + + X500Principal duke = new X500Principal("CN=Duke"); + PropertyPermission pp = new PropertyPermission("user.home", "read"); + RunAsPrivilegedUserAction runAsPrivilegedUserAction + = new RunAsPrivilegedUserAction(duke, + new CheckPermissionAction(pp)); + AccessController.doPrivileged(runAsPrivilegedUserAction); + System.out.println("test PASSED"); + } + + private static class RunAsPrivilegedUserAction + implements PrivilegedAction<Void> { + private final PrivilegedAction<Void> action; + private final Principal principal; + + RunAsPrivilegedUserAction(Principal principal, + PrivilegedAction<Void> action) { + this.principal = principal; + this.action = action; + } + + @Override public Void run() { + Set<Principal> principals = new HashSet<>(); + Set<Object> publicCredentials = new HashSet<>(); + Set<Object> privateCredentials = new HashSet<>(); + + principals.add(principal); + Subject subject = new Subject(true, + principals, + publicCredentials, + privateCredentials); + + Subject.doAsPrivileged(subject, action, null); + return null; + } + } + + private static class CheckPermissionAction + implements PrivilegedAction<Void> { + private final Permission permission; + + CheckPermissionAction(Permission permission) { + this.permission = permission; + } + + @Override public Void run() { + AccessController.checkPermission(permission); + return null; + } + } +} diff --git a/jdk/test/sun/security/provider/PolicyFile/wildcard.policy b/jdk/test/sun/security/provider/PolicyFile/wildcard.policy new file mode 100644 index 00000000000..55e942db37a --- /dev/null +++ b/jdk/test/sun/security/provider/PolicyFile/wildcard.policy @@ -0,0 +1,7 @@ +grant principal javax.security.auth.x500.X500Principal * { + permission java.util.PropertyPermission "user.home", "read"; +}; + +grant { + permission javax.security.auth.AuthPermission "doAsPrivileged"; +}; From 4994fe08404c0d0b72fd718677e480eb76f9b527 Mon Sep 17 00:00:00 2001 From: Dan Xu <dxu@openjdk.org> Date: Fri, 1 Mar 2013 14:12:59 -0800 Subject: [PATCH 125/180] 8006645: TEST_BUG: java/nio/file/Files/CopyAndMove.java failing intermittently (sol) Fix test failures and update java doc of Files.move Reviewed-by: alanb, chegar --- .../share/classes/java/nio/file/Files.java | 35 ++++++++++--------- jdk/test/java/nio/file/Files/CopyAndMove.java | 9 ++--- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/jdk/src/share/classes/java/nio/file/Files.java b/jdk/src/share/classes/java/nio/file/Files.java index c1c85b521e0..2db7ba25c4a 100644 --- a/jdk/src/share/classes/java/nio/file/Files.java +++ b/jdk/src/share/classes/java/nio/file/Files.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2013, 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 @@ -1152,7 +1152,7 @@ public final class Files { * and file system dependent and therefore unspecified. Minimally, the * {@link BasicFileAttributes#lastModifiedTime last-modified-time} is * copied to the target file if supported by both the source and target - * file store. Copying of file timestamps may result in precision + * file stores. Copying of file timestamps may result in precision * loss. </td> * </tr> * <tr> @@ -1169,12 +1169,12 @@ public final class Files { * implementation specific options. * * <p> Copying a file is not an atomic operation. If an {@link IOException} - * is thrown then it possible that the target file is incomplete or some of - * its file attributes have not been copied from the source file. When the - * {@code REPLACE_EXISTING} option is specified and the target file exists, - * then the target file is replaced. The check for the existence of the file - * and the creation of the new file may not be atomic with respect to other - * file system activities. + * is thrown, then it is possible that the target file is incomplete or some + * of its file attributes have not been copied from the source file. When + * the {@code REPLACE_EXISTING} option is specified and the target file + * exists, then the target file is replaced. The check for the existence of + * the file and the creation of the new file may not be atomic with respect + * to other file system activities. * * <p> <b>Usage Example:</b> * Suppose we want to copy a file into a directory, giving it the same file @@ -1279,15 +1279,16 @@ public final class Files { * <p> An implementation of this interface may support additional * implementation specific options. * - * <p> Where the move requires that the file be copied then the {@link - * BasicFileAttributes#lastModifiedTime last-modified-time} is copied to the - * new file. An implementation may also attempt to copy other file - * attributes but is not required to fail if the file attributes cannot be - * copied. When the move is performed as a non-atomic operation, and a {@code - * IOException} is thrown, then the state of the files is not defined. The - * original file and the target file may both exist, the target file may be - * incomplete or some of its file attributes may not been copied from the - * original file. + * <p> Moving a file will copy the {@link + * BasicFileAttributes#lastModifiedTime last-modified-time} to the target + * file if supported by both source and target file stores. Copying of file + * timestamps may result in precision loss. An implementation may also + * attempt to copy other file attributes but is not required to fail if the + * file attributes cannot be copied. When the move is performed as + * a non-atomic operation, and an {@code IOException} is thrown, then the + * state of the files is not defined. The original file and the target file + * may both exist, the target file may be incomplete or some of its file + * attributes may not been copied from the original file. * * <p> <b>Usage Examples:</b> * Suppose we want to rename a file to "newname", keeping the file in the diff --git a/jdk/test/java/nio/file/Files/CopyAndMove.java b/jdk/test/java/nio/file/Files/CopyAndMove.java index 48ecb0dfcbc..4853b0dcdf4 100644 --- a/jdk/test/java/nio/file/Files/CopyAndMove.java +++ b/jdk/test/java/nio/file/Files/CopyAndMove.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2013, 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 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 6838333 6917021 7006126 6950237 + * @bug 4313887 6838333 6917021 7006126 6950237 8006645 * @summary Unit test for java.nio.file.Files copy and move methods * @library .. * @build CopyAndMove PassThroughFileSystem @@ -37,6 +37,7 @@ import static java.nio.file.LinkOption.*; import java.nio.file.attribute.*; import java.io.*; import java.util.*; +import java.util.concurrent.TimeUnit; public class CopyAndMove { static final Random rand = new Random(); @@ -94,8 +95,8 @@ public class CopyAndMove { // check last modified time if not a symbolic link if (!attrs1.isSymbolicLink()) { - long time1 = attrs1.lastModifiedTime().toMillis(); - long time2 = attrs2.lastModifiedTime().toMillis(); + long time1 = attrs1.lastModifiedTime().to(TimeUnit.SECONDS); + long time2 = attrs2.lastModifiedTime().to(TimeUnit.SECONDS); if (time1 != time2) { System.err.format("File time for %s is %s\n", attrs1.fileKey(), attrs1.lastModifiedTime()); From 3a216a7fdcb0417556d0d39885692e6d0821626c Mon Sep 17 00:00:00 2001 From: Chris Hegarty <chegar@openjdk.org> Date: Sat, 2 Mar 2013 08:54:37 +0000 Subject: [PATCH 126/180] 8008378: FJP.commonPool support parallelism 0, add awaitQuiescence Co-authored-by: Doug Lea <dl@cs.oswego.edu> Reviewed-by: chegar --- .../java/util/concurrent/ForkJoinPool.java | 686 +++++++++--------- .../java/util/concurrent/ForkJoinTask.java | 40 +- .../concurrent/forkjoin/ThreadLessCommon.java | 135 ++++ .../concurrent/forkjoin/ThrowingRunnable.java | 85 +++ 4 files changed, 602 insertions(+), 344 deletions(-) create mode 100644 jdk/test/java/util/concurrent/forkjoin/ThreadLessCommon.java create mode 100644 jdk/test/java/util/concurrent/forkjoin/ThrowingRunnable.java diff --git a/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java index 86bb3b59ebc..0bb27589e60 100644 --- a/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java @@ -35,6 +35,7 @@ package java.util.concurrent; +import java.lang.Thread.UncaughtExceptionHandler; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -104,38 +105,45 @@ import java.util.concurrent.TimeUnit; * there is little difference among choice of methods. * * <table BORDER CELLPADDING=3 CELLSPACING=1> + * <caption>Summary of task execution methods</caption> * <tr> * <td></td> * <td ALIGN=CENTER> <b>Call from non-fork/join clients</b></td> * <td ALIGN=CENTER> <b>Call from within fork/join computations</b></td> * </tr> * <tr> - * <td> <b>Arrange async execution</td> + * <td> <b>Arrange async execution</b></td> * <td> {@link #execute(ForkJoinTask)}</td> * <td> {@link ForkJoinTask#fork}</td> * </tr> * <tr> - * <td> <b>Await and obtain result</td> + * <td> <b>Await and obtain result</b></td> * <td> {@link #invoke(ForkJoinTask)}</td> * <td> {@link ForkJoinTask#invoke}</td> * </tr> * <tr> - * <td> <b>Arrange exec and obtain Future</td> + * <td> <b>Arrange exec and obtain Future</b></td> * <td> {@link #submit(ForkJoinTask)}</td> * <td> {@link ForkJoinTask#fork} (ForkJoinTasks <em>are</em> Futures)</td> * </tr> * </table> * * <p>The common pool is by default constructed with default - * parameters, but these may be controlled by setting three {@link - * System#getProperty system properties} with prefix {@code - * java.util.concurrent.ForkJoinPool.common}: {@code parallelism} -- - * an integer greater than zero, {@code threadFactory} -- the class - * name of a {@link ForkJoinWorkerThreadFactory}, and {@code - * exceptionHandler} -- the class name of a {@link - * java.lang.Thread.UncaughtExceptionHandler - * Thread.UncaughtExceptionHandler}. Upon any error in establishing - * these settings, default parameters are used. + * parameters, but these may be controlled by setting three + * {@linkplain System#getProperty system properties}: + * <ul> + * <li>{@code java.util.concurrent.ForkJoinPool.common.parallelism} + * - the parallelism level, a non-negative integer + * <li>{@code java.util.concurrent.ForkJoinPool.common.threadFactory} + * - the class name of a {@link ForkJoinWorkerThreadFactory} + * <li>{@code java.util.concurrent.ForkJoinPool.common.exceptionHandler} + * - the class name of a {@link UncaughtExceptionHandler} + * </ul> + * The system class loader is used to load these classes. + * Upon any error in establishing these settings, default parameters + * are used. It is possible to disable or limit the use of threads in + * the common pool by setting the parallelism property to zero, and/or + * using a factory that may return {@code null}. * * <p><b>Implementation notes</b>: This implementation restricts the * maximum number of running threads to 32767. Attempts to create @@ -225,18 +233,18 @@ public class ForkJoinPool extends AbstractExecutorService { * for work-stealing (this would contaminate lifo/fifo * processing). Instead, we randomly associate submission queues * with submitting threads, using a form of hashing. The - * ThreadLocal Submitter class contains a value initially used as - * a hash code for choosing existing queues, but may be randomly - * repositioned upon contention with other submitters. In - * essence, submitters act like workers except that they are - * restricted to executing local tasks that they submitted (or in - * the case of CountedCompleters, others with the same root task). - * However, because most shared/external queue operations are more - * expensive than internal, and because, at steady state, external - * submitters will compete for CPU with workers, ForkJoinTask.join - * and related methods disable them from repeatedly helping to - * process tasks if all workers are active. Insertion of tasks in - * shared mode requires a lock (mainly to protect in the case of + * ThreadLocalRandom probe value serves as a hash code for + * choosing existing queues, and may be randomly repositioned upon + * contention with other submitters. In essence, submitters act + * like workers except that they are restricted to executing local + * tasks that they submitted (or in the case of CountedCompleters, + * others with the same root task). However, because most + * shared/external queue operations are more expensive than + * internal, and because, at steady state, external submitters + * will compete for CPU with workers, ForkJoinTask.join and + * related methods disable them from repeatedly helping to process + * tasks if all workers are active. Insertion of tasks in shared + * mode requires a lock (mainly to protect in the case of * resizing) but we use only a simple spinlock (using bits in * field qlock), because submitters encountering a busy queue move * on to try or create other queues -- they block only when @@ -469,7 +477,7 @@ public class ForkJoinPool extends AbstractExecutorService { * Common Pool * =========== * - * The static commonPool always exists after static + * The static common Pool always exists after static * initialization. Since it (or any other created pool) need * never be used, we minimize initial construction overhead and * footprint to the setup of about a dozen fields, with no nested @@ -548,6 +556,7 @@ public class ForkJoinPool extends AbstractExecutorService { * * @param pool the pool this thread works in * @throws NullPointerException if the pool is null + * @return the new worker thread */ public ForkJoinWorkerThread newThread(ForkJoinPool pool); } @@ -563,26 +572,6 @@ public class ForkJoinPool extends AbstractExecutorService { } } - /** - * Per-thread records for threads that submit to pools. Currently - * holds only pseudo-random seed / index that is used to choose - * submission queues in method externalPush. In the future, this may - * also incorporate a means to implement different task rejection - * and resubmission policies. - * - * Seeds for submitters and workers/workQueues work in basically - * the same way but are initialized and updated using slightly - * different mechanics. Both are initialized using the same - * approach as in class ThreadLocal, where successive values are - * unlikely to collide with previous values. Seeds are then - * randomly modified upon collisions using xorshifts, which - * requires a non-zero seed. - */ - static final class Submitter { - int seed; - Submitter(int s) { seed = s; } - } - /** * Class for artificial tasks that are used to replace the target * of local joins if they are removed from an interior queue slot @@ -737,7 +726,7 @@ public class ForkJoinPool extends AbstractExecutorService { * shared-queue version is embedded in method externalPush.) * * @param task the task. Caller must ensure non-null. - * @throw RejectedExecutionException if array cannot be resized + * @throws RejectedExecutionException if array cannot be resized */ final void push(ForkJoinTask<?> task) { ForkJoinTask<?>[] a; ForkJoinPool p; @@ -936,7 +925,7 @@ public class ForkJoinPool extends AbstractExecutorService { * or any other cancelled task. Returns (true) on any CAS * or consistency check failure so caller can retry. * - * @return false if no progress can be made, else true; + * @return false if no progress can be made, else true */ final boolean tryRemoveAndExec(ForkJoinTask<?> task) { boolean stat = true, removed = false, empty = true; @@ -981,7 +970,7 @@ public class ForkJoinPool extends AbstractExecutorService { /** * Polls for and executes the given task or any other task in - * its CountedCompleter computation + * its CountedCompleter computation. */ final boolean pollAndExecCC(ForkJoinTask<?> root) { ForkJoinTask<?>[] a; int b; Object o; @@ -1055,7 +1044,6 @@ public class ForkJoinPool extends AbstractExecutorService { private static final int ABASE; private static final int ASHIFT; static { - int s; try { U = sun.misc.Unsafe.getUnsafe(); Class<?> k = WorkQueue.class; @@ -1063,13 +1051,13 @@ public class ForkJoinPool extends AbstractExecutorService { QLOCK = U.objectFieldOffset (k.getDeclaredField("qlock")); ABASE = U.arrayBaseOffset(ak); - s = U.arrayIndexScale(ak); + int scale = U.arrayIndexScale(ak); + if ((scale & (scale - 1)) != 0) + throw new Error("data type scale not a power of two"); + ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); } catch (Exception e) { throw new Error(e); } - if ((s & (s-1)) != 0) - throw new Error("data type scale not a power of two"); - ASHIFT = 31 - Integer.numberOfLeadingZeros(s); } } @@ -1082,15 +1070,6 @@ public class ForkJoinPool extends AbstractExecutorService { public static final ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory; - /** - * Per-thread submission bookkeeping. Shared across all pools - * to reduce ThreadLocal pollution and because random motion - * to avoid contention in one pool is likely to hold for others. - * Lazily initialized on first submission (but null-checked - * in other contexts to avoid unnecessary initialization). - */ - static final ThreadLocal<Submitter> submitters; - /** * Permission required for callers of methods that may start or * kill threads. @@ -1103,12 +1082,15 @@ public class ForkJoinPool extends AbstractExecutorService { * to paranoically avoid potential initialization circularities * as well as to simplify generated code. */ - static final ForkJoinPool commonPool; + static final ForkJoinPool common; /** - * Common pool parallelism. Must equal commonPool.parallelism. + * Common pool parallelism. To allow simpler use and management + * when common pool threads are disabled, we allow the underlying + * common.config field to be zero, but in that case still report + * parallelism as 1 to reflect resulting caller-runs mechanics. */ - static final int commonPoolParallelism; + static final int commonParallelism; /** * Sequence number for creating workerNamePrefix. @@ -1116,8 +1098,8 @@ public class ForkJoinPool extends AbstractExecutorService { private static int poolNumberSequence; /** - * Return the next sequence number. We don't expect this to - * ever contend so use simple builtin sync. + * Returns the next sequence number. We don't expect this to + * ever contend, so use simple builtin sync. */ private static final synchronized int nextPoolId() { return ++poolNumberSequence; @@ -1161,7 +1143,7 @@ public class ForkJoinPool extends AbstractExecutorService { */ private static final int SEED_INCREMENT = 0x61c88647; - /** + /* * Bits and masks for control variables * * Field ctl is a long packed with: @@ -1268,39 +1250,28 @@ public class ForkJoinPool extends AbstractExecutorService { final int config; // mode and parallelism level WorkQueue[] workQueues; // main registry final ForkJoinWorkerThreadFactory factory; - final Thread.UncaughtExceptionHandler ueh; // per-worker UEH + final UncaughtExceptionHandler ueh; // per-worker UEH final String workerNamePrefix; // to create worker name string volatile Object pad10, pad11, pad12, pad13, pad14, pad15, pad16, pad17; volatile Object pad18, pad19, pad1a, pad1b; - /* + /** * Acquires the plock lock to protect worker array and related * updates. This method is called only if an initial CAS on plock - * fails. This acts as a spinLock for normal cases, but falls back + * fails. This acts as a spinlock for normal cases, but falls back * to builtin monitor to block when (rarely) needed. This would be * a terrible idea for a highly contended lock, but works fine as * a more conservative alternative to a pure spinlock. */ private int acquirePlock() { - int spins = PL_SPINS, r = 0, ps, nps; + int spins = PL_SPINS, ps, nps; for (;;) { if (((ps = plock) & PL_LOCK) == 0 && U.compareAndSwapInt(this, PLOCK, ps, nps = ps + PL_LOCK)) return nps; - else if (r == 0) { // randomize spins if possible - Thread t = Thread.currentThread(); WorkQueue w; Submitter z; - if ((t instanceof ForkJoinWorkerThread) && - (w = ((ForkJoinWorkerThread)t).workQueue) != null) - r = w.seed; - else if ((z = submitters.get()) != null) - r = z.seed; - else - r = 1; - } else if (spins >= 0) { - r ^= r << 1; r ^= r >>> 3; r ^= r << 10; // xorshift - if (r >= 0) + if (ThreadLocalRandom.nextSecondarySeed() >= 0) --spins; } else if (U.compareAndSwapInt(this, PLOCK, ps, ps | PL_SIGNAL)) { @@ -1331,39 +1302,6 @@ public class ForkJoinPool extends AbstractExecutorService { synchronized (this) { notifyAll(); } } - /** - * Performs secondary initialization, called when plock is zero. - * Creates workQueue array and sets plock to a valid value. The - * lock body must be exception-free (so no try/finally) so we - * optimistically allocate new array outside the lock and throw - * away if (very rarely) not needed. (A similar tactic is used in - * fullExternalPush.) Because the plock seq value can eventually - * wrap around zero, this method harmlessly fails to reinitialize - * if workQueues exists, while still advancing plock. - * - * Additionally tries to create the first worker. - */ - private void initWorkers() { - WorkQueue[] ws, nws; int ps; - int p = config & SMASK; // find power of two table size - int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots - n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; - n = (n + 1) << 1; - if ((ws = workQueues) == null || ws.length == 0) - nws = new WorkQueue[n]; - else - nws = null; - if (((ps = plock) & PL_LOCK) != 0 || - !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) - ps = acquirePlock(); - if (((ws = workQueues) == null || ws.length == 0) && nws != null) - workQueues = nws; - int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); - if (!U.compareAndSwapInt(this, PLOCK, ps, nps)) - releasePlock(nps); - tryAddWorker(); - } - /** * Tries to create and start one worker if fewer than target * parallelism level exist. Adjusts counts etc on failure. @@ -1406,7 +1344,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the worker's queue */ final WorkQueue registerWorker(ForkJoinWorkerThread wt) { - Thread.UncaughtExceptionHandler handler; WorkQueue[] ws; int s, ps; + UncaughtExceptionHandler handler; WorkQueue[] ws; int s, ps; wt.setDaemon(true); if ((handler = ueh) != null) wt.setUncaughtExceptionHandler(handler); @@ -1450,7 +1388,7 @@ public class ForkJoinPool extends AbstractExecutorService { * array, and adjusts counts. If pool is shutting down, tries to * complete termination. * - * @param wt the worker thread or null if construction failed + * @param wt the worker thread, or null if construction failed * @param ex the exception causing failure, or null if none */ final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) { @@ -1489,7 +1427,7 @@ public class ForkJoinPool extends AbstractExecutorService { if (e > 0) { // activate or create replacement if ((ws = workQueues) == null || (i = e & SMASK) >= ws.length || - (v = ws[i]) != null) + (v = ws[i]) == null) break; long nc = (((long)(v.nextWait & E_MASK)) | ((long)(u + UAC_UNIT) << 32)); @@ -1526,10 +1464,10 @@ public class ForkJoinPool extends AbstractExecutorService { * @param task the task. Caller must ensure non-null. */ final void externalPush(ForkJoinTask<?> task) { - WorkQueue[] ws; WorkQueue q; Submitter z; int m; ForkJoinTask<?>[] a; - if ((z = submitters.get()) != null && plock > 0 && + WorkQueue[] ws; WorkQueue q; int z, m; ForkJoinTask<?>[] a; + if ((z = ThreadLocalRandom.getProbe()) != 0 && plock > 0 && (ws = workQueues) != null && (m = (ws.length - 1)) >= 0 && - (q = ws[m & z.seed & SQMASK]) != null && + (q = ws[m & z & SQMASK]) != null && U.compareAndSwapInt(q, QLOCK, 0, 1)) { // lock int b = q.base, s = q.top, n, an; if ((a = q.array) != null && (an = a.length) > (n = s + 1 - b)) { @@ -1549,34 +1487,48 @@ public class ForkJoinPool extends AbstractExecutorService { /** * Full version of externalPush. This method is called, among * other times, upon the first submission of the first task to the - * pool, so must perform secondary initialization (via - * initWorkers). It also detects first submission by an external - * thread by looking up its ThreadLocal, and creates a new shared - * queue if the one at index if empty or contended. The plock lock - * body must be exception-free (so no try/finally) so we - * optimistically allocate new queues outside the lock and throw - * them away if (very rarely) not needed. + * pool, so must perform secondary initialization. It also + * detects first submission by an external thread by looking up + * its ThreadLocal, and creates a new shared queue if the one at + * index if empty or contended. The plock lock body must be + * exception-free (so no try/finally) so we optimistically + * allocate new queues outside the lock and throw them away if + * (very rarely) not needed. + * + * Secondary initialization occurs when plock is zero, to create + * workQueue array and set plock to a valid value. This lock body + * must also be exception-free. Because the plock seq value can + * eventually wrap around zero, this method harmlessly fails to + * reinitialize if workQueues exists, while still advancing plock. */ private void fullExternalPush(ForkJoinTask<?> task) { - int r = 0; // random index seed - for (Submitter z = submitters.get();;) { + int r; + if ((r = ThreadLocalRandom.getProbe()) == 0) { + ThreadLocalRandom.localInit(); + r = ThreadLocalRandom.getProbe(); + } + for (;;) { WorkQueue[] ws; WorkQueue q; int ps, m, k; - if (z == null) { - if (U.compareAndSwapInt(this, INDEXSEED, r = indexSeed, - r += SEED_INCREMENT) && r != 0) - submitters.set(z = new Submitter(r)); - } - else if (r == 0) { // move to a different index - r = z.seed; - r ^= r << 13; // same xorshift as WorkQueues - r ^= r >>> 17; - z.seed = r ^ (r << 5); - } - else if ((ps = plock) < 0) + boolean move = false; + if ((ps = plock) < 0) throw new RejectedExecutionException(); else if (ps == 0 || (ws = workQueues) == null || - (m = ws.length - 1) < 0) - initWorkers(); + (m = ws.length - 1) < 0) { // initialize workQueues + int p = config & SMASK; // find power of two table size + int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots + n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; + n |= n >>> 8; n |= n >>> 16; n = (n + 1) << 1; + WorkQueue[] nws = ((ws = workQueues) == null || ws.length == 0 ? + new WorkQueue[n] : null); + if (((ps = plock) & PL_LOCK) != 0 || + !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) + ps = acquirePlock(); + if (((ws = workQueues) == null || ws.length == 0) && nws != null) + workQueues = nws; + int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN); + if (!U.compareAndSwapInt(this, PLOCK, ps, nps)) + releasePlock(nps); + } else if ((q = ws[k = r & m & SQMASK]) != null) { if (q.qlock == 0 && U.compareAndSwapInt(q, QLOCK, 0, 1)) { ForkJoinTask<?>[] a = q.array; @@ -1598,7 +1550,7 @@ public class ForkJoinPool extends AbstractExecutorService { return; } } - r = 0; // move on failure + move = true; // move on failure } else if (((ps = plock) & PL_LOCK) == 0) { // create new queue q = new WorkQueue(this, null, SHARED_QUEUE, r); @@ -1612,7 +1564,9 @@ public class ForkJoinPool extends AbstractExecutorService { releasePlock(nps); } else - r = 0; // try elsewhere while lock held + move = true; // move if busy + if (move) + r = ThreadLocalRandom.advanceProbe(r); } } @@ -1703,7 +1657,7 @@ public class ForkJoinPool extends AbstractExecutorService { * park awaiting signal, else lingering to help scan and signal. * * * If a non-empty queue discovered or left as a hint, - * help wake up other workers before return + * help wake up other workers before return. * * @param w the worker (via its WorkQueue) * @return a task or null if none found @@ -1758,14 +1712,13 @@ public class ForkJoinPool extends AbstractExecutorService { else if ((int)(c >> AC_SHIFT) == 1 - (config & SMASK)) idleAwaitWork(w, nc, c); } - else if (w.eventCount < 0 && !tryTerminate(false, false) && - ctl == c) { // block + else if (w.eventCount < 0 && ctl == c) { Thread wt = Thread.currentThread(); Thread.interrupted(); // clear status U.putObject(wt, PARKBLOCKER, this); w.parker = wt; // emulate LockSupport.park if (w.eventCount < 0) // recheck - U.park(false, 0L); + U.park(false, 0L); // block w.parker = null; U.putObject(wt, PARKBLOCKER, null); } @@ -1774,7 +1727,7 @@ public class ForkJoinPool extends AbstractExecutorService { (ws = workQueues) != null && h < ws.length && (q = ws[h]) != null) { // signal others before retry WorkQueue v; Thread p; int u, i, s; - for (int n = (config & SMASK) >>> 1;;) { + for (int n = (config & SMASK) - 1;;) { int idleCount = (w.eventCount < 0) ? 0 : -1; if (((s = idleCount - q.base + q.top) <= n && (n = s) <= 0) || @@ -1814,7 +1767,8 @@ public class ForkJoinPool extends AbstractExecutorService { */ private void idleAwaitWork(WorkQueue w, long currentCtl, long prevCtl) { if (w != null && w.eventCount < 0 && - !tryTerminate(false, false) && (int)prevCtl != 0) { + !tryTerminate(false, false) && (int)prevCtl != 0 && + ctl == currentCtl) { int dc = -(short)(currentCtl >>> TC_SHIFT); long parkTime = dc < 0 ? FAST_IDLE_TIMEOUT: (dc + 1) * IDLE_TIMEOUT; long deadline = System.nanoTime() + parkTime - TIMEOUT_SLOP; @@ -1832,6 +1786,7 @@ public class ForkJoinPool extends AbstractExecutorService { if (deadline - System.nanoTime() <= 0L && U.compareAndSwapLong(this, CTL, currentCtl, prevCtl)) { w.eventCount = (w.eventCount + E_SEQ) | E_MASK; + w.hint = -1; w.qlock = -1; // shrink break; } @@ -1973,7 +1928,6 @@ public class ForkJoinPool extends AbstractExecutorService { * @param task the task to join * @param mode if shared, exit upon completing any task * if all workers are active - * */ private int helpComplete(ForkJoinTask<?> task, int mode) { WorkQueue[] ws; WorkQueue q; int m, n, s, u; @@ -2125,29 +2079,22 @@ public class ForkJoinPool extends AbstractExecutorService { /** * Returns a (probably) non-empty steal queue, if one is found - * during a random, then cyclic scan, else null. This method must - * be retried by caller if, by the time it tries to use the queue, - * it is empty. + * during a scan, else null. This method must be retried by + * caller if, by the time it tries to use the queue, it is empty. * @param r a (random) seed for scanning */ private WorkQueue findNonEmptyStealQueue(int r) { - for (WorkQueue[] ws;;) { - int ps = plock, m, n; - if ((ws = workQueues) == null || (m = ws.length - 1) < 1) - return null; - for (int j = (m + 1) << 2; ;) { - WorkQueue q = ws[(((r + j) << 1) | 1) & m]; - if (q != null && (n = q.base - q.top) < 0) { - if (n < -1) - signalWork(q); - return q; - } - else if (--j < 0) { - if (plock == ps) - return null; - break; + for (;;) { + int ps = plock, m; WorkQueue[] ws; WorkQueue q; + if ((ws = workQueues) != null && (m = ws.length - 1) >= 0) { + for (int j = (m + 1) << 2; j >= 0; --j) { + if ((q = ws[(((r + j) << 1) | 1) & m]) != null && + q.base - q.top < 0) + return q; } } + if (plock == ps) + return null; } } @@ -2159,37 +2106,34 @@ public class ForkJoinPool extends AbstractExecutorService { */ final void helpQuiescePool(WorkQueue w) { for (boolean active = true;;) { - ForkJoinTask<?> localTask; // exhaust local queue - while ((localTask = w.nextLocalTask()) != null) - localTask.doExec(); - // Similar to loop in scan(), but ignoring submissions - WorkQueue q = findNonEmptyStealQueue(w.nextSeed()); - if (q != null) { - ForkJoinTask<?> t; int b; + long c; WorkQueue q; ForkJoinTask<?> t; int b; + while ((t = w.nextLocalTask()) != null) { + if (w.base - w.top < 0) + signalWork(w); + t.doExec(); + } + if ((q = findNonEmptyStealQueue(w.nextSeed())) != null) { if (!active) { // re-establish active count - long c; active = true; do {} while (!U.compareAndSwapLong (this, CTL, c = ctl, c + AC_UNIT)); } - if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null) + if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null) { + if (q.base - q.top < 0) + signalWork(q); w.runSubtask(t); + } } - else { - long c; - if (active) { // decrement active count without queuing + else if (active) { // decrement active count without queuing + long nc = (c = ctl) - AC_UNIT; + if ((int)(nc >> AC_SHIFT) + (config & SMASK) == 0) + return; // bypass decrement-then-increment + if (U.compareAndSwapLong(this, CTL, c, nc)) active = false; - do {} while (!U.compareAndSwapLong - (this, CTL, c = ctl, c -= AC_UNIT)); - } - else - c = ctl; // re-increment on exit - if ((int)(c >> AC_SHIFT) + (config & SMASK) == 0) { - do {} while (!U.compareAndSwapLong - (this, CTL, c = ctl, c + AC_UNIT)); - break; - } } + else if ((int)((c = ctl) >> AC_SHIFT) + (config & SMASK) == 0 && + U.compareAndSwapLong(this, CTL, c, c + AC_UNIT)) + return; } } @@ -2205,8 +2149,11 @@ public class ForkJoinPool extends AbstractExecutorService { return t; if ((q = findNonEmptyStealQueue(w.nextSeed())) == null) return null; - if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null) + if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null) { + if (q.base - q.top < 0) + signalWork(q); return t; + } } } @@ -2235,7 +2182,7 @@ public class ForkJoinPool extends AbstractExecutorService { * producing extra tasks amortizes the uncertainty of progress and * diffusion assumptions. * - * So, users will want to use values larger, but not much larger + * So, users will want to use values larger (but not much larger) * than 1 to both smooth over transient shortages and hedge * against uneven progress; as traded off against the cost of * extra task overhead. We leave the user to pick a threshold @@ -2288,45 +2235,49 @@ public class ForkJoinPool extends AbstractExecutorService { * @return true if now terminating or terminated */ private boolean tryTerminate(boolean now, boolean enable) { - if (this == commonPool) // cannot shut down + int ps; + if (this == common) // cannot shut down return false; + if ((ps = plock) >= 0) { // enable by setting plock + if (!enable) + return false; + if ((ps & PL_LOCK) != 0 || + !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) + ps = acquirePlock(); + int nps = ((ps + PL_LOCK) & ~SHUTDOWN) | SHUTDOWN; + if (!U.compareAndSwapInt(this, PLOCK, ps, nps)) + releasePlock(nps); + } for (long c;;) { - if (((c = ctl) & STOP_BIT) != 0) { // already terminating + if (((c = ctl) & STOP_BIT) != 0) { // already terminating if ((short)(c >>> TC_SHIFT) == -(config & SMASK)) { synchronized (this) { - notifyAll(); // signal when 0 workers + notifyAll(); // signal when 0 workers } } return true; } - if (plock >= 0) { // not yet enabled - int ps; - if (!enable) + if (!now) { // check if idle & no tasks + WorkQueue[] ws; WorkQueue w; + if ((int)(c >> AC_SHIFT) != -(config & SMASK)) return false; - if (((ps = plock) & PL_LOCK) != 0 || - !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK)) - ps = acquirePlock(); - if (!U.compareAndSwapInt(this, PLOCK, ps, SHUTDOWN)) - releasePlock(SHUTDOWN); - } - if (!now) { // check if idle & no tasks - if ((int)(c >> AC_SHIFT) != -(config & SMASK) || - hasQueuedSubmissions()) - return false; - // Check for unqueued inactive workers. One pass suffices. - WorkQueue[] ws = workQueues; WorkQueue w; - if (ws != null) { - for (int i = 1; i < ws.length; i += 2) { - if ((w = ws[i]) != null && w.eventCount >= 0) - return false; + if ((ws = workQueues) != null) { + for (int i = 0; i < ws.length; ++i) { + if ((w = ws[i]) != null) { + if (!w.isEmpty()) { // signal unprocessed tasks + signalWork(w); + return false; + } + if ((i & 1) != 0 && w.eventCount >= 0) + return false; // unqueued inactive worker + } } } } if (U.compareAndSwapLong(this, CTL, c, c | STOP_BIT)) { for (int pass = 0; pass < 3; ++pass) { - WorkQueue[] ws = workQueues; - if (ws != null) { - WorkQueue w; Thread wt; + WorkQueue[] ws; WorkQueue w; Thread wt; + if ((ws = workQueues) != null) { int n = ws.length; for (int i = 0; i < n; ++i) { if ((w = ws[i]) != null) { @@ -2337,7 +2288,7 @@ public class ForkJoinPool extends AbstractExecutorService { if (!wt.isInterrupted()) { try { wt.interrupt(); - } catch (SecurityException ignore) { + } catch (Throwable ignore) { } } U.unpark(wt); @@ -2348,7 +2299,7 @@ public class ForkJoinPool extends AbstractExecutorService { // Wake up workers parked on event queue int i, e; long cc; Thread p; while ((e = (int)(cc = ctl) & E_MASK) != 0 && - (i = e & SMASK) < n && + (i = e & SMASK) < n && i >= 0 && (w = ws[i]) != null) { long nc = ((long)(w.nextWait & E_MASK) | ((cc + AC_UNIT) & AC_MASK) | @@ -2374,26 +2325,26 @@ public class ForkJoinPool extends AbstractExecutorService { * least one task. */ static WorkQueue commonSubmitterQueue() { - ForkJoinPool p; WorkQueue[] ws; int m; Submitter z; - return ((z = submitters.get()) != null && - (p = commonPool) != null && + ForkJoinPool p; WorkQueue[] ws; int m, z; + return ((z = ThreadLocalRandom.getProbe()) != 0 && + (p = common) != null && (ws = p.workQueues) != null && (m = ws.length - 1) >= 0) ? - ws[m & z.seed & SQMASK] : null; + ws[m & z & SQMASK] : null; } /** * Tries to pop the given task from submitter's queue in common pool. */ static boolean tryExternalUnpush(ForkJoinTask<?> t) { - ForkJoinPool p; WorkQueue[] ws; WorkQueue q; Submitter z; - ForkJoinTask<?>[] a; int m, s; + ForkJoinPool p; WorkQueue[] ws; WorkQueue q; + ForkJoinTask<?>[] a; int m, s, z; if (t != null && - (z = submitters.get()) != null && - (p = commonPool) != null && + (z = ThreadLocalRandom.getProbe()) != 0 && + (p = common) != null && (ws = p.workQueues) != null && (m = ws.length - 1) >= 0 && - (q = ws[m & z.seed & SQMASK]) != null && + (q = ws[m & z & SQMASK]) != null && (s = q.top) != q.base && (a = q.array) != null) { long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE; @@ -2445,9 +2396,10 @@ public class ForkJoinPool extends AbstractExecutorService { if (task != null) task.doExec(); if (root.status < 0 || - (u = (int)(ctl >>> 32)) >= 0 || (u >> UAC_SHIFT) >= 0) + (config != 0 && + ((u = (int)(ctl >>> 32)) >= 0 || (u >> UAC_SHIFT) >= 0))) break; - if (task == null) { + if (task == null) { helpSignal(root, q.poolIndex); if (root.status >= 0) helpComplete(root, SHARED_QUEUE); @@ -2463,14 +2415,14 @@ public class ForkJoinPool extends AbstractExecutorService { */ static void externalHelpJoin(ForkJoinTask<?> t) { // Some hard-to-avoid overlap with tryExternalUnpush - ForkJoinPool p; WorkQueue[] ws; WorkQueue q, w; Submitter z; - ForkJoinTask<?>[] a; int m, s, n; + ForkJoinPool p; WorkQueue[] ws; WorkQueue q, w; + ForkJoinTask<?>[] a; int m, s, n, z; if (t != null && - (z = submitters.get()) != null && - (p = commonPool) != null && + (z = ThreadLocalRandom.getProbe()) != 0 && + (p = common) != null && (ws = p.workQueues) != null && (m = ws.length - 1) >= 0 && - (q = ws[m & z.seed & SQMASK]) != null && + (q = ws[m & z & SQMASK]) != null && (a = q.array) != null) { int am = a.length - 1; if ((s = q.top) != q.base) { @@ -2496,18 +2448,6 @@ public class ForkJoinPool extends AbstractExecutorService { } } - /** - * Restricted version of helpQuiescePool for external callers - */ - static void externalHelpQuiescePool() { - ForkJoinPool p; ForkJoinTask<?> t; WorkQueue q; int b; - if ((p = commonPool) != null && - (q = p.findNonEmptyStealQueue(1)) != null && - (b = q.base) - q.top < 0 && - (t = q.pollAt(b)) != null) - t.doExec(); - } - // Exported methods // Constructors @@ -2524,7 +2464,7 @@ public class ForkJoinPool extends AbstractExecutorService { * java.lang.RuntimePermission}{@code ("modifyThread")} */ public ForkJoinPool() { - this(Runtime.getRuntime().availableProcessors(), + this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()), defaultForkJoinWorkerThreadFactory, null, false); } @@ -2572,50 +2512,63 @@ public class ForkJoinPool extends AbstractExecutorService { */ public ForkJoinPool(int parallelism, ForkJoinWorkerThreadFactory factory, - Thread.UncaughtExceptionHandler handler, + UncaughtExceptionHandler handler, boolean asyncMode) { + this(checkParallelism(parallelism), + checkFactory(factory), + handler, + asyncMode, + "ForkJoinPool-" + nextPoolId() + "-worker-"); checkPermission(); - if (factory == null) - throw new NullPointerException(); + } + + private static int checkParallelism(int parallelism) { if (parallelism <= 0 || parallelism > MAX_CAP) throw new IllegalArgumentException(); + return parallelism; + } + + private static ForkJoinWorkerThreadFactory checkFactory + (ForkJoinWorkerThreadFactory factory) { + if (factory == null) + throw new NullPointerException(); + return factory; + } + + /** + * Creates a {@code ForkJoinPool} with the given parameters, without + * any security checks or parameter validation. Invoked directly by + * makeCommonPool. + */ + private ForkJoinPool(int parallelism, + ForkJoinWorkerThreadFactory factory, + UncaughtExceptionHandler handler, + boolean asyncMode, + String workerNamePrefix) { + this.workerNamePrefix = workerNamePrefix; this.factory = factory; this.ueh = handler; this.config = parallelism | (asyncMode ? (FIFO_QUEUE << 16) : 0); long np = (long)(-parallelism); // offset ctl counts this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK); - int pn = nextPoolId(); - StringBuilder sb = new StringBuilder("ForkJoinPool-"); - sb.append(Integer.toString(pn)); - sb.append("-worker-"); - this.workerNamePrefix = sb.toString(); - } - - /** - * Constructor for common pool, suitable only for static initialization. - * Basically the same as above, but uses smallest possible initial footprint. - */ - ForkJoinPool(int parallelism, long ctl, - ForkJoinWorkerThreadFactory factory, - Thread.UncaughtExceptionHandler handler) { - this.config = parallelism; - this.ctl = ctl; - this.factory = factory; - this.ueh = handler; - this.workerNamePrefix = "ForkJoinPool.commonPool-worker-"; } /** * Returns the common pool instance. This pool is statically - * constructed; its run state is unaffected by attempts to - * {@link #shutdown} or {@link #shutdownNow}. + * constructed; its run state is unaffected by attempts to {@link + * #shutdown} or {@link #shutdownNow}. However this pool and any + * ongoing processing are automatically terminated upon program + * {@link System#exit}. Any program that relies on asynchronous + * task processing to complete before program termination should + * invoke {@code commonPool().}{@link #awaitQuiescence awaitQuiescence}, + * before exit. * * @return the common pool instance * @since 1.8 */ public static ForkJoinPool commonPool() { - // assert commonPool != null : "static init error"; - return commonPool; + // assert common != null : "static init error"; + return common; } // Execution methods @@ -2671,7 +2624,7 @@ public class ForkJoinPool extends AbstractExecutorService { if (task instanceof ForkJoinTask<?>) // avoid re-wrap job = (ForkJoinTask<?>) task; else - job = new ForkJoinTask.AdaptedRunnableAction(task); + job = new ForkJoinTask.RunnableExecuteAction(task); externalPush(job); } @@ -2738,27 +2691,23 @@ public class ForkJoinPool extends AbstractExecutorService { // In previous versions of this class, this method constructed // a task to run ForkJoinTask.invokeAll, but now external // invocation of multiple tasks is at least as efficient. - List<ForkJoinTask<T>> fs = new ArrayList<ForkJoinTask<T>>(tasks.size()); - // Workaround needed because method wasn't declared with - // wildcards in return type but should have been. - @SuppressWarnings({"unchecked", "rawtypes"}) - List<Future<T>> futures = (List<Future<T>>) (List) fs; + ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size()); boolean done = false; try { for (Callable<T> t : tasks) { ForkJoinTask<T> f = new ForkJoinTask.AdaptedCallable<T>(t); + futures.add(f); externalPush(f); - fs.add(f); } - for (ForkJoinTask<T> f : fs) - f.quietlyJoin(); + for (int i = 0, size = futures.size(); i < size; i++) + ((ForkJoinTask<?>)futures.get(i)).quietlyJoin(); done = true; return futures; } finally { if (!done) - for (ForkJoinTask<T> f : fs) - f.cancel(false); + for (int i = 0, size = futures.size(); i < size; i++) + futures.get(i).cancel(false); } } @@ -2777,7 +2726,7 @@ public class ForkJoinPool extends AbstractExecutorService { * * @return the handler, or {@code null} if none */ - public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() { + public UncaughtExceptionHandler getUncaughtExceptionHandler() { return ueh; } @@ -2787,7 +2736,8 @@ public class ForkJoinPool extends AbstractExecutorService { * @return the targeted parallelism level of this pool */ public int getParallelism() { - return config & SMASK; + int par = (config & SMASK); + return (par > 0) ? par : 1; } /** @@ -2797,7 +2747,7 @@ public class ForkJoinPool extends AbstractExecutorService { * @since 1.8 */ public static int getCommonPoolParallelism() { - return commonPoolParallelism; + return commonParallelism; } /** @@ -3055,7 +3005,7 @@ public class ForkJoinPool extends AbstractExecutorService { * Possibly initiates an orderly shutdown in which previously * submitted tasks are executed, but no new tasks will be * accepted. Invocation has no effect on execution state if this - * is the {@link #commonPool}, and no additional effect if + * is the {@link #commonPool()}, and no additional effect if * already shut down. Tasks that are in the process of being * submitted concurrently during the course of this method may or * may not be rejected. @@ -3073,7 +3023,7 @@ public class ForkJoinPool extends AbstractExecutorService { /** * Possibly attempts to cancel and/or stop all tasks, and reject * all subsequently submitted tasks. Invocation has no effect on - * execution state if this is the {@link #commonPool}, and no + * execution state if this is the {@link #commonPool()}, and no * additional effect if already shut down. Otherwise, tasks that * are in the process of being submitted or executed concurrently * during the course of this method may or may not be @@ -3136,9 +3086,10 @@ public class ForkJoinPool extends AbstractExecutorService { /** * Blocks until all tasks have completed execution after a * shutdown request, or the timeout occurs, or the current thread - * is interrupted, whichever happens first. Note that the {@link - * #commonPool()} never terminates until program shutdown so - * this method will always time out. + * is interrupted, whichever happens first. Because the {@link + * #commonPool()} never terminates until program shutdown, when + * applied to the common pool, this method is equivalent to {@link + * #awaitQuiescence(long, TimeUnit)} but always returns {@code false}. * * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument @@ -3148,6 +3099,12 @@ public class ForkJoinPool extends AbstractExecutorService { */ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + if (Thread.interrupted()) + throw new InterruptedException(); + if (this == common) { + awaitQuiescence(timeout, unit); + return false; + } long nanos = unit.toNanos(timeout); if (isTerminated()) return true; @@ -3166,6 +3123,62 @@ public class ForkJoinPool extends AbstractExecutorService { return terminated; } + /** + * If called by a ForkJoinTask operating in this pool, equivalent + * in effect to {@link ForkJoinTask#helpQuiesce}. Otherwise, + * waits and/or attempts to assist performing tasks until this + * pool {@link #isQuiescent} or the indicated timeout elapses. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return {@code true} if quiescent; {@code false} if the + * timeout elapsed. + */ + public boolean awaitQuiescence(long timeout, TimeUnit unit) { + long nanos = unit.toNanos(timeout); + ForkJoinWorkerThread wt; + Thread thread = Thread.currentThread(); + if ((thread instanceof ForkJoinWorkerThread) && + (wt = (ForkJoinWorkerThread)thread).pool == this) { + helpQuiescePool(wt.workQueue); + return true; + } + long startTime = System.nanoTime(); + WorkQueue[] ws; + int r = 0, m; + boolean found = true; + while (!isQuiescent() && (ws = workQueues) != null && + (m = ws.length - 1) >= 0) { + if (!found) { + if ((System.nanoTime() - startTime) > nanos) + return false; + Thread.yield(); // cannot block + } + found = false; + for (int j = (m + 1) << 2; j >= 0; --j) { + ForkJoinTask<?> t; WorkQueue q; int b; + if ((q = ws[r++ & m]) != null && (b = q.base) - q.top < 0) { + found = true; + if ((t = q.pollAt(b)) != null) { + if (q.base - q.top < 0) + signalWork(q); + t.doExec(); + } + break; + } + } + } + return true; + } + + /** + * Waits and/or attempts to assist performing tasks indefinitely + * until the {@link #commonPool()} {@link #isQuiescent}. + */ + static void quiesceCommonPool() { + common.awaitQuiescence(Long.MAX_VALUE, TimeUnit.NANOSECONDS); + } + /** * Interface for extending managed parallelism for tasks running * in {@link ForkJoinPool}s. @@ -3175,9 +3188,9 @@ public class ForkJoinPool extends AbstractExecutorService { * not necessary. Method {@code block} blocks the current thread * if necessary (perhaps internally invoking {@code isReleasable} * before actually blocking). These actions are performed by any - * thread invoking {@link ForkJoinPool#managedBlock}. The - * unusual methods in this API accommodate synchronizers that may, - * but don't usually, block for long periods. Similarly, they + * thread invoking {@link ForkJoinPool#managedBlock(ManagedBlocker)}. + * The unusual methods in this API accommodate synchronizers that + * may, but don't usually, block for long periods. Similarly, they * allow more efficient internal handling of cases in which * additional workers may be, but usually are not, needed to * ensure sufficient parallelism. Toward this end, @@ -3235,6 +3248,7 @@ public class ForkJoinPool extends AbstractExecutorService { /** * Returns {@code true} if blocking is unnecessary. + * @return {@code true} if blocking is unnecessary */ boolean isReleasable(); } @@ -3319,7 +3333,7 @@ public class ForkJoinPool extends AbstractExecutorService { private static final long QLOCK; static { - int s; // initialize field offsets for CAS etc + // initialize field offsets for CAS etc try { U = sun.misc.Unsafe.getUnsafe(); Class<?> k = ForkJoinPool.class; @@ -3339,54 +3353,58 @@ public class ForkJoinPool extends AbstractExecutorService { (wk.getDeclaredField("qlock")); Class<?> ak = ForkJoinTask[].class; ABASE = U.arrayBaseOffset(ak); - s = U.arrayIndexScale(ak); - ASHIFT = 31 - Integer.numberOfLeadingZeros(s); + int scale = U.arrayIndexScale(ak); + if ((scale & (scale - 1)) != 0) + throw new Error("data type scale not a power of two"); + ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); } catch (Exception e) { throw new Error(e); } - if ((s & (s-1)) != 0) - throw new Error("data type scale not a power of two"); - submitters = new ThreadLocal<Submitter>(); - ForkJoinWorkerThreadFactory fac = defaultForkJoinWorkerThreadFactory = + defaultForkJoinWorkerThreadFactory = new DefaultForkJoinWorkerThreadFactory(); modifyThreadPermission = new RuntimePermission("modifyThread"); - /* - * Establish common pool parameters. For extra caution, - * computations to set up common pool state are here; the - * constructor just assigns these values to fields. - */ + common = java.security.AccessController.doPrivileged + (new java.security.PrivilegedAction<ForkJoinPool>() { + public ForkJoinPool run() { return makeCommonPool(); }}); + int par = common.config; // report 1 even if threads disabled + commonParallelism = par > 0 ? par : 1; + } - int par = 0; - Thread.UncaughtExceptionHandler handler = null; - try { // TBD: limit or report ignored exceptions? + /** + * Creates and returns the common pool, respecting user settings + * specified via system properties. + */ + private static ForkJoinPool makeCommonPool() { + int parallelism = -1; + ForkJoinWorkerThreadFactory factory + = defaultForkJoinWorkerThreadFactory; + UncaughtExceptionHandler handler = null; + try { // ignore exceptions in accesing/parsing properties String pp = System.getProperty ("java.util.concurrent.ForkJoinPool.common.parallelism"); - String hp = System.getProperty - ("java.util.concurrent.ForkJoinPool.common.exceptionHandler"); String fp = System.getProperty ("java.util.concurrent.ForkJoinPool.common.threadFactory"); - if (fp != null) - fac = ((ForkJoinWorkerThreadFactory)ClassLoader. - getSystemClassLoader().loadClass(fp).newInstance()); - if (hp != null) - handler = ((Thread.UncaughtExceptionHandler)ClassLoader. - getSystemClassLoader().loadClass(hp).newInstance()); + String hp = System.getProperty + ("java.util.concurrent.ForkJoinPool.common.exceptionHandler"); if (pp != null) - par = Integer.parseInt(pp); + parallelism = Integer.parseInt(pp); + if (fp != null) + factory = ((ForkJoinWorkerThreadFactory)ClassLoader. + getSystemClassLoader().loadClass(fp).newInstance()); + if (hp != null) + handler = ((UncaughtExceptionHandler)ClassLoader. + getSystemClassLoader().loadClass(hp).newInstance()); } catch (Exception ignore) { } - if (par <= 0) - par = Runtime.getRuntime().availableProcessors(); - if (par > MAX_CAP) - par = MAX_CAP; - commonPoolParallelism = par; - long np = (long)(-par); // precompute initial ctl value - long ct = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK); - - commonPool = new ForkJoinPool(par, ct, fac, handler); + if (parallelism < 0) + parallelism = Runtime.getRuntime().availableProcessors(); + if (parallelism > MAX_CAP) + parallelism = MAX_CAP; + return new ForkJoinPool(parallelism, factory, handler, false, + "ForkJoinPool.commonPool-worker-"); } } diff --git a/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java b/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java index 3b4fbb1d8fa..a17cc28b744 100644 --- a/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java +++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java @@ -464,7 +464,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { } /** - * Records exception and possibly propagates + * Records exception and possibly propagates. * * @return status on exit */ @@ -497,7 +497,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { } /** - * Removes exception node and clears status + * Removes exception node and clears status. */ private void clearExceptionalCompletion() { int h = System.identityHashCode(this); @@ -635,7 +635,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { throw (Error)ex; if (ex instanceof RuntimeException) throw (RuntimeException)ex; - throw uncheckedThrowable(ex, RuntimeException.class); + ForkJoinTask.<RuntimeException>uncheckedThrow(ex); } } @@ -645,8 +645,9 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { * unchecked exceptions */ @SuppressWarnings("unchecked") static <T extends Throwable> - T uncheckedThrowable(final Throwable t, final Class<T> c) { - return (T)t; // rely on vacuous cast + void uncheckedThrow(Throwable t) throws T { + if (t != null) + throw (T)t; // rely on vacuous cast } /** @@ -681,7 +682,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ((ForkJoinWorkerThread)t).workQueue.push(this); else - ForkJoinPool.commonPool.externalPush(this); + ForkJoinPool.common.externalPush(this); return this; } @@ -857,7 +858,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { * <p>This method is designed to be invoked by <em>other</em> * tasks. To terminate the current task, you can just return or * throw an unchecked exception from its computation method, or - * invoke {@link #completeExceptionally}. + * invoke {@link #completeExceptionally(Throwable)}. * * @param mayInterruptIfRunning this value has no effect in the * default implementation because interrupts are not used to @@ -1007,8 +1008,9 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { if (Thread.interrupted()) throw new InterruptedException(); // Messy in part because we measure in nanosecs, but wait in millisecs - int s; long ns, ms; - if ((s = status) >= 0 && (ns = unit.toNanos(timeout)) > 0L) { + int s; long ms; + long ns = unit.toNanos(timeout); + if ((s = status) >= 0 && ns > 0L) { long deadline = System.nanoTime() + ns; ForkJoinPool p = null; ForkJoinPool.WorkQueue w = null; @@ -1104,7 +1106,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { wt.pool.helpQuiescePool(wt.workQueue); } else - ForkJoinPool.externalHelpQuiescePool(); + ForkJoinPool.quiesceCommonPool(); } /** @@ -1390,6 +1392,24 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable { private static final long serialVersionUID = 5232453952276885070L; } + /** + * Adaptor for Runnables in which failure forces worker exception + */ + static final class RunnableExecuteAction extends ForkJoinTask<Void> { + final Runnable runnable; + RunnableExecuteAction(Runnable runnable) { + if (runnable == null) throw new NullPointerException(); + this.runnable = runnable; + } + public final Void getRawResult() { return null; } + public final void setRawResult(Void v) { } + public final boolean exec() { runnable.run(); return true; } + void internalPropagateException(Throwable ex) { + rethrow(ex); // rethrow outside exec() catches. + } + private static final long serialVersionUID = 5232453952276885070L; + } + /** * Adaptor for Callables */ diff --git a/jdk/test/java/util/concurrent/forkjoin/ThreadLessCommon.java b/jdk/test/java/util/concurrent/forkjoin/ThreadLessCommon.java new file mode 100644 index 00000000000..1dd3b660f60 --- /dev/null +++ b/jdk/test/java/util/concurrent/forkjoin/ThreadLessCommon.java @@ -0,0 +1,135 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* + * @test + * @bug 8008378 + * @summary Basic checks for parallelism 0, and null returning factory + * @run main/othervm -Djava.util.concurrent.ForkJoinPool.common.parallelism=0 ThreadLessCommon + * @run main/othervm -Djava.util.concurrent.ForkJoinPool.common.threadFactory=ThreadLessCommon$NullForkJoinWorkerThreadFactory ThreadLessCommon + * @author Chris Hegarty + */ + +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory; +import java.util.concurrent.ForkJoinWorkerThread; +import java.util.concurrent.RecursiveTask; + +public class ThreadLessCommon { + + static final int THRESHOLD = 1000; + static final boolean debug = true; + + private static void realMain(String[] args) throws Throwable { + if (debug) { + String pp = System.getProperty( + "java.util.concurrent.ForkJoinPool.common.parallelism"); + System.out.println( + "java.util.concurrent.ForkJoinPool.common.parallelism:" + pp); + String tf = System.getProperty( + "java.util.concurrent.ForkJoinPool.common.threadFactory"); + System.out.println( + "java.util.concurrent.ForkJoinPool.common.threadFactory:" + tf); + } + + long from = 0, to = 50000; + RecursiveTask<Long> task = new SumTask(from, to, Thread.currentThread()); + long sum = task.invoke(); + System.out.printf("%nSum: from [%d] to [%d] = [%d]%n", from, to, sum); + + task.fork(); + sum = task.join(); + System.out.printf("%nSum: from [%d] to [%d] = [%d]%n", from, to, sum); + + sum = ForkJoinPool.commonPool().invoke(task.fork()); + System.out.printf("%nSum: from [%d] to [%d] = [%d]%n", from, to, sum); + } + + static class SumTask extends RecursiveTask<Long> { + final Thread expectedThread; + final long from; + final long to; + SumTask(long from, long to, Thread thread) { + this.from = from; this.to = to; expectedThread = thread; + } + + @Override + public Long compute() { + check(Thread.currentThread() == expectedThread, + "Expected " + expectedThread + ", got " + Thread.currentThread()); + long range = to - from; + if (range < THRESHOLD) { + long acc = 0; + for (long i = from; i <= to; i++) + acc = acc + i; + return acc; + } else { + long half = from + range / 2; + SumTask t1 = new SumTask(from, half ,expectedThread); + SumTask t2 = new SumTask(half+1, to ,expectedThread); + if (half % 2 == 0) { + t1.fork(); + return t2.compute() + t1.join(); + } else { + invokeAll(t1, t2); + try { return t1.get() + t2.get(); } + catch (Exception x) { unexpected(x); return 0L;} + } + } + } + } + + public static class NullForkJoinWorkerThreadFactory + implements ForkJoinWorkerThreadFactory + { + @Override + public ForkJoinWorkerThread newThread(ForkJoinPool pool) { + return null; + } + } + + //--------------------- Infrastructure --------------------------- + static volatile int passed = 0, failed = 0; + static void pass() {passed++;} + static void fail() {failed++; /*Thread.dumpStack();*/} + static void fail(String msg) {System.out.println(msg); fail();} + static void unexpected(Throwable t) {failed++; t.printStackTrace();} + static void check(boolean cond, String msg) {if (cond) pass(); else fail(msg);} + static void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + try {realMain(args);} catch (Throwable t) {unexpected(t);} + System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} diff --git a/jdk/test/java/util/concurrent/forkjoin/ThrowingRunnable.java b/jdk/test/java/util/concurrent/forkjoin/ThrowingRunnable.java new file mode 100644 index 00000000000..47e6f3543db --- /dev/null +++ b/jdk/test/java/util/concurrent/forkjoin/ThrowingRunnable.java @@ -0,0 +1,85 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* + * @test + * @bug 8008378 + * @run main/othervm -Djava.util.concurrent.ForkJoinPool.common.exceptionHandler=ThrowingRunnable + * ThrowingRunnable + * @summary FJP.execute(Runnable), uncaught exception should cause worker thread + * to die. + * @author Chris Hegarty + */ + +import java.lang.Thread.UncaughtExceptionHandler; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.Phaser; +import java.util.concurrent.TimeUnit; + +public class ThrowingRunnable implements Runnable, UncaughtExceptionHandler { + + static final Phaser phaser = new Phaser(2); + + private static void realMain(String[] args) throws Throwable { + ThrowingRunnable r = new ThrowingRunnable(); + ForkJoinPool.commonPool().execute(r); + phaser.awaitAdvanceInterruptibly(phaser.arrive(), 10, TimeUnit.SECONDS); + pass(); + } + + @Override + public void run() { + throw new RuntimeException("This is an exception."); + } + + @Override + public void uncaughtException(Thread t, Throwable e) { + pass(); + phaser.arrive(); + } + + //--------------------- Infrastructure --------------------------- + static volatile int passed = 0, failed = 0; + static void pass() {passed++;} + static void fail() {failed++; /*Thread.dumpStack();*/} + static void fail(String msg) {System.out.println(msg); fail();} + static void unexpected(Throwable t) {failed++; t.printStackTrace();} + static void check(boolean cond, String msg) {if (cond) pass(); else fail(msg);} + static void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + try {realMain(args);} catch (Throwable t) {unexpected(t);} + System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} From bffaa53287e3f47b473ee9493fa2cc0fccac9d7b Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan <ksrini@openjdk.org> Date: Sun, 3 Mar 2013 20:52:04 -0800 Subject: [PATCH 127/180] 8007297: [pack200] allow opcodes with InterfaceMethodRefs Reviewed-by: jrose --- .../sun/java/util/jar/pack/ClassReader.java | 2 +- .../sun/java/util/jar/pack/ConstantPool.java | 4 ++ .../com/sun/java/util/jar/pack/Constants.java | 6 +++ .../sun/java/util/jar/pack/Instruction.java | 20 ++++++-- .../sun/java/util/jar/pack/PackageReader.java | 6 +++ .../sun/java/util/jar/pack/PackageWriter.java | 15 +++++- .../com/sun/java/util/jar/pack/constants.h | 4 ++ .../com/sun/java/util/jar/pack/unpack.cpp | 9 ++++ jdk/test/tools/pack200/AttributeTests.java | 12 +---- jdk/test/tools/pack200/InstructionTests.java | 49 ++++++------------- jdk/test/tools/pack200/Utils.java | 14 ++++++ 11 files changed, 89 insertions(+), 52 deletions(-) diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java index 3df8706da37..3da159f6e29 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java @@ -564,7 +564,7 @@ class ClassReader { code.bytes = new byte[readInt()]; in.readFully(code.bytes); Entry[] cpMap = cls.getCPMap(); - Instruction.opcodeChecker(code.bytes, cpMap); + Instruction.opcodeChecker(code.bytes, cpMap, this.cls.version); int nh = readUnsignedShort(); code.setHandlerCount(nh); for (int i = 0; i < nh; i++) { diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java index ad2175f9993..c23dcb9d4a7 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java @@ -207,6 +207,10 @@ class ConstantPool { return tag; } + public final boolean tagEquals(int tag) { + return getTag() == tag; + } + public Entry getRef(int i) { return null; } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java index 15882624381..5059bc07967 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Constants.java @@ -479,4 +479,10 @@ class Constants { public final static int _qldc = _xldc_op+7; public final static int _qldc_w = _xldc_op+8; public final static int _xldc_limit = _xldc_op+9; + + // handling of InterfaceMethodRef + public final static int _invoke_int_op = _xldc_limit; + public final static int _invokespecial_int = _invoke_int_op+0; + public final static int _invokestatic_int = _invoke_int_op+1; + public final static int _invoke_int_limit = _invoke_int_op+2; } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java index 31ee22b059d..93175fe8ecf 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java @@ -446,12 +446,14 @@ class Instruction { public static boolean isCPRefOp(int bc) { if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0) return true; if (bc >= _xldc_op && bc < _xldc_limit) return true; + if (bc == _invokespecial_int || bc == _invokestatic_int) return true; return false; } public static byte getCPRefOpTag(int bc) { if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0) return BC_TAG[0][bc]; if (bc >= _xldc_op && bc < _xldc_limit) return CONSTANT_LoadableValue; + if (bc == _invokestatic_int || bc == _invokespecial_int) return CONSTANT_InterfaceMethodref; return CONSTANT_None; } @@ -647,7 +649,8 @@ class Instruction { } } - public static void opcodeChecker(byte[] code, ConstantPool.Entry[] cpMap) throws FormatException { + public static void opcodeChecker(byte[] code, ConstantPool.Entry[] cpMap, + Package.Version clsVersion) throws FormatException { Instruction i = at(code, 0); while (i != null) { int opcode = i.getBC(); @@ -658,10 +661,17 @@ class Instruction { ConstantPool.Entry e = i.getCPRef(cpMap); if (e != null) { byte tag = i.getCPTag(); - if (!e.tagMatches(tag)) { - String message = "illegal reference, expected type=" + - ConstantPool.tagName(tag) + ": " + - i.toString(cpMap); + boolean match = e.tagMatches(tag); + if (!match && + (i.bc == _invokespecial || i.bc == _invokestatic) && + e.tagMatches(CONSTANT_InterfaceMethodref) && + clsVersion.greaterThan(Constants.JAVA7_MAX_CLASS_VERSION)) { + match = true; + } + if (!match) { + String message = "illegal reference, expected type=" + + ConstantPool.tagName(tag) + ": " + + i.toString(cpMap); throw new FormatException(message); } } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java index df4687b4aff..b42dda30eb4 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageReader.java @@ -2256,6 +2256,12 @@ class PackageReader extends BandStructure { int origBC = bc; int size = 2; switch (bc) { + case _invokestatic_int: + origBC = _invokestatic; + break; + case _invokespecial_int: + origBC = _invokespecial; + break; case _ildc: case _cldc: case _fldc: diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java index 47959294fd2..a78c9ae9969 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackageWriter.java @@ -1409,6 +1409,10 @@ class PackageWriter extends BandStructure { int bc = i.getBC(); if (!(bc >= _first_linker_op && bc <= _last_linker_op)) return -1; MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap); + // do not optimize this case, simply fall back to regular coding + if ((bc == _invokespecial || bc == _invokestatic) && + ref.tagEquals(CONSTANT_InterfaceMethodref)) + return -1; ClassEntry refClass = ref.classRef; int self_bc = _self_linker_op + (bc - _first_linker_op); if (refClass == curClass.thisClass) @@ -1609,7 +1613,16 @@ class PackageWriter extends BandStructure { case CONSTANT_Fieldref: bc_which = bc_fieldref; break; case CONSTANT_Methodref: - bc_which = bc_methodref; break; + if (ref.tagEquals(CONSTANT_InterfaceMethodref)) { + if (bc == _invokespecial) + vbc = _invokespecial_int; + if (bc == _invokestatic) + vbc = _invokestatic_int; + bc_which = bc_imethodref; + } else { + bc_which = bc_methodref; + } + break; case CONSTANT_InterfaceMethodref: bc_which = bc_imethodref; break; case CONSTANT_InvokeDynamic: diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h b/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h index 040d8edd55b..2f125e0d800 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/constants.h @@ -505,5 +505,9 @@ enum { bc_qldc = _xldc_op+7, bc_qldc_w = _xldc_op+8, _xldc_limit = _xldc_op+9, + _invoke_int_op = _xldc_limit, + _invokespecial_int = _invoke_int_op+0, + _invokestatic_int = _invoke_int_op+1, + _invoke_int_limit = _invoke_int_op+2, _xxx_3_end }; diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp index 9ce0308089f..aae7921ae43 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp @@ -2942,6 +2942,9 @@ band* unpacker::ref_band_for_op(int bc) { case bc_putfield: return &bc_fieldref; + case _invokespecial_int: + case _invokestatic_int: + return &bc_imethodref; case bc_invokevirtual: case bc_invokespecial: case bc_invokestatic: @@ -4177,6 +4180,12 @@ void unpacker::write_bc_ops() { } origBC = bc; switch (bc) { + case _invokestatic_int: + origBC = bc_invokestatic; + break; + case _invokespecial_int: + origBC = bc_invokespecial; + break; case bc_ildc: case bc_cldc: case bc_fldc: diff --git a/jdk/test/tools/pack200/AttributeTests.java b/jdk/test/tools/pack200/AttributeTests.java index 6526737b732..c12891829e7 100644 --- a/jdk/test/tools/pack200/AttributeTests.java +++ b/jdk/test/tools/pack200/AttributeTests.java @@ -67,17 +67,7 @@ public class AttributeTests { File testjarFile = new File(cwd, "test" + Utils.JAR_FILE_EXT); Utils.jar("cvf", testjarFile.getName(), javaClassName); - // pack using native --repack - File nativejarFile = new File(cwd, "out-n" + Utils.JAR_FILE_EXT); - Utils.repack(testjarFile, nativejarFile, false, - "--unknown-attribute=error"); - Utils.doCompareVerify(testjarFile, nativejarFile); - - // pack using java --repack - File javajarFile = new File(cwd, "out-j" + Utils.JAR_FILE_EXT); - Utils.repack(testjarFile, javajarFile, true, - "--unknown-attribute=error"); - Utils.doCompareBitWise(nativejarFile, javajarFile); + Utils.testWithRepack(testjarFile, "--unknown-attribute=error"); } /* * this test checks to see if we get the expected strings for output diff --git a/jdk/test/tools/pack200/InstructionTests.java b/jdk/test/tools/pack200/InstructionTests.java index ce92c0ed558..7015ae9a11f 100644 --- a/jdk/test/tools/pack200/InstructionTests.java +++ b/jdk/test/tools/pack200/InstructionTests.java @@ -26,11 +26,10 @@ import java.nio.file.Files; import java.util.ArrayList; import java.util.List; import static java.nio.file.StandardOpenOption.*; -import java.util.regex.Pattern; /* * @test - * @bug 8003549 + * @bug 8003549 8007297 * @summary tests class files instruction formats introduced in JSR-335 * @compile -XDignore.symbol.file Utils.java InstructionTests.java * @run main InstructionTests @@ -48,52 +47,34 @@ public class InstructionTests { List<String> scratch = new ArrayList<>(); final String fname = "A"; String javaFileName = fname + Utils.JAVA_FILE_EXT; - scratch.add("interface IntIterator {"); + scratch.add("interface I {"); scratch.add(" default void forEach(){}"); scratch.add(" static void next() {}"); scratch.add("}"); - scratch.add("class A implements IntIterator {"); - scratch.add("public void forEach(Object o){"); - scratch.add("IntIterator.super.forEach();"); - scratch.add("IntIterator.next();"); - scratch.add("}"); + scratch.add("class A implements I {"); + scratch.add(" public void forEach(Object o){"); + scratch.add(" I.super.forEach();"); + scratch.add(" I.next();"); + scratch.add(" }"); scratch.add("}"); File cwd = new File("."); File javaFile = new File(cwd, javaFileName); Files.write(javaFile.toPath(), scratch, Charset.defaultCharset(), CREATE, TRUNCATE_EXISTING); - // make sure we have -g so that we compare LVT and LNT entries + // -g to compare LVT and LNT entries Utils.compiler("-g", javaFile.getName()); + File propsFile = new File("pack.props"); + scratch.clear(); + scratch.add("com.sun.java.util.jar.pack.class.format.error=error"); + scratch.add("pack.unknown.attribute=error"); + Files.write(propsFile.toPath(), scratch, Charset.defaultCharset(), + CREATE, TRUNCATE_EXISTING); // jar the file up File testjarFile = new File(cwd, "test" + Utils.JAR_FILE_EXT); Utils.jar("cvf", testjarFile.getName(), "."); - // pack using --repack - File outjarFile = new File(cwd, "out" + Utils.JAR_FILE_EXT); - scratch.clear(); - scratch.add(Utils.getPack200Cmd()); - scratch.add("-J-ea"); - scratch.add("-J-esa"); - scratch.add("--repack"); - scratch.add(outjarFile.getName()); - scratch.add(testjarFile.getName()); - List<String> output = Utils.runExec(scratch); - // TODO remove this when we get bc escapes working correctly - // this test anyhow would fail at that time - findString("WARNING: Passing.*" + fname + Utils.CLASS_FILE_EXT, - output); - - Utils.doCompareVerify(testjarFile, outjarFile); - } - - static boolean findString(String str, List<String> list) { - Pattern p = Pattern.compile(str); - for (String x : list) { - if (p.matcher(x).matches()) - return true; - } - throw new RuntimeException("Error: " + str + " not found in output"); + Utils.testWithRepack(testjarFile, "--config-file=" + propsFile.getName()); } } diff --git a/jdk/test/tools/pack200/Utils.java b/jdk/test/tools/pack200/Utils.java index 07a64595e9f..f3d1d4666b8 100644 --- a/jdk/test/tools/pack200/Utils.java +++ b/jdk/test/tools/pack200/Utils.java @@ -314,6 +314,20 @@ class Utils { throw new RuntimeException("jar command failed"); } } + + static void testWithRepack(File inFile, String... repackOpts) throws IOException { + File cwd = new File("."); + // pack using --repack in native mode + File nativejarFile = new File(cwd, "out-n" + Utils.JAR_FILE_EXT); + repack(inFile, nativejarFile, false, repackOpts); + doCompareVerify(inFile, nativejarFile); + + // ensure bit compatibility between the unpacker variants + File javajarFile = new File(cwd, "out-j" + Utils.JAR_FILE_EXT); + repack(inFile, javajarFile, true, repackOpts); + doCompareBitWise(javajarFile, nativejarFile); + } + static List<String> repack(File inFile, File outFile, boolean disableNative, String... extraOpts) { List<String> cmdList = new ArrayList<>(); From bc576240bccd3624ce8f1290d5f9debebe2c0ce2 Mon Sep 17 00:00:00 2001 From: Joe Darcy <darcy@openjdk.org> Date: Mon, 4 Mar 2013 19:42:56 -0800 Subject: [PATCH 128/180] 8009267: Restore isAnnotationPresent methods in public AnnotatedElement implementations Reviewed-by: jjg --- jdk/src/share/classes/java/lang/Class.java | 11 ++++ jdk/src/share/classes/java/lang/Package.java | 11 ++++ .../java/lang/reflect/AccessibleObject.java | 10 ++++ .../reflect/OldenCompilingWithDefaults.java | 54 +++++++++++++++++++ 4 files changed, 86 insertions(+) create mode 100644 jdk/test/java/lang/reflect/OldenCompilingWithDefaults.java diff --git a/jdk/src/share/classes/java/lang/Class.java b/jdk/src/share/classes/java/lang/Class.java index 671d04a65c7..441f25a8a2c 100644 --- a/jdk/src/share/classes/java/lang/Class.java +++ b/jdk/src/share/classes/java/lang/Class.java @@ -25,6 +25,7 @@ package java.lang; +import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; import java.lang.reflect.Member; @@ -3083,6 +3084,16 @@ public final return (A) annotations.get(annotationClass); } + /** + * {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @since 1.5 + */ + @Override + public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { + return AnnotatedElement.super.isAnnotationPresent(annotationClass); + } + /** * @throws NullPointerException {@inheritDoc} * @since 1.8 diff --git a/jdk/src/share/classes/java/lang/Package.java b/jdk/src/share/classes/java/lang/Package.java index b9776f478db..7d1d38db64d 100644 --- a/jdk/src/share/classes/java/lang/Package.java +++ b/jdk/src/share/classes/java/lang/Package.java @@ -25,6 +25,7 @@ package java.lang; +import java.lang.reflect.AnnotatedElement; import java.io.InputStream; import java.util.Enumeration; @@ -385,6 +386,16 @@ public class Package implements java.lang.reflect.AnnotatedElement { return getPackageInfo().getAnnotation(annotationClass); } + /** + * {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @since 1.5 + */ + @Override + public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { + return AnnotatedElement.super.isAnnotationPresent(annotationClass); + } + /** * @throws NullPointerException {@inheritDoc} * @since 1.8 diff --git a/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java b/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java index d198d939d4b..f98aed5db25 100644 --- a/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java +++ b/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java @@ -181,6 +181,16 @@ public class AccessibleObject implements AnnotatedElement { } /** + * {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @since 1.5 + */ + @Override + public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { + return AnnotatedElement.super.isAnnotationPresent(annotationClass); + } + + /** * @throws NullPointerException {@inheritDoc} * @since 1.8 */ diff --git a/jdk/test/java/lang/reflect/OldenCompilingWithDefaults.java b/jdk/test/java/lang/reflect/OldenCompilingWithDefaults.java new file mode 100644 index 00000000000..c8609b35f9d --- /dev/null +++ b/jdk/test/java/lang/reflect/OldenCompilingWithDefaults.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013, 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 8009267 + * @summary Verify uses of isAnnotationPresent compile under older source versions + * @compile -source 1.5 -target 1.5 OldenCompilingWithDefaults.java + * @compile -source 1.6 -target 1.6 OldenCompilingWithDefaults.java + * @compile -source 1.7 -target 1.7 OldenCompilingWithDefaults.java + * @compile OldenCompilingWithDefaults.java + */ + +import java.lang.reflect.*; + +public class OldenCompilingWithDefaults { + public OldenCompilingWithDefaults(){} + static Object f; + + public static void main(String... args) throws Exception { + Class<OldenCompilingWithDefaults> clazz = OldenCompilingWithDefaults.class; + Package pkg = clazz.getPackage(); + Constructor<OldenCompilingWithDefaults> ctor = clazz.getConstructor(); + Method m = clazz.getMethod("main", String[].class); + Field f = clazz.getField("f"); + + if(clazz.isAnnotationPresent(SuppressWarnings.class) || + pkg.isAnnotationPresent(SuppressWarnings.class) || + ctor.isAnnotationPresent(SuppressWarnings.class) || + m.isAnnotationPresent(SuppressWarnings.class) || + f.isAnnotationPresent(SuppressWarnings.class)) + System.out.println("An annotation is present."); + } +} From 16bd2e129810019abfcc836a5ba6da8c42ba657a Mon Sep 17 00:00:00 2001 From: Naoto Sato <naoto@openjdk.org> Date: Mon, 4 Mar 2013 20:46:42 -0800 Subject: [PATCH 129/180] 8004240: Return value from getAdapterPrefence() can be modified Reviewed-by: okutsu --- .../provider/LocaleProviderAdapter.java | 37 +++++++------- jdk/test/java/util/Locale/Bug8004240.java | 49 +++++++++++++++++++ 2 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 jdk/test/java/util/Locale/Bug8004240.java diff --git a/jdk/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java b/jdk/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java index 2f12f6540ce..d7e32408cbc 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java +++ b/jdk/src/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java @@ -33,6 +33,7 @@ import java.text.spi.DateFormatSymbolsProvider; import java.text.spi.DecimalFormatSymbolsProvider; import java.text.spi.NumberFormatProvider; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.ResourceBundle; @@ -89,10 +90,7 @@ public abstract class LocaleProviderAdapter { * LocaleProviderAdapter preference list. The default list is intended * to behave the same manner in JDK7. */ - private static Type[] adapterPreference = { - Type.JRE, - Type.SPI, - }; + private static final List<Type> adapterPreference; /** * JRE Locale Data Adapter instance @@ -129,10 +127,11 @@ public abstract class LocaleProviderAdapter { static { String order = AccessController.doPrivileged( new sun.security.action.GetPropertyAction("java.locale.providers")); - // Override adapterPreference with the properties one + List<Type> typeList = new ArrayList<>(); + + // Check user specified adapter preference if (order != null && order.length() != 0) { String[] types = order.split(","); - List<Type> typeList = new ArrayList<>(); for (String type : types) { try { Type aType = Type.valueOf(type.trim().toUpperCase(Locale.ROOT)); @@ -153,18 +152,22 @@ public abstract class LocaleProviderAdapter { LocaleServiceProviderPool.config(LocaleProviderAdapter.class, e.toString()); } } - - if (!typeList.isEmpty()) { - if (!typeList.contains(Type.JRE)) { - // Append FALLBACK as the last resort. - fallbackLocaleProviderAdapter = new FallbackLocaleProviderAdapter(); - typeList.add(Type.FALLBACK); - } - adapterPreference = typeList.toArray(new Type[0]); - } } - } + if (!typeList.isEmpty()) { + if (!typeList.contains(Type.JRE)) { + // Append FALLBACK as the last resort. + fallbackLocaleProviderAdapter = new FallbackLocaleProviderAdapter(); + typeList.add(Type.FALLBACK); + } + } else { + // Default preference list + typeList.add(Type.JRE); + typeList.add(Type.SPI); + } + + adapterPreference = Collections.unmodifiableList(typeList); + } /** * Returns the singleton instance for each adapter type @@ -202,7 +205,7 @@ public abstract class LocaleProviderAdapter { /** * Returns the preference order of LocaleProviderAdapter.Type */ - public static Type[] getAdapterPreference() { + public static List<Type> getAdapterPreference() { return adapterPreference; } diff --git a/jdk/test/java/util/Locale/Bug8004240.java b/jdk/test/java/util/Locale/Bug8004240.java new file mode 100644 index 00000000000..84f291b93ba --- /dev/null +++ b/jdk/test/java/util/Locale/Bug8004240.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013, 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 8004240 + * @summary Verify that getAdapterPreference returns an unmodifiable list. + * @compile -XDignore.symbol.file Bug8004240.java + * @run main Bug8004240 + */ + +import java.util.List; +import sun.util.locale.provider.LocaleProviderAdapter; + +public class Bug8004240 { + + public static void main(String[] args) { + List<LocaleProviderAdapter.Type> types = LocaleProviderAdapter.getAdapterPreference(); + + try { + types.set(0, null); + } catch (UnsupportedOperationException e) { + // success + return; + } + + throw new RuntimeException("LocaleProviderAdapter.getAdapterPrefence() returned a modifiable list."); + } +} From 112317dbe3a0674c1f3ec012d33c5a4634992e91 Mon Sep 17 00:00:00 2001 From: Staffan Larsen <sla@openjdk.org> Date: Tue, 5 Mar 2013 08:50:59 +0100 Subject: [PATCH 130/180] 8009287: [parfait] Uninitialised variable in hotspot/agent/src/os/linux/ps_core.c Reviewed-by: dholmes, kvn, mikael, morris --- hotspot/agent/src/os/linux/ps_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/agent/src/os/linux/ps_core.c b/hotspot/agent/src/os/linux/ps_core.c index 30023f2397b..c211ff3b34a 100644 --- a/hotspot/agent/src/os/linux/ps_core.c +++ b/hotspot/agent/src/os/linux/ps_core.c @@ -132,12 +132,12 @@ static map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset, } // Part of the class sharing workaround -static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset, +static void add_class_share_map_info(struct ps_prochandle* ph, off_t offset, uintptr_t vaddr, size_t memsz) { map_info* map; if ((map = allocate_init_map(ph->core->classes_jsa_fd, offset, vaddr, memsz)) == NULL) { - return NULL; + return; } map->next = ph->core->class_share_maps; From 1ba4dd5979d8124c19f89f2c4133617d8eb44d4d Mon Sep 17 00:00:00 2001 From: Eric Wang <ewang@openjdk.org> Date: Tue, 5 Mar 2013 10:10:55 +0000 Subject: [PATCH 131/180] 8009259: TEST_BUG: sun/misc/Cleaner/exitOnThrow.sh failing intermittently Reviewed-by: chegar, alanb --- jdk/test/sun/misc/Cleaner/ExitOnThrow.java | 6 +----- jdk/test/sun/misc/Cleaner/exitOnThrow.sh | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/jdk/test/sun/misc/Cleaner/ExitOnThrow.java b/jdk/test/sun/misc/Cleaner/ExitOnThrow.java index 03ea83d9d45..f4fd8021748 100644 --- a/jdk/test/sun/misc/Cleaner/ExitOnThrow.java +++ b/jdk/test/sun/misc/Cleaner/ExitOnThrow.java @@ -28,21 +28,17 @@ import sun.misc.*; public class ExitOnThrow { - private static volatile boolean ran = false; - public static void main(String[] args) throws Exception { Cleaner.create(new Object(), new Runnable() { public void run() { - ran = true; throw new RuntimeException("Foo!"); } }); - while (!ran) { + while (true) { System.gc(); Thread.sleep(100); } - System.exit(0); } } diff --git a/jdk/test/sun/misc/Cleaner/exitOnThrow.sh b/jdk/test/sun/misc/Cleaner/exitOnThrow.sh index 7506ce4403f..4a22114ab18 100644 --- a/jdk/test/sun/misc/Cleaner/exitOnThrow.sh +++ b/jdk/test/sun/misc/Cleaner/exitOnThrow.sh @@ -25,7 +25,7 @@ # # @test -# @bug 4954921 +# @bug 4954921 8009259 # @summary Ensure that if a cleaner throws an exception then the VM exits # # @build ExitOnThrow From 7659fe9df29c3325df8020c5a921c5387d2a0ccf Mon Sep 17 00:00:00 2001 From: Andrew Brygin <bae@openjdk.org> Date: Tue, 5 Mar 2013 17:18:55 +0400 Subject: [PATCH 132/180] 7152608: [macosx] Crash in liblwawt.dylib in AccelGlyphCache_RemoveCellInfo Reviewed-by: jgodinez, ant --- jdk/src/macosx/classes/sun/font/CStrike.java | 10 ++++++++-- .../classes/sun/font/CStrikeDisposer.java | 2 ++ jdk/src/macosx/native/sun/font/AWTStrike.m | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/jdk/src/macosx/classes/sun/font/CStrike.java b/jdk/src/macosx/classes/sun/font/CStrike.java index 61fe234cb29..9635b85a1de 100644 --- a/jdk/src/macosx/classes/sun/font/CStrike.java +++ b/jdk/src/macosx/classes/sun/font/CStrike.java @@ -500,7 +500,10 @@ public class CStrike extends FontStrike { final Iterator<Long> i = generalCache.values().iterator(); while (i.hasNext()) { final long longValue = i.next().longValue(); - if (longValue != -1 && longValue != 0) StrikeCache.freeLongPointer(longValue); + if (longValue != -1 && longValue != 0) { + removeGlyphInfoFromCache(longValue); + StrikeCache.freeLongPointer(longValue); + } } } @@ -512,7 +515,10 @@ public class CStrike extends FontStrike { private static void disposeLongArray(final long[] longArray) { for (int i = 0; i < longArray.length; i++) { final long ptr = longArray[i]; - if (ptr != 0 && ptr != -1) StrikeCache.freeLongPointer(ptr); // free's the native struct pointer + if (ptr != 0 && ptr != -1) { + removeGlyphInfoFromCache(ptr); + StrikeCache.freeLongPointer(ptr); // free's the native struct pointer + } } } diff --git a/jdk/src/macosx/classes/sun/font/CStrikeDisposer.java b/jdk/src/macosx/classes/sun/font/CStrikeDisposer.java index 7357ea6bd42..661bd6a7b42 100644 --- a/jdk/src/macosx/classes/sun/font/CStrikeDisposer.java +++ b/jdk/src/macosx/classes/sun/font/CStrikeDisposer.java @@ -85,4 +85,6 @@ class CStrikeDisposer extends FontStrikeDisposer { } private native void freeNativeScalerContext(long pContext); + + protected static native void removeGlyphInfoFromCache(long glyphInfo); } diff --git a/jdk/src/macosx/native/sun/font/AWTStrike.m b/jdk/src/macosx/native/sun/font/AWTStrike.m index 261bd34ae57..7f04b530ade 100644 --- a/jdk/src/macosx/native/sun/font/AWTStrike.m +++ b/jdk/src/macosx/native/sun/font/AWTStrike.m @@ -27,11 +27,13 @@ #import "java_awt_geom_PathIterator.h" #import "sun_awt_SunHints.h" #import "sun_font_CStrike.h" +#import "sun_font_CStrikeDisposer.h" #import "CGGlyphImages.h" #import "CGGlyphOutlines.h" #import "AWTStrike.h" #import "CoreTextSupport.h" //#import "jni_util.h" +#include "fontscalerdefs.h" /* Use THIS_FILE when it is available. */ #ifndef THIS_FILE @@ -423,3 +425,19 @@ JNF_COCOA_EXIT(env); return metrics; } + +extern void AccelGlyphCache_RemoveAllInfos(GlyphInfo* glyph); +/* + * Class: sun_font_CStrikeDisposer + * Method: removeGlyphInfoFromCache + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_sun_font_CStrikeDisposer_removeGlyphInfoFromCache +(JNIEnv *env, jclass cls, jlong glyphInfo) +{ + JNF_COCOA_ENTER(env); + + AccelGlyphCache_RemoveAllCellInfos((GlyphInfo*)jlong_to_ptr(glyphInfo)); + + JNF_COCOA_EXIT(env); +} From d2b27faad41f29cfd2126f8a661a740018a0259e Mon Sep 17 00:00:00 2001 From: John Zavgren <jzavgren@openjdk.org> Date: Tue, 5 Mar 2013 14:30:18 +0000 Subject: [PATCH 133/180] 8008804: file descriptor leak in src/windows/native/java/net/DualStackPlainSocketImpl.c Reviewed-by: alanb, chegar, dsamersoff --- .../windows/native/java/net/DualStackPlainDatagramSocketImpl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/src/windows/native/java/net/DualStackPlainDatagramSocketImpl.c b/jdk/src/windows/native/java/net/DualStackPlainDatagramSocketImpl.c index d3de6e7f024..cdd969cef79 100644 --- a/jdk/src/windows/native/java/net/DualStackPlainDatagramSocketImpl.c +++ b/jdk/src/windows/native/java/net/DualStackPlainDatagramSocketImpl.c @@ -89,6 +89,7 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketCrea rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt)); if (rv == SOCKET_ERROR) { NET_ThrowNew(env, WSAGetLastError(), "Socket creation failed"); + closesocket(fd); return -1; } From 838b7a170643806f679728889565399e697f6b22 Mon Sep 17 00:00:00 2001 From: John Zavgren <jzavgren@openjdk.org> Date: Tue, 5 Mar 2013 09:50:53 -0500 Subject: [PATCH 134/180] 4880778: URL final class has protected methods The two set() methods have been defined to be package private. Reviewed-by: alanb, chegar, khazra --- jdk/src/share/classes/java/net/URL.java | 10 +++++----- jdk/src/share/classes/java/net/URLStreamHandler.java | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/jdk/src/share/classes/java/net/URL.java b/jdk/src/share/classes/java/net/URL.java index 62271037126..caa1d5964cb 100644 --- a/jdk/src/share/classes/java/net/URL.java +++ b/jdk/src/share/classes/java/net/URL.java @@ -661,8 +661,8 @@ public final class URL implements java.io.Serializable { * @param file the file on the host * @param ref the internal reference in the URL */ - protected void set(String protocol, String host, - int port, String file, String ref) { + void set(String protocol, String host, int port, + String file, String ref) { synchronized (this) { this.protocol = protocol; this.host = host; @@ -698,9 +698,9 @@ public final class URL implements java.io.Serializable { * @param query the query part of this URL * @since 1.3 */ - protected void set(String protocol, String host, int port, - String authority, String userInfo, String path, - String query, String ref) { + void set(String protocol, String host, int port, + String authority, String userInfo, String path, + String query, String ref) { synchronized (this) { this.protocol = protocol; this.host = host; diff --git a/jdk/src/share/classes/java/net/URLStreamHandler.java b/jdk/src/share/classes/java/net/URLStreamHandler.java index 6af130b6c4c..0561527488d 100644 --- a/jdk/src/share/classes/java/net/URLStreamHandler.java +++ b/jdk/src/share/classes/java/net/URLStreamHandler.java @@ -509,8 +509,8 @@ public abstract class URLStreamHandler { /** * Sets the fields of the <code>URL</code> argument to the indicated values. - * Only classes derived from URLStreamHandler are supposed to be able - * to call the set method on a URL. + * Only classes derived from URLStreamHandler are able + * to use this method to set the values of the URL fields. * * @param u the URL to modify. * @param protocol the protocol name. @@ -539,8 +539,8 @@ public abstract class URLStreamHandler { /** * Sets the fields of the <code>URL</code> argument to the indicated values. - * Only classes derived from URLStreamHandler are supposed to be able - * to call the set method on a URL. + * Only classes derived from URLStreamHandler are able + * to use this method to set the values of the URL fields. * * @param u the URL to modify. * @param protocol the protocol name. This value is ignored since 1.2. From 2b100092d00d34b87508126912b157c597fa958d Mon Sep 17 00:00:00 2001 From: Staffan Larsen <sla@openjdk.org> Date: Tue, 5 Mar 2013 19:25:35 +0100 Subject: [PATCH 135/180] 8009397: test/com/sun/jdi/PrivateTransportTest.sh: ERROR: transport library missing onLoad entry: private_dt_socket Reviewed-by: alanb --- jdk/src/share/back/transport.c | 3 +++ jdk/src/share/demo/jvmti/hprof/hprof_init.c | 9 +++++++++ jdk/src/solaris/back/linker_md.c | 9 +++++++-- jdk/src/solaris/demo/jvmti/hprof/hprof_md.c | 11 ++++++++--- jdk/src/windows/back/linker_md.c | 11 ++++++++--- jdk/src/windows/demo/jvmti/hprof/hprof_md.c | 11 ++++++++--- 6 files changed, 43 insertions(+), 11 deletions(-) diff --git a/jdk/src/share/back/transport.c b/jdk/src/share/back/transport.c index 40608b31239..1d7335d660b 100644 --- a/jdk/src/share/back/transport.c +++ b/jdk/src/share/back/transport.c @@ -117,6 +117,9 @@ loadTransportLibrary(char *libdir, char *name) /* Construct library name (simple name or full path) */ dbgsysBuildLibName(libname, sizeof(libname), plibdir, name); + if (strlen(libname) == 0) { + return NULL; + } /* dlopen (unix) / LoadLibrary (windows) the transport library */ handle = dbgsysLoadLibrary(libname, buf, sizeof(buf)); diff --git a/jdk/src/share/demo/jvmti/hprof/hprof_init.c b/jdk/src/share/demo/jvmti/hprof/hprof_init.c index 328c474d410..aa3c820f1fc 100644 --- a/jdk/src/share/demo/jvmti/hprof/hprof_init.c +++ b/jdk/src/share/demo/jvmti/hprof/hprof_init.c @@ -1899,11 +1899,17 @@ load_library(char *name) */ getSystemProperty("sun.boot.library.path", &boot_path); md_build_library_name(lname, FILENAME_MAX, boot_path, name); + if ( strlen(lname) == 0 ) { + HPROF_ERROR(JNI_TRUE, "Could not find library"); + } jvmtiDeallocate(boot_path); handle = md_load_library(lname, err_buf, (int)sizeof(err_buf)); if ( handle == NULL ) { /* This may be necessary on Windows. */ md_build_library_name(lname, FILENAME_MAX, "", name); + if ( strlen(lname) == 0 ) { + HPROF_ERROR(JNI_TRUE, "Could not find library"); + } handle = md_load_library(lname, err_buf, (int)sizeof(err_buf)); if ( handle == NULL ) { HPROF_ERROR(JNI_TRUE, err_buf); @@ -1968,6 +1974,9 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved) getSystemProperty("sun.boot.library.path", &boot_path); /* Load in NPT library for character conversions */ md_build_library_name(npt_lib, sizeof(npt_lib), boot_path, NPT_LIBNAME); + if ( strlen(npt_lib) == 0 ) { + HPROF_ERROR(JNI_TRUE, "Could not find npt library"); + } jvmtiDeallocate(boot_path); NPT_INITIALIZE(npt_lib, &(gdata->npt), NPT_VERSION, NULL); if ( gdata->npt == NULL ) { diff --git a/jdk/src/solaris/back/linker_md.c b/jdk/src/solaris/back/linker_md.c index a1cbcce3fcf..dbcfc04a40a 100644 --- a/jdk/src/solaris/back/linker_md.c +++ b/jdk/src/solaris/back/linker_md.c @@ -60,6 +60,7 @@ static void dll_build_name(char* buffer, size_t buflen, char *path_sep = PATH_SEPARATOR; char *pathname = (char *)pname; + *buffer = '\0'; while (strlen(pathname) > 0) { char *p = strchr(pathname, *path_sep); if (p == NULL) { @@ -69,13 +70,17 @@ static void dll_build_name(char* buffer, size_t buflen, if (p == pathname) { continue; } - (void)snprintf(buffer, buflen, "%.*s/lib%s." LIB_SUFFIX, (p - pathname), + (void)snprintf(buffer, buflen, "%.*s/lib%s." LIB_SUFFIX, (int)(p - pathname), pathname, fname); if (access(buffer, F_OK) == 0) { break; } - pathname = p + 1; + if (*p == '\0') { + pathname = p; + } else { + pathname = p + 1; + } *buffer = '\0'; } } diff --git a/jdk/src/solaris/demo/jvmti/hprof/hprof_md.c b/jdk/src/solaris/demo/jvmti/hprof/hprof_md.c index 1df2271ce4e..204636328f9 100644 --- a/jdk/src/solaris/demo/jvmti/hprof/hprof_md.c +++ b/jdk/src/solaris/demo/jvmti/hprof/hprof_md.c @@ -385,6 +385,7 @@ static void dll_build_name(char* buffer, size_t buflen, // Loosely based on os_solaris.cpp char *pathname = (char *)pname; + *buffer = '\0'; while (strlen(pathname) > 0) { char *p = strchr(pathname, ':'); if (p == NULL) { @@ -395,12 +396,16 @@ static void dll_build_name(char* buffer, size_t buflen, continue; } (void)snprintf(buffer, buflen, "%.*s/lib%s" JNI_LIB_SUFFIX, - (p - pathname), pathname, fname); + (int)(p - pathname), pathname, fname); if (access(buffer, F_OK) == 0) { - break; + break; + } + if (*p == '\0') { + pathname = p; + } else { + pathname = p + 1; } - pathname = p + 1; *buffer = '\0'; } } diff --git a/jdk/src/windows/back/linker_md.c b/jdk/src/windows/back/linker_md.c index e3ca2584cef..ad48d3d57c2 100644 --- a/jdk/src/windows/back/linker_md.c +++ b/jdk/src/windows/back/linker_md.c @@ -44,6 +44,7 @@ static void dll_build_name(char* buffer, size_t buflen, char *path_sep = PATH_SEPARATOR; char *pathname = (char *)pname; + *buffer = '\0'; while (strlen(pathname) > 0) { char *p = strchr(pathname, *path_sep); if (p == NULL) { @@ -54,16 +55,20 @@ static void dll_build_name(char* buffer, size_t buflen, continue; } if (*(p-1) == ':' || *(p-1) == '\\') { - (void)_snprintf(buffer, buflen, "%.*s%s.dll", (p - pathname), + (void)_snprintf(buffer, buflen, "%.*s%s.dll", (int)(p - pathname), pathname, fname); } else { - (void)_snprintf(buffer, buflen, "%.*s\\%s.dll", (p - pathname), + (void)_snprintf(buffer, buflen, "%.*s\\%s.dll", (int)(p - pathname), pathname, fname); } if (_access(buffer, 0) == 0) { break; } - pathname = p + 1; + if (*p == '\0') { + pathname = p; + } else { + pathname = p + 1; + } *buffer = '\0'; } } diff --git a/jdk/src/windows/demo/jvmti/hprof/hprof_md.c b/jdk/src/windows/demo/jvmti/hprof/hprof_md.c index e5cbeda0f69..4bd4a40f049 100644 --- a/jdk/src/windows/demo/jvmti/hprof/hprof_md.c +++ b/jdk/src/windows/demo/jvmti/hprof/hprof_md.c @@ -372,6 +372,7 @@ static void dll_build_name(char* buffer, size_t buflen, // Loosley based on os_windows.cpp char *pathname = (char *)pname; + *buffer = '\0'; while (strlen(pathname) > 0) { char *p = strchr(pathname, ';'); if (p == NULL) { @@ -382,16 +383,20 @@ static void dll_build_name(char* buffer, size_t buflen, continue; } if (*(p-1) == ':' || *(p-1) == '\\') { - (void)_snprintf(buffer, buflen, "%.*s%s.dll", (p - pathname), + (void)_snprintf(buffer, buflen, "%.*s%s.dll", (int)(p - pathname), pathname, fname); } else { - (void)_snprintf(buffer, buflen, "%.*s\\%s.dll", (p - pathname), + (void)_snprintf(buffer, buflen, "%.*s\\%s.dll", (int)(p - pathname), pathname, fname); } if (_access(buffer, 0) == 0) { break; } - pathname = p + 1; + if (*p == '\0') { + pathname = p; + } else { + pathname = p + 1; + } *buffer = '\0'; } } From 8391257f03fd2ccf35be23327cc00ca7b3d5a9d6 Mon Sep 17 00:00:00 2001 From: Martin Buchholz <martin@openjdk.org> Date: Tue, 5 Mar 2013 13:16:40 -0800 Subject: [PATCH 136/180] 8006988: build-infra: Configure fails if 'cl' is in path on linux Respect user CC and CXX environment variables; use cl iff on windows Reviewed-by: erikj --- common/autoconf/generated-configure.sh | 36 ++++++++++++++++---------- common/autoconf/toolchain.m4 | 34 ++++++++++++++---------- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 04bef5cadc1..5772ad39a19 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -3733,7 +3733,7 @@ fi #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1361899489 +DATE_WHEN_GENERATED=1362517596 ############################################################################### # @@ -18105,14 +18105,18 @@ fi ### Locate C compiler (CC) -# gcc is almost always present, but on Windows we -# prefer cl.exe and on Solaris we prefer CC. -# Thus test for them in this order. -if test "x$OPENJDK_TARGET_OS" = xmacosx; then - # Do not probe for cc on MacOSX. - COMPILER_CHECK_LIST="cl gcc" +# On windows, only cl.exe is supported. +# On Solaris, cc is preferred to gcc. +# Elsewhere, gcc is preferred to cc. + +if test "x$CC" != x; then + COMPILER_CHECK_LIST="$CC" +elif test "x$OPENJDK_TARGET_OS" = "xwindows"; then + COMPILER_CHECK_LIST="cl" +elif test "x$OPENJDK_TARGET_OS" = "xsolaris"; then + COMPILER_CHECK_LIST="cc gcc" else - COMPILER_CHECK_LIST="cl cc gcc" + COMPILER_CHECK_LIST="gcc cc" fi @@ -19076,7 +19080,7 @@ $as_echo "$as_me: The result from running with --version was: \"$COMPILER_VERSIO $as_echo "$as_me: Using $COMPILER_VENDOR $COMPILER_NAME compiler version $COMPILER_VERSION (located at $COMPILER)" >&6;} -# Now that we have resolved CC ourself, let autoconf have it's go at it +# Now that we have resolved CC ourself, let autoconf have its go at it ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -19678,13 +19682,17 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ### Locate C++ compiler (CXX) -if test "x$OPENJDK_TARGET_OS" = xmacosx; then - # Do not probe for CC on MacOSX. - COMPILER_CHECK_LIST="cl g++" +if test "x$CXX" != x; then + COMPILER_CHECK_LIST="$CXX" +elif test "x$OPENJDK_TARGET_OS" = "xwindows"; then + COMPILER_CHECK_LIST="cl" +elif test "x$OPENJDK_TARGET_OS" = "xsolaris"; then + COMPILER_CHECK_LIST="CC g++" else - COMPILER_CHECK_LIST="cl CC g++" + COMPILER_CHECK_LIST="g++ CC" fi + COMPILER_NAME=C++ CXX= @@ -20645,7 +20653,7 @@ $as_echo "$as_me: The result from running with --version was: \"$COMPILER_VERSIO $as_echo "$as_me: Using $COMPILER_VENDOR $COMPILER_NAME compiler version $COMPILER_VERSION (located at $COMPILER)" >&6;} -# Now that we have resolved CXX ourself, let autoconf have it's go at it +# Now that we have resolved CXX ourself, let autoconf have its go at it ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4 index 740b0c48093..80d81c4ff6e 100644 --- a/common/autoconf/toolchain.m4 +++ b/common/autoconf/toolchain.m4 @@ -248,30 +248,38 @@ fi ### Locate C compiler (CC) -# gcc is almost always present, but on Windows we -# prefer cl.exe and on Solaris we prefer CC. -# Thus test for them in this order. -if test "x$OPENJDK_TARGET_OS" = xmacosx; then - # Do not probe for cc on MacOSX. - COMPILER_CHECK_LIST="cl gcc" +# On windows, only cl.exe is supported. +# On Solaris, cc is preferred to gcc. +# Elsewhere, gcc is preferred to cc. + +if test "x$CC" != x; then + COMPILER_CHECK_LIST="$CC" +elif test "x$OPENJDK_TARGET_OS" = "xwindows"; then + COMPILER_CHECK_LIST="cl" +elif test "x$OPENJDK_TARGET_OS" = "xsolaris"; then + COMPILER_CHECK_LIST="cc gcc" else - COMPILER_CHECK_LIST="cl cc gcc" + COMPILER_CHECK_LIST="gcc cc" fi TOOLCHAIN_FIND_COMPILER([CC],[C],[$COMPILER_CHECK_LIST]) -# Now that we have resolved CC ourself, let autoconf have it's go at it +# Now that we have resolved CC ourself, let autoconf have its go at it AC_PROG_CC([$CC]) ### Locate C++ compiler (CXX) -if test "x$OPENJDK_TARGET_OS" = xmacosx; then - # Do not probe for CC on MacOSX. - COMPILER_CHECK_LIST="cl g++" +if test "x$CXX" != x; then + COMPILER_CHECK_LIST="$CXX" +elif test "x$OPENJDK_TARGET_OS" = "xwindows"; then + COMPILER_CHECK_LIST="cl" +elif test "x$OPENJDK_TARGET_OS" = "xsolaris"; then + COMPILER_CHECK_LIST="CC g++" else - COMPILER_CHECK_LIST="cl CC g++" + COMPILER_CHECK_LIST="g++ CC" fi + TOOLCHAIN_FIND_COMPILER([CXX],[C++],[$COMPILER_CHECK_LIST]) -# Now that we have resolved CXX ourself, let autoconf have it's go at it +# Now that we have resolved CXX ourself, let autoconf have its go at it AC_PROG_CXX([$CXX]) ### Locate other tools From 5116181e1f80882289f8c89a674be38af9954099 Mon Sep 17 00:00:00 2001 From: Ioi Lam <ioi.lam@oracle.com> Date: Tue, 5 Mar 2013 13:55:56 -0800 Subject: [PATCH 137/180] 7107135: Stack guard pages are no more protected after loading a shared library with executable stack Detect the execstack attribute of the loaded library and attempt to fix the stack guard using Safepoint op. Reviewed-by: dholmes, zgu --- hotspot/src/os/linux/vm/globals_linux.hpp | 5 +- hotspot/src/os/linux/vm/os_linux.cpp | 120 +++++++++++++++++- hotspot/src/os/linux/vm/os_linux.hpp | 3 + .../os_cpu/linux_sparc/vm/os_linux_sparc.cpp | 5 + .../src/os_cpu/linux_x86/vm/os_linux_x86.cpp | 5 + hotspot/src/share/vm/runtime/thread.hpp | 7 +- .../src/share/vm/runtime/vm_operations.hpp | 1 + hotspot/src/share/vm/utilities/elfFile.cpp | 24 ++++ hotspot/src/share/vm/utilities/elfFile.hpp | 10 ++ hotspot/test/runtime/7107135/Test.java | 65 ++++++++++ hotspot/test/runtime/7107135/Test7107135.sh | 98 ++++++++++++++ hotspot/test/runtime/7107135/TestMT.java | 85 +++++++++++++ hotspot/test/runtime/7107135/test.c | 39 ++++++ 13 files changed, 464 insertions(+), 3 deletions(-) create mode 100644 hotspot/test/runtime/7107135/Test.java create mode 100644 hotspot/test/runtime/7107135/Test7107135.sh create mode 100644 hotspot/test/runtime/7107135/TestMT.java create mode 100644 hotspot/test/runtime/7107135/test.c diff --git a/hotspot/src/os/linux/vm/globals_linux.hpp b/hotspot/src/os/linux/vm/globals_linux.hpp index 56bb45213ad..af4947b1b86 100644 --- a/hotspot/src/os/linux/vm/globals_linux.hpp +++ b/hotspot/src/os/linux/vm/globals_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, 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 @@ -40,6 +40,9 @@ product(bool, UseHugeTLBFS, false, \ "Use MAP_HUGETLB for large pages") \ \ + product(bool, LoadExecStackDllInVMThread, true, \ + "Load DLLs with executable-stack attribute in the VM Thread") \ + \ product(bool, UseSHM, false, \ "Use SYSV shared memory for large pages") diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index b14615e58e8..6dfe962b1c5 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -44,6 +44,7 @@ #include "runtime/extendedPC.hpp" #include "runtime/globals.hpp" #include "runtime/interfaceSupport.hpp" +#include "runtime/init.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/mutexLocker.hpp" @@ -61,6 +62,7 @@ #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" +#include "utilities/elfFile.hpp" #include "utilities/growableArray.hpp" #include "utilities/vmError.hpp" @@ -1796,9 +1798,93 @@ bool os::dll_address_to_library_name(address addr, char* buf, // in case of error it checks if .dll/.so was built for the // same architecture as Hotspot is running on + +// Remember the stack's state. The Linux dynamic linker will change +// the stack to 'executable' at most once, so we must safepoint only once. +bool os::Linux::_stack_is_executable = false; + +// VM operation that loads a library. This is necessary if stack protection +// of the Java stacks can be lost during loading the library. If we +// do not stop the Java threads, they can stack overflow before the stacks +// are protected again. +class VM_LinuxDllLoad: public VM_Operation { + private: + const char *_filename; + void *_lib; + public: + VM_LinuxDllLoad(const char *fn) : + _filename(fn), _lib(NULL) {} + VMOp_Type type() const { return VMOp_LinuxDllLoad; } + void doit() { + _lib = os::Linux::dll_load_inner(_filename); + os::Linux::_stack_is_executable = true; + } + void* loaded_library() { return _lib; } +}; + void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { - void * result= ::dlopen(filename, RTLD_LAZY); + void * result = NULL; + bool load_attempted = false; + + // Check whether the library to load might change execution rights + // of the stack. If they are changed, the protection of the stack + // guard pages will be lost. We need a safepoint to fix this. + // + // See Linux man page execstack(8) for more info. + if (os::uses_stack_guard_pages() && !os::Linux::_stack_is_executable) { + ElfFile ef(filename); + if (!ef.specifies_noexecstack()) { + if (!is_init_completed()) { + os::Linux::_stack_is_executable = true; + // This is OK - No Java threads have been created yet, and hence no + // stack guard pages to fix. + // + // This should happen only when you are building JDK7 using a very + // old version of JDK6 (e.g., with JPRT) and running test_gamma. + // + // Dynamic loader will make all stacks executable after + // this function returns, and will not do that again. + assert(Threads::first() == NULL, "no Java threads should exist yet."); + } else { + warning("You have loaded library %s which might have disabled stack guard. " + "The VM will try to fix the stack guard now.\n" + "It's highly recommended that you fix the library with " + "'execstack -c <libfile>', or link it with '-z noexecstack'.", + filename); + + assert(Thread::current()->is_Java_thread(), "must be Java thread"); + JavaThread *jt = JavaThread::current(); + if (jt->thread_state() != _thread_in_native) { + // This happens when a compiler thread tries to load a hsdis-<arch>.so file + // that requires ExecStack. Cannot enter safe point. Let's give up. + warning("Unable to fix stack guard. Giving up."); + } else { + if (!LoadExecStackDllInVMThread) { + // This is for the case where the DLL has an static + // constructor function that executes JNI code. We cannot + // load such DLLs in the VMThread. + result = ::dlopen(filename, RTLD_LAZY); + } + + ThreadInVMfromNative tiv(jt); + debug_only(VMNativeEntryWrapper vew;) + + VM_LinuxDllLoad op(filename); + VMThread::execute(&op); + if (LoadExecStackDllInVMThread) { + result = op.loaded_library(); + } + load_attempted = true; + } + } + } + } + + if (!load_attempted) { + result = ::dlopen(filename, RTLD_LAZY); + } + if (result != NULL) { // Successful loading return result; @@ -1952,6 +2038,38 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) return NULL; } +void * os::Linux::dll_load_inner(const char *filename) { + void * result = NULL; + if (LoadExecStackDllInVMThread) { + result = ::dlopen(filename, RTLD_LAZY); + } + + // Since 7019808, libjvm.so is linked with -noexecstack. If the VM loads a + // library that requires an executable stack, or which does not have this + // stack attribute set, dlopen changes the stack attribute to executable. The + // read protection of the guard pages gets lost. + // + // Need to check _stack_is_executable again as multiple VM_LinuxDllLoad + // may have been queued at the same time. + + if (!_stack_is_executable) { + JavaThread *jt = Threads::first(); + + while (jt) { + if (!jt->stack_guard_zone_unused() && // Stack not yet fully initialized + jt->stack_yellow_zone_enabled()) { // No pending stack overflow exceptions + if (!os::guard_memory((char *) jt->stack_red_zone_base() - jt->stack_red_zone_size(), + jt->stack_yellow_zone_size() + jt->stack_red_zone_size())) { + warning("Attempt to reguard stack yellow zone failed."); + } + } + jt = jt->next(); + } + } + + return result; +} + /* * glibc-2.0 libdl is not MT safe. If you are building with any glibc, * chances are you might want to run the generated bits against glibc-2.0 diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp index 414ccd976fc..356f7f67afa 100644 --- a/hotspot/src/os/linux/vm/os_linux.hpp +++ b/hotspot/src/os/linux/vm/os_linux.hpp @@ -94,6 +94,9 @@ class Linux { static void print_libversion_info(outputStream* st); public: + static bool _stack_is_executable; + static void *dll_load_inner(const char *name); + static void init_thread_fpu_state(); static int get_fpu_control_word(); static void set_fpu_control_word(int fpu_control); diff --git a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp index 81c013301d2..cf8634f90cb 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp @@ -410,6 +410,11 @@ inline static bool checkOverflow(sigcontext* uc, // to handle_unexpected_exception way down below. thread->disable_stack_red_zone(); tty->print_raw_cr("An irrecoverable stack overflow has occurred."); + + // This is a likely cause, but hard to verify. Let's just print + // it as a hint. + tty->print_raw_cr("Please check if any of your loaded .so files has " + "enabled executable stack (see man page execstack(8))"); } else { // Accessing stack address below sp may cause SEGV if current // thread has MAP_GROWSDOWN stack. This should only happen when diff --git a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp index bfb0e960a0c..4c9d3dbed8b 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp @@ -305,6 +305,11 @@ JVM_handle_linux_signal(int sig, // to handle_unexpected_exception way down below. thread->disable_stack_red_zone(); tty->print_raw_cr("An irrecoverable stack overflow has occurred."); + + // This is a likely cause, but hard to verify. Let's just print + // it as a hint. + tty->print_raw_cr("Please check if any of your loaded .so files has " + "enabled executable stack (see man page execstack(8))"); } else { // Accessing stack address below sp may cause SEGV if current // thread has MAP_GROWSDOWN stack. This should only happen when diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index 98f8d254545..259a4765cf4 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, 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 @@ -1289,6 +1289,7 @@ class JavaThread: public Thread { void enable_stack_red_zone(); void disable_stack_red_zone(); + inline bool stack_guard_zone_unused(); inline bool stack_yellow_zone_disabled(); inline bool stack_yellow_zone_enabled(); @@ -1759,6 +1760,10 @@ inline CompilerThread* JavaThread::as_CompilerThread() { return (CompilerThread*)this; } +inline bool JavaThread::stack_guard_zone_unused() { + return _stack_guard_state == stack_guard_unused; +} + inline bool JavaThread::stack_yellow_zone_disabled() { return _stack_guard_state == stack_guard_yellow_disabled; } diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index 949fa2d34f7..ec3e8519968 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -94,6 +94,7 @@ template(ReportJavaOutOfMemory) \ template(JFRCheckpoint) \ template(Exit) \ + template(LinuxDllLoad) \ class VM_Operation: public CHeapObj<mtInternal> { public: diff --git a/hotspot/src/share/vm/utilities/elfFile.cpp b/hotspot/src/share/vm/utilities/elfFile.cpp index 155a78f5d04..9fba1c39cc2 100644 --- a/hotspot/src/share/vm/utilities/elfFile.cpp +++ b/hotspot/src/share/vm/utilities/elfFile.cpp @@ -197,4 +197,28 @@ ElfStringTable* ElfFile::get_string_table(int index) { return NULL; } +#ifdef LINUX +bool ElfFile::specifies_noexecstack() { + Elf_Phdr phdr; + if (!m_file) return true; + + if (!fseek(m_file, m_elfHdr.e_phoff, SEEK_SET)) { + for (int index = 0; index < m_elfHdr.e_phnum; index ++) { + if (fread((void*)&phdr, sizeof(Elf_Phdr), 1, m_file) != 1) { + m_status = NullDecoder::file_invalid; + return false; + } + if (phdr.p_type == PT_GNU_STACK) { + if (phdr.p_flags == (PF_R | PF_W)) { + return true; + } else { + return false; + } + } + } + } + return false; +} +#endif + #endif // _WINDOWS diff --git a/hotspot/src/share/vm/utilities/elfFile.hpp b/hotspot/src/share/vm/utilities/elfFile.hpp index 60f2a880482..d6aa886bbbb 100644 --- a/hotspot/src/share/vm/utilities/elfFile.hpp +++ b/hotspot/src/share/vm/utilities/elfFile.hpp @@ -43,6 +43,7 @@ typedef Elf64_Addr Elf_Addr; typedef Elf64_Ehdr Elf_Ehdr; typedef Elf64_Shdr Elf_Shdr; +typedef Elf64_Phdr Elf_Phdr; typedef Elf64_Sym Elf_Sym; #if !defined(_ALLBSD_SOURCE) || defined(__APPLE__) @@ -59,6 +60,7 @@ typedef Elf32_Addr Elf_Addr; typedef Elf32_Ehdr Elf_Ehdr; typedef Elf32_Shdr Elf_Shdr; +typedef Elf32_Phdr Elf_Phdr; typedef Elf32_Sym Elf_Sym; #if !defined(_ALLBSD_SOURCE) || defined(__APPLE__) @@ -123,6 +125,14 @@ protected: ElfFile* next() const { return m_next; } void set_next(ElfFile* file) { m_next = file; } + public: + // Returns true if the elf file is marked NOT to require an executable stack, + // or if the file could not be opened. + // Returns false if the elf file requires an executable stack, the stack flag + // is not set at all, or if the file can not be read. + // On systems other than linux it always returns false. + bool specifies_noexecstack() NOT_LINUX({ return false; }); + protected: ElfFile* m_next; diff --git a/hotspot/test/runtime/7107135/Test.java b/hotspot/test/runtime/7107135/Test.java new file mode 100644 index 00000000000..84f3ab3393f --- /dev/null +++ b/hotspot/test/runtime/7107135/Test.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2002-2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 SAP AG. 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. + */ + +class Test { + + static boolean loadLib(String libName){ + try { + System.loadLibrary(libName); + System.out.println("Loaded library "+ libName + "."); + return true; + } catch (SecurityException e) { + System.out.println("loadLibrary(\"" + libName + "\") throws: " + e + "\n"); + } catch (UnsatisfiedLinkError e) { + System.out.println("loadLibrary(\"" + libName + "\") throws: " + e + "\n"); + } + return false; + } + + public static int counter = 1; + + static int Runner() { + counter = counter * -1; + int i = counter; + if(counter < 2) counter += Runner(); + return i; + } + + public static int run() { + try{ + Runner(); + } catch (StackOverflowError e) { + System.out.println("Caught stack overflow error."); + return 0; + } catch (OutOfMemoryError e) { + return 0; + } + return 2; + } + + public static void main(String argv[]) { + loadLib(argv[0]); + System.exit(run()); + } +} diff --git a/hotspot/test/runtime/7107135/Test7107135.sh b/hotspot/test/runtime/7107135/Test7107135.sh new file mode 100644 index 00000000000..6dc91a3039c --- /dev/null +++ b/hotspot/test/runtime/7107135/Test7107135.sh @@ -0,0 +1,98 @@ +#!/bin/sh + +# +# Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011 SAP AG. 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 Test7107135.sh +## @bug 7107135 +## @summary Stack guard pages lost after loading library with executable stack. +## @run shell Test7107135.sh +## + +if [ "${TESTSRC}" = "" ] +then TESTSRC=. +fi + +if [ "${TESTJAVA}" = "" ] +then + PARENT=`dirname \`which java\`` + TESTJAVA=`dirname ${PARENT}` + echo "TESTJAVA not set, selecting " ${TESTJAVA} + echo "If this is incorrect, try setting the variable manually." +fi + +BIT_FLAG="" + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Linux) + NULL=/dev/null + PS=":" + FS="/" + ;; + *) + NULL=NUL + PS=";" + FS="\\" + echo "Test passed; only valid for Linux" + exit 0; + ;; +esac + +ARCH=`uname -m` + +THIS_DIR=`pwd` + +cp ${TESTSRC}${FS}*.java ${THIS_DIR} +${TESTJAVA}${FS}bin${FS}javac *.java + +gcc -fPIC -shared -c -o test.o -I${TESTJAVA}${FS}include -I${TESTJAVA}${FS}include${FS}linux ${TESTSRC}${FS}test.c +ld -shared -z execstack -o libtest-rwx.so test.o +ld -shared -z noexecstack -o libtest-rw.so test.o + + +LD_LIBRARY_PATH=${THIS_DIR} +echo LD_LIBRARY_PATH = ${LD_LIBRARY_PATH} +export LD_LIBRARY_PATH + +# This should not fail. +echo Check testprogram. Expected to pass: +echo ${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} Test test-rw +${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} Test test-rw + +echo +echo Test changing of stack protection: +echo ${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} Test test-rw +${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} Test test-rwx + +if [ "$?" == "0" ] +then + echo + echo ${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} TestMT test-rwx + ${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} TestMT test-rwx +fi + +exit $? diff --git a/hotspot/test/runtime/7107135/TestMT.java b/hotspot/test/runtime/7107135/TestMT.java new file mode 100644 index 00000000000..edea698ac8c --- /dev/null +++ b/hotspot/test/runtime/7107135/TestMT.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2002-2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 SAP AG. 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. + */ + +class TestMT { + + static boolean loadLib(String libName) { + try { + System.loadLibrary(libName); + System.out.println("Loaded library "+ libName + "."); + return true; + } catch (SecurityException e) { + System.out.println("loadLibrary(\"" + libName + "\") throws: " + e + "\n"); + } catch (UnsatisfiedLinkError e) { + System.out.println("loadLibrary(\"" + libName + "\") throws: " + e + "\n"); + } + return false; + } + + public static int counter = 1; + static int Runner() { + counter = counter * -1; + int i = counter; + if (counter < 2) counter += Runner(); + return i; + } + + public static int run(String msg) { + try { + Runner(); + } catch (StackOverflowError e) { + System.out.println(msg + " caught stack overflow error."); + return 0; + } catch (OutOfMemoryError e) { + return 0; + } + return 2; + } + + public static void main(String argv[]) { + try { + for (int i = 0; i < 20; i++) { + Thread t = new DoStackOverflow("SpawnedThread " + i); + t.start(); + } + run("Main thread"); + loadLib("test-rwx"); + run("Main thread"); + } catch (Exception e) { + System.out.println(e); + } + } + + static class DoStackOverflow extends Thread { + public DoStackOverflow(String name) { + super(name); + } + public void run() { + for (int i = 0; i < 10; ++i) { + TestMT.run(getName()); + yield(); + } + } + } +} diff --git a/hotspot/test/runtime/7107135/test.c b/hotspot/test/runtime/7107135/test.c new file mode 100644 index 00000000000..602063f640e --- /dev/null +++ b/hotspot/test/runtime/7107135/test.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2002-2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 SAP AG. 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. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include "jni.h" +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT jint JNICALL Java_Test_someMethod(JNIEnv *env, jobject mainObject) { + return 3; +} + +#ifdef __cplusplus +} +#endif From 4bec822d4011f873fb72cc7a803fa0bd2ef48a7e Mon Sep 17 00:00:00 2001 From: Tao Mao <tao.mao@oracle.com> Date: Tue, 5 Mar 2013 15:36:56 -0800 Subject: [PATCH 138/180] 8008079: G1: Add nextObject routine to CMBitMapRO and replace nextWord Update the task local finger to the start of the next object when marking aborts, in order to avoid the redundant scanning of all 0's when the marking task restarts, if otherwise updating to the next word. In addition, reuse the routine nextObject() in routine iterate(). Reviewed-by: johnc, ysr --- .../share/vm/gc_implementation/g1/concurrentMark.cpp | 2 +- .../share/vm/gc_implementation/g1/concurrentMark.hpp | 10 +++++++--- .../vm/gc_implementation/g1/concurrentMark.inline.hpp | 6 ++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index cc2a611f0f0..ca22b90c769 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -4111,7 +4111,7 @@ void CMTask::do_marking_step(double time_target_ms, // bitmap knows by how much we need to move it as it knows its // granularity). assert(_finger < _region_limit, "invariant"); - HeapWord* new_finger = _nextMarkBitMap->nextWord(_finger); + HeapWord* new_finger = _nextMarkBitMap->nextObject(_finger); // Check if bitmap iteration was aborted while scanning the last object if (new_finger >= _region_limit) { giveup_current_region(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp index 6ec27c7d9fa..61e64df8b9c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp @@ -97,7 +97,6 @@ class CMBitMapRO VALUE_OBJ_CLASS_SPEC { HeapWord* limit = NULL) const; // conversion utilities - // XXX Fix these so that offsets are size_t's... HeapWord* offsetToHeapWord(size_t offset) const { return _bmStartWord + (offset << _shifter); } @@ -105,8 +104,13 @@ class CMBitMapRO VALUE_OBJ_CLASS_SPEC { return pointer_delta(addr, _bmStartWord) >> _shifter; } int heapWordDiffToOffsetDiff(size_t diff) const; - HeapWord* nextWord(HeapWord* addr) { - return offsetToHeapWord(heapWordToOffset(addr) + 1); + + // The argument addr should be the start address of a valid object + HeapWord* nextObject(HeapWord* addr) { + oop obj = (oop) addr; + HeapWord* res = addr + obj->size(); + assert(offsetToHeapWord(heapWordToOffset(res)) == res, "sanity"); + return res; } // debugging diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp index f084bca5a77..d962842b39a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, 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 @@ -252,12 +252,10 @@ inline bool CMBitMapRO::iterate(BitMapClosure* cl, MemRegion mr) { start_offset = _bm.get_next_one_offset(start_offset, end_offset); while (start_offset < end_offset) { - HeapWord* obj_addr = offsetToHeapWord(start_offset); - oop obj = (oop) obj_addr; if (!cl->do_bit(start_offset)) { return false; } - HeapWord* next_addr = MIN2(obj_addr + obj->size(), end_addr); + HeapWord* next_addr = MIN2(nextObject(offsetToHeapWord(start_offset)), end_addr); BitMap::idx_t next_offset = heapWordToOffset(next_addr); start_offset = _bm.get_next_one_offset(next_offset, end_offset); } From a9a7cc3a2301ac338b92dbae11631648ef2779b6 Mon Sep 17 00:00:00 2001 From: David Holmes <dholmes@openjdk.org> Date: Tue, 5 Mar 2013 22:45:59 -0500 Subject: [PATCH 139/180] 8009529: Fix for 8006988 missed closed configure changes Reviewed-by: mr --- common/autoconf/generated-configure.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index a941e313bd7..cdafd221faa 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -3725,7 +3725,7 @@ fi #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1362517596 +DATE_WHEN_GENERATED=1362540061 ############################################################################### # From a99c6a7fe59941b9c9bf0fcd89830e651f6f0da3 Mon Sep 17 00:00:00 2001 From: Alexander Scherbatiy <alexsch@openjdk.org> Date: Wed, 6 Mar 2013 19:42:26 +0400 Subject: [PATCH 140/180] 6877495: JTextField and JTextArea does not support supplementary characters Reviewed-by: serb, alexp --- .../sun/awt/datatransfer/DataTransferer.java | 49 ++++-- .../SuplementaryCharactersTransferTest.java | 165 ++++++++++++++++++ 2 files changed, 199 insertions(+), 15 deletions(-) create mode 100644 jdk/test/sun/awt/datatransfer/SuplementaryCharactersTransferTest.java diff --git a/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java b/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java index f8dd9dfc380..7465d52c8bf 100644 --- a/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java +++ b/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java @@ -1873,7 +1873,7 @@ search: */ public class ReencodingInputStream extends InputStream { protected BufferedReader wrapped; - protected final char[] in = new char[1]; + protected final char[] in = new char[2]; protected byte[] out; protected CharsetEncoder encoder; @@ -1926,7 +1926,7 @@ search: try { encoder = Charset.forName(targetEncoding).newEncoder(); - out = new byte[(int)(encoder.maxBytesPerChar() + 0.5)]; + out = new byte[(int)(encoder.maxBytesPerChar() * 2 + 0.5)]; inBuf = CharBuffer.wrap(in); outBuf = ByteBuffer.wrap(out); } catch (IllegalCharsetNameException e) { @@ -1950,31 +1950,50 @@ search: } } + private int readChar() throws IOException { + int c = wrapped.read(); + + if (c == -1) { // -1 is EOS + eos = true; + return -1; + } + + // "c == 0" is not quite correct, but good enough on Windows. + if (numTerminators > 0 && c == 0) { + eos = true; + return -1; + } else if (eoln != null && matchCharArray(eoln, c)) { + c = '\n' & 0xFFFF; + } + + return c; + } + public int read() throws IOException { if (eos) { return -1; } if (index >= limit) { - int c = wrapped.read(); - - if (c == -1) { // -1 is EOS - eos = true; + // deal with supplementary characters + int c = readChar(); + if (c == -1) { return -1; } - // "c == 0" is not quite correct, but good enough on Windows. - if (numTerminators > 0 && c == 0) { - eos = true; - return -1; - } else if (eoln != null && matchCharArray(eoln, c)) { - c = '\n' & 0xFFFF; + in[0] = (char) c; + in[1] = 0; + inBuf.limit(1); + if (Character.isHighSurrogate((char) c)) { + c = readChar(); + if (c != -1) { + in[1] = (char) c; + inBuf.limit(2); + } } - in[0] = (char)c; - inBuf.rewind(); - outBuf.rewind(); + outBuf.limit(out.length).rewind(); encoder.encode(inBuf, outBuf, false); outBuf.flip(); limit = outBuf.limit(); diff --git a/jdk/test/sun/awt/datatransfer/SuplementaryCharactersTransferTest.java b/jdk/test/sun/awt/datatransfer/SuplementaryCharactersTransferTest.java new file mode 100644 index 00000000000..75f63496bfa --- /dev/null +++ b/jdk/test/sun/awt/datatransfer/SuplementaryCharactersTransferTest.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2013, 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 6877495 + @summary JTextField and JTextArea does not support supplementary characters + @author Alexander Scherbatiy + @run main SuplementaryCharactersTransferTest +*/ + + +import java.io.*; +import java.util.*; +import java.awt.*; +import java.awt.datatransfer.*; +import sun.awt.datatransfer.*; +import sun.awt.datatransfer.DataTransferer.ReencodingInputStream; + +public class SuplementaryCharactersTransferTest { + + public static final long TEXT_FORMAT = 13; + + public static void main(String[] args) throws Exception { + + DataTransferer dataTransferer = new TestDataTransferer(); + dataTransferer.registerTextFlavorProperties("UNICODE TEXT", "utf-16le", "\r\n", "2"); + ByteTransferable transferable = new ByteTransferable(); + ReencodingInputStream is = dataTransferer.new ReencodingInputStream(transferable.getByteInputStream(), TEXT_FORMAT, + DataTransferer.getTextCharset(transferable.getDataFlavor()), transferable); + + byte[] bytes = transferable.getBytes(); + byte[] result = new byte[bytes.length]; + + is.read(result); + + for (int i = 0; i < bytes.length; i++) { + if (bytes[i] != result[i]) { + throw new RuntimeException("Characters are not equal!"); + } + } + + } + + static class ByteTransferable implements Transferable, ClipboardOwner { + + private final DataFlavor dataFlavor; + + public ByteTransferable() throws Exception { + dataFlavor = DataFlavor.getTextPlainUnicodeFlavor(); + } + + public DataFlavor getDataFlavor() { + return dataFlavor; + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[]{dataFlavor}; + } + + public boolean isDataFlavorSupported(DataFlavor flavor) { + return flavor.equals(dataFlavor); + } + + public byte[] getBytes() { + return new byte[]{97, 0, 64, -40, 32, -36, 98, 0}; + } + + public InputStream getByteInputStream() { + return new ByteArrayInputStream(getBytes()); + } + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException { + if (flavor.equals(dataFlavor)) { + return getByteInputStream(); + } else { + throw new UnsupportedFlavorException(flavor); + } + } + + public void lostOwnership(Clipboard clipboard, Transferable contents) { + } + } + + static class TestDataTransferer extends DataTransferer { + + @Override + public String getDefaultUnicodeEncoding() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isLocaleDependentTextFormat(long format) { + return false; + } + + @Override + public boolean isFileFormat(long format) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isImageFormat(long format) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + protected Long getFormatForNativeAsLong(String str) { + return TEXT_FORMAT; + } + + @Override + protected String getNativeForFormat(long format) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + protected ByteArrayOutputStream convertFileListToBytes( + ArrayList<String> fileList) throws IOException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + protected String[] dragQueryFile(byte[] bytes) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + protected Image platformImageBytesOrStreamToImage(InputStream str, + byte[] bytes, long format) throws IOException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + protected byte[] imageToPlatformBytes(Image image, long format) + throws IOException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ToolkitThreadBlockedHandler getToolkitThreadBlockedHandler() { + throw new UnsupportedOperationException("Not supported yet."); + } + } +} \ No newline at end of file From b1d7c46e1428251f988db984d892a697e258eafb Mon Sep 17 00:00:00 2001 From: Mikhail Cherkasov <mcherkas@openjdk.org> Date: Wed, 6 Mar 2013 20:10:04 +0400 Subject: [PATCH 141/180] 8007295: Reduce number of warnings in awt classes Reviewed-by: bae, anthony --- .../classes/java/awt/CheckboxMenuItem.java | 2 +- jdk/src/share/classes/java/awt/Cursor.java | 20 +++++++++---------- .../share/classes/java/awt/EventQueue.java | 6 +++--- jdk/src/share/classes/java/awt/Menu.java | 18 ++++++++--------- jdk/src/share/classes/java/awt/MenuBar.java | 12 +++++------ .../share/classes/java/awt/MenuComponent.java | 4 ++-- jdk/src/share/classes/java/awt/MenuItem.java | 2 +- .../classes/java/awt/RenderingHints.java | 9 +++++---- .../java/awt/datatransfer/Clipboard.java | 8 ++++---- .../java/awt/dnd/DragGestureEvent.java | 7 +++---- .../java/awt/dnd/DragGestureRecognizer.java | 2 +- .../classes/java/awt/dnd/DragSource.java | 9 ++++----- .../awt/dnd/InvalidDnDOperationException.java | 2 ++ .../java/awt/geom/AffineTransform.java | 19 ++++++++++++++++++ 14 files changed, 70 insertions(+), 50 deletions(-) diff --git a/jdk/src/share/classes/java/awt/CheckboxMenuItem.java b/jdk/src/share/classes/java/awt/CheckboxMenuItem.java index 635e9b55b89..ad12d4c29a9 100644 --- a/jdk/src/share/classes/java/awt/CheckboxMenuItem.java +++ b/jdk/src/share/classes/java/awt/CheckboxMenuItem.java @@ -277,7 +277,7 @@ public class CheckboxMenuItem extends MenuItem implements ItemSelectable, Access * @since 1.4 */ public synchronized ItemListener[] getItemListeners() { - return (ItemListener[])(getListeners(ItemListener.class)); + return getListeners(ItemListener.class); } /** diff --git a/jdk/src/share/classes/java/awt/Cursor.java b/jdk/src/share/classes/java/awt/Cursor.java index c340532b20d..d022a647869 100644 --- a/jdk/src/share/classes/java/awt/Cursor.java +++ b/jdk/src/share/classes/java/awt/Cursor.java @@ -163,11 +163,11 @@ public class Cursor implements java.io.Serializable { * hashtable, filesystem dir prefix, filename, and properties for custom cursors support */ - private static final Hashtable systemCustomCursors = new Hashtable(1); + private static final Hashtable<String,Cursor> systemCustomCursors = new Hashtable<>(1); private static final String systemCustomCursorDirPrefix = initCursorDir(); private static String initCursorDir() { - String jhome = (String) java.security.AccessController.doPrivileged( + String jhome = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("java.home")); return jhome + File.separator + "lib" + File.separator + "images" + @@ -298,7 +298,7 @@ public class Cursor implements java.io.Serializable { static public Cursor getSystemCustomCursor(final String name) throws AWTException, HeadlessException { GraphicsEnvironment.checkHeadless(); - Cursor cursor = (Cursor)systemCustomCursors.get(name); + Cursor cursor = systemCustomCursors.get(name); if (cursor == null) { synchronized(systemCustomCursors) { @@ -319,11 +319,11 @@ public class Cursor implements java.io.Serializable { final String fileName = systemCustomCursorProperties.getProperty(key); - String localized = (String)systemCustomCursorProperties.getProperty(prefix + DotNameSuffix); + String localized = systemCustomCursorProperties.getProperty(prefix + DotNameSuffix); if (localized == null) localized = name; - String hotspot = (String)systemCustomCursorProperties.getProperty(prefix + DotHotspotSuffix); + String hotspot = systemCustomCursorProperties.getProperty(prefix + DotHotspotSuffix); if (hotspot == null) throw new AWTException("no hotspot property defined for cursor: " + name); @@ -348,9 +348,9 @@ public class Cursor implements java.io.Serializable { final int fy = y; final String flocalized = localized; - cursor = (Cursor) java.security.AccessController.doPrivileged( - new java.security.PrivilegedExceptionAction() { - public Object run() throws Exception { + cursor = java.security.AccessController.<Cursor>doPrivileged( + new java.security.PrivilegedExceptionAction<Cursor>() { + public Cursor run() throws Exception { Toolkit toolkit = Toolkit.getDefaultToolkit(); Image image = toolkit.getImage( systemCustomCursorDirPrefix + fileName); @@ -447,8 +447,8 @@ public class Cursor implements java.io.Serializable { systemCustomCursorProperties = new Properties(); try { - AccessController.doPrivileged( - new java.security.PrivilegedExceptionAction() { + AccessController.<Object>doPrivileged( + new java.security.PrivilegedExceptionAction<Object>() { public Object run() throws Exception { FileInputStream fis = null; try { diff --git a/jdk/src/share/classes/java/awt/EventQueue.java b/jdk/src/share/classes/java/awt/EventQueue.java index 5ba9756a1af..7f84721dd9e 100644 --- a/jdk/src/share/classes/java/awt/EventQueue.java +++ b/jdk/src/share/classes/java/awt/EventQueue.java @@ -171,7 +171,7 @@ public class EventQueue { * The modifiers field of the current event, if the current event is an * InputEvent or ActionEvent. */ - private WeakReference currentEvent; + private WeakReference<AWTEvent> currentEvent; /* * Non-zero if a thread is waiting in getNextEvent(int) for an event of @@ -809,7 +809,7 @@ public class EventQueue { pushPopLock.lock(); try { return (Thread.currentThread() == dispatchThread) - ? ((AWTEvent)currentEvent.get()) + ? currentEvent.get() : null; } finally { pushPopLock.unlock(); @@ -1167,7 +1167,7 @@ public class EventQueue { return; } - currentEvent = new WeakReference(e); + currentEvent = new WeakReference<>(e); // This series of 'instanceof' checks should be replaced with a // polymorphic type (for example, an interface which declares a diff --git a/jdk/src/share/classes/java/awt/Menu.java b/jdk/src/share/classes/java/awt/Menu.java index e702a9cb8fd..ae5d2fa2f82 100644 --- a/jdk/src/share/classes/java/awt/Menu.java +++ b/jdk/src/share/classes/java/awt/Menu.java @@ -66,7 +66,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { AWTAccessor.setMenuAccessor( new AWTAccessor.MenuAccessor() { - public Vector getItems(Menu menu) { + public Vector<MenuComponent> getItems(Menu menu) { return menu.items; } }); @@ -78,7 +78,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { * @serial * @see #countItems() */ - Vector items = new Vector(); + Vector<MenuComponent> items = new Vector<>(); /** * This field indicates whether the menu has the @@ -313,7 +313,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { } int nitems = getItemCount(); - Vector tempItems = new Vector(); + Vector<MenuItem> tempItems = new Vector<>(); /* Remove the item at index, nitems-index times storing them in a temporary vector in the @@ -330,7 +330,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { already in the correct order in the temp vector. */ for (int i = 0; i < tempItems.size() ; i++) { - add((MenuItem)tempItems.elementAt(i)); + add(tempItems.elementAt(i)); } } } @@ -379,7 +379,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { } int nitems = getItemCount(); - Vector tempItems = new Vector(); + Vector<MenuItem> tempItems = new Vector<>(); /* Remove the item at index, nitems-index times storing them in a temporary vector in the @@ -396,7 +396,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { already in the correct order in the temp vector. */ for (int i = 0; i < tempItems.size() ; i++) { - add((MenuItem)tempItems.elementAt(i)); + add(tempItems.elementAt(i)); } } } @@ -475,13 +475,13 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { return null; } - synchronized Enumeration shortcuts() { - Vector shortcuts = new Vector(); + synchronized Enumeration<MenuShortcut> shortcuts() { + Vector<MenuShortcut> shortcuts = new Vector<>(); int nitems = getItemCount(); for (int i = 0 ; i < nitems ; i++) { MenuItem mi = getItem(i); if (mi instanceof Menu) { - Enumeration e = ((Menu)mi).shortcuts(); + Enumeration<MenuShortcut> e = ((Menu)mi).shortcuts(); while (e.hasMoreElements()) { shortcuts.addElement(e.nextElement()); } diff --git a/jdk/src/share/classes/java/awt/MenuBar.java b/jdk/src/share/classes/java/awt/MenuBar.java index 1fd442e1583..bd0a7d890c0 100644 --- a/jdk/src/share/classes/java/awt/MenuBar.java +++ b/jdk/src/share/classes/java/awt/MenuBar.java @@ -81,7 +81,7 @@ public class MenuBar extends MenuComponent implements MenuContainer, Accessible return menuBar.helpMenu; } - public Vector getMenus(MenuBar menuBar) { + public Vector<Menu> getMenus(MenuBar menuBar) { return menuBar.menus; } }); @@ -94,7 +94,7 @@ public class MenuBar extends MenuComponent implements MenuContainer, Accessible * @serial * @see #countMenus() */ - Vector menus = new Vector(); + Vector<Menu> menus = new Vector<>(); /** * This menu is a special menu dedicated to @@ -309,7 +309,7 @@ public class MenuBar extends MenuComponent implements MenuContainer, Accessible * be called on the toolkit thread. */ final Menu getMenuImpl(int i) { - return (Menu)menus.elementAt(i); + return menus.elementAt(i); } /** @@ -321,10 +321,10 @@ public class MenuBar extends MenuComponent implements MenuContainer, Accessible * @since JDK1.1 */ public synchronized Enumeration<MenuShortcut> shortcuts() { - Vector shortcuts = new Vector(); + Vector<MenuShortcut> shortcuts = new Vector<>(); int nmenus = getMenuCount(); for (int i = 0 ; i < nmenus ; i++) { - Enumeration e = getMenu(i).shortcuts(); + Enumeration<MenuShortcut> e = getMenu(i).shortcuts(); while (e.hasMoreElements()) { shortcuts.addElement(e.nextElement()); } @@ -438,7 +438,7 @@ public class MenuBar extends MenuComponent implements MenuContainer, Accessible // HeadlessException will be thrown from MenuComponent's readObject s.defaultReadObject(); for (int i = 0; i < menus.size(); i++) { - Menu m = (Menu)menus.elementAt(i); + Menu m = menus.elementAt(i); m.parent = this; } } diff --git a/jdk/src/share/classes/java/awt/MenuComponent.java b/jdk/src/share/classes/java/awt/MenuComponent.java index ebd9c0576ba..4895fdc9548 100644 --- a/jdk/src/share/classes/java/awt/MenuComponent.java +++ b/jdk/src/share/classes/java/awt/MenuComponent.java @@ -290,7 +290,7 @@ public abstract class MenuComponent implements java.io.Serializable { public void setFont(Font f) { font = f; //Fixed 6312943: NullPointerException in method MenuComponent.setFont(Font) - MenuComponentPeer peer = (MenuComponentPeer)this.peer; + MenuComponentPeer peer = this.peer; if (peer != null) { peer.setFont(f); } @@ -303,7 +303,7 @@ public abstract class MenuComponent implements java.io.Serializable { */ public void removeNotify() { synchronized (getTreeLock()) { - MenuComponentPeer p = (MenuComponentPeer)this.peer; + MenuComponentPeer p = this.peer; if (p != null) { Toolkit.getEventQueue().removeSourceEvents(this, true); this.peer = null; diff --git a/jdk/src/share/classes/java/awt/MenuItem.java b/jdk/src/share/classes/java/awt/MenuItem.java index 3b8b2cffa0e..4838d187a89 100644 --- a/jdk/src/share/classes/java/awt/MenuItem.java +++ b/jdk/src/share/classes/java/awt/MenuItem.java @@ -564,7 +564,7 @@ public class MenuItem extends MenuComponent implements Accessible { * @since 1.4 */ public synchronized ActionListener[] getActionListeners() { - return (ActionListener[])(getListeners(ActionListener.class)); + return getListeners(ActionListener.class); } /** diff --git a/jdk/src/share/classes/java/awt/RenderingHints.java b/jdk/src/share/classes/java/awt/RenderingHints.java index 5b8daa9e519..48cf9e11d32 100644 --- a/jdk/src/share/classes/java/awt/RenderingHints.java +++ b/jdk/src/share/classes/java/awt/RenderingHints.java @@ -92,7 +92,7 @@ public class RenderingHints * {@code equals()} method. */ public abstract static class Key { - private static HashMap identitymap = new HashMap(17); + private static HashMap<Object,Object> identitymap = new HashMap<>(17); private String getIdentity() { // Note that the identity string is dependent on 3 variables: @@ -138,7 +138,7 @@ public class RenderingHints } // Note: Use a weak reference to avoid holding on to extra // objects and classes after they should be unloaded. - identitymap.put(identity, new WeakReference(k)); + identitymap.put(identity, new WeakReference<Key>(k)); } private int privatekey; @@ -195,7 +195,7 @@ public class RenderingHints } } - HashMap hintmap = new HashMap(7); + HashMap<Object,Object> hintmap = new HashMap<>(7); /** * Antialiasing hint key. @@ -1267,12 +1267,13 @@ public class RenderingHints * object. * @return a clone of this instance. */ + @SuppressWarnings("unchecked") public Object clone() { RenderingHints rh; try { rh = (RenderingHints) super.clone(); if (hintmap != null) { - rh.hintmap = (HashMap) hintmap.clone(); + rh.hintmap = (HashMap<Object,Object>) hintmap.clone(); } } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable diff --git a/jdk/src/share/classes/java/awt/datatransfer/Clipboard.java b/jdk/src/share/classes/java/awt/datatransfer/Clipboard.java index d58bd92f3e0..cce9c74c192 100644 --- a/jdk/src/share/classes/java/awt/datatransfer/Clipboard.java +++ b/jdk/src/share/classes/java/awt/datatransfer/Clipboard.java @@ -71,7 +71,7 @@ public class Clipboard { * * @since 1.5 */ - private Set currentDataFlavors; + private Set<DataFlavor> currentDataFlavors; /** * Creates a clipboard object. @@ -313,7 +313,7 @@ public class Clipboard { if (flavorListeners == null) { return; } - Set prevDataFlavors = currentDataFlavors; + Set<DataFlavor> prevDataFlavors = currentDataFlavors; currentDataFlavors = getAvailableDataFlavorSet(); if (prevDataFlavors.equals(currentDataFlavors)) { return; @@ -339,8 +339,8 @@ public class Clipboard { * * @since 1.5 */ - private Set getAvailableDataFlavorSet() { - Set set = new HashSet(); + private Set<DataFlavor> getAvailableDataFlavorSet() { + Set<DataFlavor> set = new HashSet<>(); Transferable contents = getContents(null); if (contents != null) { DataFlavor[] flavors = contents.getTransferDataFlavors(); diff --git a/jdk/src/share/classes/java/awt/dnd/DragGestureEvent.java b/jdk/src/share/classes/java/awt/dnd/DragGestureEvent.java index 298436fc50f..3b72ed9afda 100644 --- a/jdk/src/share/classes/java/awt/dnd/DragGestureEvent.java +++ b/jdk/src/share/classes/java/awt/dnd/DragGestureEvent.java @@ -165,7 +165,7 @@ public class DragGestureEvent extends EventObject { * <P> * @return an Iterator for the events comprising the gesture */ - + @SuppressWarnings("unchecked") public Iterator<InputEvent> iterator() { return events.iterator(); } /** @@ -184,7 +184,7 @@ public class DragGestureEvent extends EventObject { * <P> * @return an array of the events comprising the gesture */ - + @SuppressWarnings("unchecked") public Object[] toArray(Object[] array) { return events.toArray(array); } /** @@ -333,7 +333,6 @@ public class DragGestureEvent extends EventObject { component = (Component)f.get("component", null); origin = (Point)f.get("origin", null); action = f.get("action", 0); - // Pre-1.4 support. 'events' was previously non-transient try { events = (List)f.get("events", null); @@ -351,7 +350,7 @@ public class DragGestureEvent extends EventObject { /* * fields */ - + @SuppressWarnings("rawtypes") private transient List events; /** diff --git a/jdk/src/share/classes/java/awt/dnd/DragGestureRecognizer.java b/jdk/src/share/classes/java/awt/dnd/DragGestureRecognizer.java index 4b433264701..1f1b9a3f488 100644 --- a/jdk/src/share/classes/java/awt/dnd/DragGestureRecognizer.java +++ b/jdk/src/share/classes/java/awt/dnd/DragGestureRecognizer.java @@ -297,7 +297,7 @@ public abstract class DragGestureRecognizer implements Serializable { * @return the initial event that triggered the drag gesture */ - public InputEvent getTriggerEvent() { return events.isEmpty() ? null : (InputEvent)events.get(0); } + public InputEvent getTriggerEvent() { return events.isEmpty() ? null : events.get(0); } /** * Reset the Recognizer, if its currently recognizing a gesture, ignore diff --git a/jdk/src/share/classes/java/awt/dnd/DragSource.java b/jdk/src/share/classes/java/awt/dnd/DragSource.java index 2311ccc6283..bceedda646b 100644 --- a/jdk/src/share/classes/java/awt/dnd/DragSource.java +++ b/jdk/src/share/classes/java/awt/dnd/DragSource.java @@ -600,7 +600,7 @@ public class DragSource implements Serializable { * @since 1.4 */ public DragSourceListener[] getDragSourceListeners() { - return (DragSourceListener[])getListeners(DragSourceListener.class); + return getListeners(DragSourceListener.class); } /** @@ -660,8 +660,7 @@ public class DragSource implements Serializable { * @since 1.4 */ public DragSourceMotionListener[] getDragSourceMotionListeners() { - return (DragSourceMotionListener[]) - getListeners(DragSourceMotionListener.class); + return getListeners(DragSourceMotionListener.class); } /** @@ -896,8 +895,8 @@ public class DragSource implements Serializable { * @since 1.5 */ public static int getDragThreshold() { - int ts = ((Integer)AccessController.doPrivileged( - new GetIntegerAction("awt.dnd.drag.threshold", 0))).intValue(); + int ts = AccessController.doPrivileged( + new GetIntegerAction("awt.dnd.drag.threshold", 0)).intValue(); if (ts > 0) { return ts; } else { diff --git a/jdk/src/share/classes/java/awt/dnd/InvalidDnDOperationException.java b/jdk/src/share/classes/java/awt/dnd/InvalidDnDOperationException.java index 4ea863c981b..ed94ceefcf7 100644 --- a/jdk/src/share/classes/java/awt/dnd/InvalidDnDOperationException.java +++ b/jdk/src/share/classes/java/awt/dnd/InvalidDnDOperationException.java @@ -36,6 +36,8 @@ package java.awt.dnd; public class InvalidDnDOperationException extends IllegalStateException { + private static final long serialVersionUID = 5156676500247816278L; + static private String dft_msg = "The operation requested cannot be performed by the DnD system since it is not in the appropriate state"; /** diff --git a/jdk/src/share/classes/java/awt/geom/AffineTransform.java b/jdk/src/share/classes/java/awt/geom/AffineTransform.java index 2fa1dc2137a..751deac2497 100644 --- a/jdk/src/share/classes/java/awt/geom/AffineTransform.java +++ b/jdk/src/share/classes/java/awt/geom/AffineTransform.java @@ -876,6 +876,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { * they have not been cached. * @see #getType */ + @SuppressWarnings("fallthrough") private void calculateType() { int ret = TYPE_IDENTITY; boolean sgn0, sgn1; @@ -1038,6 +1039,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { * @see #TYPE_UNIFORM_SCALE * @since 1.2 */ + @SuppressWarnings("fallthrough") public double getDeterminant() { switch (state) { default: @@ -1250,6 +1252,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { default: stateError(); /* NOTREACHED */ + return; case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): m02 = tx * m00 + ty * m01 + m02; m12 = tx * m10 + ty * m11 + m12; @@ -1631,6 +1634,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { * Y axis direction * @since 1.2 */ + @SuppressWarnings("fallthrough") public void scale(double sx, double sy) { int state = this.state; switch (state) { @@ -1705,6 +1709,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { default: stateError(); /* NOTREACHED */ + return; case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): case (APPLY_SHEAR | APPLY_SCALE): double M0, M1; @@ -2224,6 +2229,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { * @see #preConcatenate * @since 1.2 */ + @SuppressWarnings("fallthrough") public void concatenate(AffineTransform Tx) { double M0, M1; double T00, T01, T10, T11; @@ -2432,6 +2438,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { * @see #concatenate * @since 1.2 */ + @SuppressWarnings("fallthrough") public void preConcatenate(AffineTransform Tx) { double M0, M1; double T00, T01, T10, T11; @@ -2655,6 +2662,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { default: stateError(); /* NOTREACHED */ + return null; case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): det = m00 * m11 - m01 * m10; if (Math.abs(det) <= Double.MIN_VALUE) { @@ -2751,6 +2759,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { default: stateError(); /* NOTREACHED */ + return; case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): M00 = m00; M01 = m01; M02 = m02; M10 = m10; M11 = m11; M12 = m12; @@ -2885,6 +2894,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { default: stateError(); /* NOTREACHED */ + return null; case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): ptDst.setLocation(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12); @@ -2968,6 +2978,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { default: stateError(); /* NOTREACHED */ + return; case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): dst.setLocation(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12); @@ -3043,6 +3054,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { default: stateError(); /* NOTREACHED */ + return; case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): M00 = m00; M01 = m01; M02 = m02; M10 = m10; M11 = m11; M12 = m12; @@ -3157,6 +3169,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { default: stateError(); /* NOTREACHED */ + return; case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): M00 = m00; M01 = m01; M02 = m02; M10 = m10; M11 = m11; M12 = m12; @@ -3252,6 +3265,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { default: stateError(); /* NOTREACHED */ + return; case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): M00 = m00; M01 = m01; M02 = m02; M10 = m10; M11 = m11; M12 = m12; @@ -3347,6 +3361,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { default: stateError(); /* NOTREACHED */ + return; case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): M00 = m00; M01 = m01; M02 = m02; M10 = m10; M11 = m11; M12 = m12; @@ -3436,6 +3451,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { * inverted. * @since 1.2 */ + @SuppressWarnings("fallthrough") public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst) throws NoninvertibleTransformException { @@ -3547,6 +3563,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { default: stateError(); /* NOTREACHED */ + return; case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): M00 = m00; M01 = m01; M02 = m02; M10 = m10; M11 = m11; M12 = m12; @@ -3679,6 +3696,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { default: stateError(); /* NOTREACHED */ + return null; case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): case (APPLY_SHEAR | APPLY_SCALE): ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11); @@ -3754,6 +3772,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { default: stateError(); /* NOTREACHED */ + return; case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): case (APPLY_SHEAR | APPLY_SCALE): M00 = m00; M01 = m01; From 32091fcb1b4baa359b7adbef1b75d44ad4917d44 Mon Sep 17 00:00:00 2001 From: Mike Duigou <mduigou@openjdk.org> Date: Wed, 6 Mar 2013 08:37:27 -0800 Subject: [PATCH 142/180] 8009162: root repo "make test" target should run against image Reviewed-by: alanb, martin, erikj --- common/makefiles/Main.gmk | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/makefiles/Main.gmk b/common/makefiles/Main.gmk index c43f590707c..2be24af977b 100644 --- a/common/makefiles/Main.gmk +++ b/common/makefiles/Main.gmk @@ -184,9 +184,10 @@ bootcycle-images: @$(ECHO) Boot cycle build step 2: Building a new JDK image using previously built image @($(CD) $(SRC_ROOT)/common/makefiles && $(BUILD_LOG_WRAPPER) $(MAKE) SPEC=$(dir $(SPEC))bootcycle-spec.gmk images) -test: start-make +test: images test-only +test-only: start-make @$(call TargetEnter) - @($(CD) $(SRC_ROOT)/test && $(BUILD_LOG_WRAPPER) $(MAKE) -j1 -k MAKEFLAGS= PRODUCT_HOME=$(OUTPUT_ROOT)/jdk JPRT_JAVA_HOME=$(OUTPUT_ROOT)/jdk ALT_OUTPUTDIR=$(OUTPUT_ROOT) $(TEST)) || true + @($(CD) $(SRC_ROOT)/test && $(BUILD_LOG_WRAPPER) $(MAKE) -j1 -k MAKEFLAGS= PRODUCT_HOME=$(JDK_IMAGE_DIR) JPRT_JAVA_HOME=$(JDK_IMAGE_DIR) ALT_OUTPUTDIR=$(OUTPUT_ROOT) $(TEST)) || true @$(call TargetExit) # Stores the tips for each repository. This file is be used when constructing the jdk image and can be From a65f7e7df086db25709035716a0aedfab5f02184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Borggr=C3=A9n-Franck?= <jfranck@openjdk.org> Date: Wed, 6 Mar 2013 18:35:51 +0100 Subject: [PATCH 143/180] 8007808: Missing method: Executable.getAnnotatedReturnType() Reviewed-by: darcy, forax --- .../classes/java/lang/reflect/Constructor.java | 1 + .../classes/java/lang/reflect/Executable.java | 14 ++++++++++++++ .../share/classes/java/lang/reflect/Method.java | 1 + 3 files changed, 16 insertions(+) diff --git a/jdk/src/share/classes/java/lang/reflect/Constructor.java b/jdk/src/share/classes/java/lang/reflect/Constructor.java index bbfd1d5ab9d..bdbd7c30e20 100644 --- a/jdk/src/share/classes/java/lang/reflect/Constructor.java +++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java @@ -532,6 +532,7 @@ public final class Constructor<T> extends Executable { * {@inheritDoc} * @since 1.8 */ + @Override public AnnotatedType getAnnotatedReturnType() { return getAnnotatedReturnType0(getDeclaringClass()); } diff --git a/jdk/src/share/classes/java/lang/reflect/Executable.java b/jdk/src/share/classes/java/lang/reflect/Executable.java index 83b5e9c87a4..1a89968b175 100644 --- a/jdk/src/share/classes/java/lang/reflect/Executable.java +++ b/jdk/src/share/classes/java/lang/reflect/Executable.java @@ -476,6 +476,20 @@ public abstract class Executable extends AccessibleObject return declaredAnnotations; } + /** + * Returns an AnnotatedType object that represents the potentially + * annotated return type of the method/constructor represented by this + * Executable. + * + * If this Executable represents a constructor, the AnnotatedType object + * represents the type of the constructed object. + * + * If this Executable represents a method, the AnnotatedType object + * represents the use of a type to specify the return type of the method. + * + * @since 1.8 + */ + public abstract AnnotatedType getAnnotatedReturnType(); /* Helper for subclasses of Executable. * diff --git a/jdk/src/share/classes/java/lang/reflect/Method.java b/jdk/src/share/classes/java/lang/reflect/Method.java index 1507c77194a..30e764694d0 100644 --- a/jdk/src/share/classes/java/lang/reflect/Method.java +++ b/jdk/src/share/classes/java/lang/reflect/Method.java @@ -629,6 +629,7 @@ public final class Method extends Executable { * {@inheritDoc} * @since 1.8 */ + @Override public AnnotatedType getAnnotatedReturnType() { return getAnnotatedReturnType0(getGenericReturnType()); } From a6be16446db1fdea8b29b285a0eee9aabbdcb8a9 Mon Sep 17 00:00:00 2001 From: Joseph Provino <jprovino@openjdk.org> Date: Wed, 6 Mar 2013 13:38:17 -0500 Subject: [PATCH 144/180] 8008310: Some adjustments needed to minimal VM warnings and errors for unsupported command line options Changes to arguments.cpp for warnings vs. errors. Changes for CDS arguments. Reviewed-by: coleenp, cjplummer --- hotspot/make/excludeSrc.make | 2 +- hotspot/src/share/vm/memory/filemap.hpp | 15 ++++-- hotspot/src/share/vm/runtime/arguments.cpp | 55 +++++++++++++--------- 3 files changed, 46 insertions(+), 26 deletions(-) diff --git a/hotspot/make/excludeSrc.make b/hotspot/make/excludeSrc.make index b3c468f0455..1f044812352 100644 --- a/hotspot/make/excludeSrc.make +++ b/hotspot/make/excludeSrc.make @@ -69,7 +69,7 @@ ifeq ($(INCLUDE_CDS), false) CXXFLAGS += -DINCLUDE_CDS=0 CFLAGS += -DINCLUDE_CDS=0 - Src_Files_EXCLUDE += metaspaceShared.cpp + Src_Files_EXCLUDE += filemap.cpp metaspaceShared.cpp endif ifeq ($(INCLUDE_ALL_GCS), false) diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp index 75f01d0510a..a11914b9c01 100644 --- a/hotspot/src/share/vm/memory/filemap.hpp +++ b/hotspot/src/share/vm/memory/filemap.hpp @@ -112,12 +112,19 @@ public: char* region_base(int i) { return _header._space[i]._base; } struct FileMapHeader* header() { return &_header; } - static void set_current_info(FileMapInfo* info) { _current_info = info; } - static FileMapInfo* current_info() { return _current_info; } + static void set_current_info(FileMapInfo* info) { + CDS_ONLY(_current_info = info;) + } + + static FileMapInfo* current_info() { + CDS_ONLY(return _current_info;) + NOT_CDS(return NULL;) + } + static void assert_mark(bool check); // File manipulation. - bool initialize(); + bool initialize() NOT_CDS_RETURN_(false); bool open_for_read(); void open_for_write(); void write_header(); @@ -141,7 +148,7 @@ public: void fail_continue(const char *msg, ...); // Return true if given address is in the mapped shared space. - bool is_in_shared_space(const void* p); + bool is_in_shared_space(const void* p) NOT_CDS_RETURN_(false); }; #endif // SHARE_VM_MEMORY_FILEMAP_HPP diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index db634c621b3..554d6a75433 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -2273,10 +2273,12 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, } #if !INCLUDE_JVMTI if ((strcmp(name, "hprof") == 0) || (strcmp(name, "jdwp") == 0)) { - warning("profiling and debugging agents are not supported in this VM"); - } else + jio_fprintf(defaultStream::error_stream(), + "Profiling and debugging agents are not supported in this VM\n"); + return JNI_ERR; + } #endif // !INCLUDE_JVMTI - add_init_library(name, options); + add_init_library(name, options); } // -agentlib and -agentpath } else if (match_option(option, "-agentlib:", &tail) || @@ -2293,16 +2295,19 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, } #if !INCLUDE_JVMTI if ((strcmp(name, "hprof") == 0) || (strcmp(name, "jdwp") == 0)) { - warning("profiling and debugging agents are not supported in this VM"); - } else + jio_fprintf(defaultStream::error_stream(), + "Profiling and debugging agents are not supported in this VM\n"); + return JNI_ERR; + } #endif // !INCLUDE_JVMTI add_init_agent(name, options, is_absolute_path); - } // -javaagent } else if (match_option(option, "-javaagent:", &tail)) { #if !INCLUDE_JVMTI - warning("Instrumentation agents are not supported in this VM"); + jio_fprintf(defaultStream::error_stream(), + "Instrumentation agents are not supported in this VM\n"); + return JNI_ERR; #else if(tail != NULL) { char *options = strcpy(NEW_C_HEAP_ARRAY(char, strlen(tail) + 1, mtInternal), tail); @@ -2443,8 +2448,9 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, #if INCLUDE_FPROF _has_profile = true; #else // INCLUDE_FPROF - // do we have to exit? - warning("Flat profiling is not supported in this VM."); + jio_fprintf(defaultStream::error_stream(), + "Flat profiling is not supported in this VM.\n"); + return JNI_ERR; #endif // INCLUDE_FPROF // -Xaprof } else if (match_option(option, "-Xaprof", &tail)) { @@ -2478,8 +2484,9 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, #if INCLUDE_MANAGEMENT FLAG_SET_CMDLINE(bool, ManagementServer, true); #else - vm_exit_during_initialization( - "-Dcom.sun.management is not supported in this VM.", NULL); + jio_fprintf(defaultStream::output_stream(), + "-Dcom.sun.management is not supported in this VM.\n"); + return JNI_ERR; #endif } // -Xint @@ -2492,16 +2499,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, } else if (match_option(option, "-Xcomp", &tail)) { // for testing the compiler; turn off all flags that inhibit compilation set_mode_flags(_comp); - // -Xshare:dump } else if (match_option(option, "-Xshare:dump", &tail)) { -#if !INCLUDE_CDS - vm_exit_during_initialization( - "Dumping a shared archive is not supported in this VM.", NULL); -#else FLAG_SET_CMDLINE(bool, DumpSharedSpaces, true); set_mode_flags(_int); // Prevent compilation, which creates objects -#endif // -Xshare:on } else if (match_option(option, "-Xshare:on", &tail)) { FLAG_SET_CMDLINE(bool, UseSharedSpaces, true); @@ -2514,7 +2515,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, } else if (match_option(option, "-Xshare:off", &tail)) { FLAG_SET_CMDLINE(bool, UseSharedSpaces, false); FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false); - // -Xverify } else if (match_option(option, "-Xverify", &tail)) { if (strcmp(tail, ":all") == 0 || strcmp(tail, "") == 0) { @@ -2828,8 +2828,9 @@ SOLARIS_ONLY( FLAG_SET_CMDLINE(bool, UseVMInterruptibleIO, true); #if !INCLUDE_MANAGEMENT } else if (match_option(option, "-XX:+ManagementServer", &tail)) { - vm_exit_during_initialization( - "ManagementServer is not supported in this VM.", NULL); + jio_fprintf(defaultStream::error_stream(), + "ManagementServer is not supported in this VM.\n"); + return JNI_ERR; #endif // INCLUDE_MANAGEMENT } else if (match_option(option, "-XX:", &tail)) { // -XX:xxxx // Skip -XX:Flags= since that case has already been handled @@ -3135,7 +3136,9 @@ jint Arguments::parse(const JavaVMInitArgs* args) { #if INCLUDE_NMT MemTracker::init_tracking_options(tail); #else - warning("Native Memory Tracking is not supported in this VM"); + jio_fprintf(defaultStream::error_stream(), + "Native Memory Tracking is not supported in this VM\n"); + return JNI_ERR; #endif } @@ -3254,6 +3257,16 @@ jint Arguments::parse(const JavaVMInitArgs* args) { force_serial_gc(); #endif // INCLUDE_ALL_GCS #if !INCLUDE_CDS + if (DumpSharedSpaces || RequireSharedSpaces) { + jio_fprintf(defaultStream::error_stream(), + "Shared spaces are not supported in this VM\n"); + return JNI_ERR; + } + if (UseSharedSpaces || PrintSharedSpaces) { + warning("Shared spaces are not supported in this VM"); + FLAG_SET_DEFAULT(UseSharedSpaces, false); + FLAG_SET_DEFAULT(PrintSharedSpaces, false); + } no_shared_spaces(); #endif // INCLUDE_CDS From e1f180f82e29f200c86cb545e3fcfc328fa7e843 Mon Sep 17 00:00:00 2001 From: Joseph Provino <jprovino@openjdk.org> Date: Wed, 6 Mar 2013 13:46:55 -0500 Subject: [PATCH 145/180] 8006498: #if <symbol> is wrong in the code ASSERT and other symbols used incorrectly with #if are supposed to be defined or not. Reviewed-by: dholmes, mikael --- hotspot/src/cpu/x86/vm/frame_x86.cpp | 2 +- hotspot/src/cpu/x86/vm/frame_x86.hpp | 2 +- hotspot/src/share/vm/c1/c1_LIR.hpp | 2 +- hotspot/src/share/vm/ci/ciTypeFlow.cpp | 2 +- hotspot/src/share/vm/code/compressedStream.cpp | 4 ++-- .../vm/gc_implementation/g1/concurrentMark.cpp | 16 ---------------- hotspot/src/share/vm/prims/jvmtiImpl.cpp | 2 +- hotspot/src/share/vm/prims/jvmtiTrace.hpp | 4 ++-- 8 files changed, 9 insertions(+), 25 deletions(-) diff --git a/hotspot/src/cpu/x86/vm/frame_x86.cpp b/hotspot/src/cpu/x86/vm/frame_x86.cpp index fa0855c458c..93180c8e37d 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.cpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp @@ -356,7 +356,7 @@ frame frame::sender_for_entry_frame(RegisterMap* map) const { // Verifies the calculated original PC of a deoptimization PC for the // given unextended SP. The unextended SP might also be the saved SP // for MethodHandle call sites. -#if ASSERT +#ifdef ASSERT void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) { frame fr; diff --git a/hotspot/src/cpu/x86/vm/frame_x86.hpp b/hotspot/src/cpu/x86/vm/frame_x86.hpp index b3c3f416c46..0033077dde4 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.hpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.hpp @@ -170,7 +170,7 @@ return (intptr_t*) addr_at(offset); } -#if ASSERT +#ifdef ASSERT // Used in frame::sender_for_{interpreter,compiled}_frame static void verify_deopt_original_pc( nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false); static void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) { diff --git a/hotspot/src/share/vm/c1/c1_LIR.hpp b/hotspot/src/share/vm/c1/c1_LIR.hpp index cec92f78c27..72051f19f34 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.hpp +++ b/hotspot/src/share/vm/c1/c1_LIR.hpp @@ -2375,7 +2375,7 @@ class LIR_OpVisitState: public StackObj { // collects all register operands of the instruction void visit(LIR_Op* op); -#if ASSERT +#ifdef ASSERT // check that an operation has no operands bool no_operands(LIR_Op* op); #endif diff --git a/hotspot/src/share/vm/ci/ciTypeFlow.cpp b/hotspot/src/share/vm/ci/ciTypeFlow.cpp index bdbeeaf933e..b76dd3d0fe3 100644 --- a/hotspot/src/share/vm/ci/ciTypeFlow.cpp +++ b/hotspot/src/share/vm/ci/ciTypeFlow.cpp @@ -2540,7 +2540,7 @@ void ciTypeFlow::build_loop_tree(Block* blk) { } else if (innermost->head() == blk) { // If loop header, complete the tree pointers if (blk->loop() != innermost) { -#if ASSERT +#ifdef ASSERT assert(blk->loop()->head() == innermost->head(), "same head"); Loop* dl; for (dl = innermost; dl != NULL && dl != blk->loop(); dl = dl->parent()); diff --git a/hotspot/src/share/vm/code/compressedStream.cpp b/hotspot/src/share/vm/code/compressedStream.cpp index 1d5cb341372..82b05fc03f9 100644 --- a/hotspot/src/share/vm/code/compressedStream.cpp +++ b/hotspot/src/share/vm/code/compressedStream.cpp @@ -195,7 +195,7 @@ void CompressedWriteStream::write_int_mb(jint value) { // for this block (a matching directive turns it back on later). // These directives can be removed once the MS VS.NET 2005 // compiler stack overflow is fixed. -#if _MSC_VER >=1400 && !defined(_WIN64) +#if defined(_MSC_VER) && _MSC_VER >=1400 && !defined(_WIN64) #pragma optimize("", off) #pragma warning(disable: 4748) #endif @@ -276,7 +276,7 @@ void test_compressed_stream(int trace) { guarantee(fails == 0, "test failures"); } -#if _MSC_VER >=1400 && !defined(_WIN64) +#if defined(_MSC_VER) &&_MSC_VER >=1400 && !defined(_WIN64) #pragma warning(default: 4748) #pragma optimize("", on) #endif diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index cc2a611f0f0..b6a8cac6f53 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -1310,11 +1310,6 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { _markStack.expand(); } -#if VERIFY_OBJS_PROCESSED - _scan_obj_cl.objs_processed = 0; - ThreadLocalObjQueue::objs_enqueued = 0; -#endif - // Statistics double now = os::elapsedTime(); _remark_mark_times.add((mark_work_end - start) * 1000.0); @@ -2555,17 +2550,6 @@ void ConcurrentMark::checkpointRootsFinalWork() { guarantee(satb_mq_set.completed_buffers_num() == 0, "invariant"); print_stats(); - -#if VERIFY_OBJS_PROCESSED - if (_scan_obj_cl.objs_processed != ThreadLocalObjQueue::objs_enqueued) { - gclog_or_tty->print_cr("Processed = %d, enqueued = %d.", - _scan_obj_cl.objs_processed, - ThreadLocalObjQueue::objs_enqueued); - guarantee(_scan_obj_cl.objs_processed == - ThreadLocalObjQueue::objs_enqueued, - "Different number of objs processed and enqueued."); - } -#endif } #ifndef PRODUCT diff --git a/hotspot/src/share/vm/prims/jvmtiImpl.cpp b/hotspot/src/share/vm/prims/jvmtiImpl.cpp index 4a1747e1bd2..c569b8fdcb4 100644 --- a/hotspot/src/share/vm/prims/jvmtiImpl.cpp +++ b/hotspot/src/share/vm/prims/jvmtiImpl.cpp @@ -890,7 +890,7 @@ void JvmtiSuspendControl::print() { tty->print("Suspended Threads: ["); for (JavaThread *thread = Threads::first(); thread != NULL; thread = thread->next()) { -#if JVMTI_TRACE +#ifdef JVMTI_TRACE const char *name = JvmtiTrace::safe_get_thread_name(thread); #else const char *name = ""; diff --git a/hotspot/src/share/vm/prims/jvmtiTrace.hpp b/hotspot/src/share/vm/prims/jvmtiTrace.hpp index b6d42249776..6be50d8ade8 100644 --- a/hotspot/src/share/vm/prims/jvmtiTrace.hpp +++ b/hotspot/src/share/vm/prims/jvmtiTrace.hpp @@ -43,10 +43,10 @@ // Support tracing except in product build on the client compiler #ifndef PRODUCT -#define JVMTI_TRACE 1 +#define JVMTI_TRACE #else #ifdef COMPILER2 -#define JVMTI_TRACE 1 +#define JVMTI_TRACE #endif #endif From 94853afaeedcf2eeaf4b49112d05492902c5baba Mon Sep 17 00:00:00 2001 From: Joseph Provino <jprovino@openjdk.org> Date: Wed, 6 Mar 2013 13:50:54 -0500 Subject: [PATCH 146/180] 8008474: Add -Wundef to warning flags Force use of undefined macros to be and error. Reviewed-by: dholmes, mikael --- hotspot/make/bsd/makefiles/gcc.make | 6 +++--- hotspot/make/linux/makefiles/gcc.make | 6 +++--- hotspot/make/solaris/makefiles/gcc.make | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hotspot/make/bsd/makefiles/gcc.make b/hotspot/make/bsd/makefiles/gcc.make index 2cee1b0034e..b742eb12992 100644 --- a/hotspot/make/bsd/makefiles/gcc.make +++ b/hotspot/make/bsd/makefiles/gcc.make @@ -168,12 +168,12 @@ endif # conversions which might affect the values. To avoid that, we need to turn # it off explicitly. ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" -ACCEPTABLE_WARNINGS = -Wpointer-arith -Wsign-compare +WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef else -ACCEPTABLE_WARNINGS = -Wpointer-arith -Wconversion -Wsign-compare +WARNING_FLAGS = -Wpointer-arith -Wconversion -Wsign-compare -Wundef endif -CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(ACCEPTABLE_WARNINGS) +CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(WARNING_FLAGS) # Special cases CFLAGS_WARN/BYFILE = $(CFLAGS_WARN/$@)$(CFLAGS_WARN/DEFAULT$(CFLAGS_WARN/$@)) # XXXDARWIN: for _dyld_bind_fully_image_containing_address diff --git a/hotspot/make/linux/makefiles/gcc.make b/hotspot/make/linux/makefiles/gcc.make index 9ef83664535..b2c4bdfa491 100644 --- a/hotspot/make/linux/makefiles/gcc.make +++ b/hotspot/make/linux/makefiles/gcc.make @@ -131,12 +131,12 @@ WARNINGS_ARE_ERRORS = -Werror # conversions which might affect the values. To avoid that, we need to turn # it off explicitly. ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" -ACCEPTABLE_WARNINGS = -Wpointer-arith -Wsign-compare +WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef else -ACCEPTABLE_WARNINGS = -Wpointer-arith -Wconversion -Wsign-compare +WARNING_FLAGS = -Wpointer-arith -Wconversion -Wsign-compare -Wundef endif -CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(ACCEPTABLE_WARNINGS) +CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(WARNING_FLAGS) # Special cases CFLAGS_WARN/BYFILE = $(CFLAGS_WARN/$@)$(CFLAGS_WARN/DEFAULT$(CFLAGS_WARN/$@)) diff --git a/hotspot/make/solaris/makefiles/gcc.make b/hotspot/make/solaris/makefiles/gcc.make index 66ab8c55d6a..e946d65d256 100644 --- a/hotspot/make/solaris/makefiles/gcc.make +++ b/hotspot/make/solaris/makefiles/gcc.make @@ -118,8 +118,8 @@ endif # Compiler warnings are treated as errors WARNINGS_ARE_ERRORS = -Werror # Enable these warnings. See 'info gcc' about details on these options -ADDITIONAL_WARNINGS = -Wpointer-arith -Wconversion -Wsign-compare -CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(ADDITIONAL_WARNINGS) +WARNING_FLAGS = -Wpointer-arith -Wconversion -Wsign-compare -Wundef +CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(WARNING_FLAGS) # Special cases CFLAGS_WARN/BYFILE = $(CFLAGS_WARN/$@)$(CFLAGS_WARN/DEFAULT$(CFLAGS_WARN/$@)) From 46b80b3416753c63a170c53f2f1b98de6d3e4bd7 Mon Sep 17 00:00:00 2001 From: Martin Buchholz <martin@openjdk.org> Date: Wed, 6 Mar 2013 17:43:10 -0800 Subject: [PATCH 147/180] 8008759: Do not let internal JDK zlib symbols leak out of fastdebug libzip.so Define FILES_m to force use of linker script Reviewed-by: sherman, alanb, ohair --- jdk/make/java/zip/Makefile | 10 ++++++++++ jdk/src/share/native/java/util/zip/Inflater.c | 16 ++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/jdk/make/java/zip/Makefile b/jdk/make/java/zip/Makefile index 67a8557de0b..99afd603d7c 100644 --- a/jdk/make/java/zip/Makefile +++ b/jdk/make/java/zip/Makefile @@ -68,6 +68,16 @@ ifeq ($(PLATFORM), solaris) FILES_reorder += reorder-$(ARCH) endif endif + +# +# Use mapfile unconditionally (even with fastdebug). +# JDK's internal zlib is incompatible with stock zlib, because the +# size of struct z_stream has been changed, so internal zlib +# implementation must not be allowed to leak outside of libzip.so, +# else you get hard to debug failures with fastdebug jdk when user +# native code includes stock zlib. +# +FILES_m = mapfile-vers include $(BUILDDIR)/common/Mapfile-vers.gmk include $(BUILDDIR)/common/Library.gmk diff --git a/jdk/src/share/native/java/util/zip/Inflater.c b/jdk/src/share/native/java/util/zip/Inflater.c index b67fff24f09..3778ff4e40c 100644 --- a/jdk/src/share/native/java/util/zip/Inflater.c +++ b/jdk/src/share/native/java/util/zip/Inflater.c @@ -27,6 +27,7 @@ * Native method support for java.util.zip.Inflater */ +#include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> @@ -60,12 +61,13 @@ Java_java_util_zip_Inflater_init(JNIEnv *env, jclass cls, jboolean nowrap) { z_stream *strm = calloc(1, sizeof(z_stream)); - if (strm == 0) { + if (strm == NULL) { JNU_ThrowOutOfMemoryError(env, 0); return jlong_zero; } else { - char *msg; - switch (inflateInit2(strm, nowrap ? -MAX_WBITS : MAX_WBITS)) { + const char *msg; + int ret = inflateInit2(strm, nowrap ? -MAX_WBITS : MAX_WBITS); + switch (ret) { case Z_OK: return ptr_to_jlong(strm); case Z_MEM_ERROR: @@ -73,7 +75,13 @@ Java_java_util_zip_Inflater_init(JNIEnv *env, jclass cls, jboolean nowrap) JNU_ThrowOutOfMemoryError(env, 0); return jlong_zero; default: - msg = strm->msg; + msg = ((strm->msg != NULL) ? strm->msg : + (ret == Z_VERSION_ERROR) ? + "zlib returned Z_VERSION_ERROR: " + "compile time and runtime zlib implementations differ" : + (ret == Z_STREAM_ERROR) ? + "inflateInit2 returned Z_STREAM_ERROR" : + "unknown error initializing zlib library"); free(strm); JNU_ThrowInternalError(env, msg); return jlong_zero; From 556ff23124bf2725e2466d4b40b9694c261ee7b8 Mon Sep 17 00:00:00 2001 From: Weijun Wang <weijun@openjdk.org> Date: Thu, 7 Mar 2013 11:32:14 +0800 Subject: [PATCH 148/180] 8009604: old make images failed: JarBASE64Encoder class not found Reviewed-by: xuelei, wetmore --- jdk/make/common/Release.gmk | 2 -- 1 file changed, 2 deletions(-) diff --git a/jdk/make/common/Release.gmk b/jdk/make/common/Release.gmk index 70033e457d0..5371d044b91 100644 --- a/jdk/make/common/Release.gmk +++ b/jdk/make/common/Release.gmk @@ -348,7 +348,6 @@ TOOLS = \ sun/tools/serialver \ sun/tools/tree \ sun/tools/util \ - sun/security/tools/jarsigner/JarBASE64Encoder.class \ sun/security/tools/jarsigner/Main.class \ sun/security/tools/jarsigner/JarSignerParameters.class \ sun/security/tools/jarsigner/Resources.class \ @@ -576,7 +575,6 @@ $(NOT_RT_JAR_LIST): FRC $(ECHO) "sun/tools/serialver/" >> $@ $(ECHO) "sun/tools/tree/" >> $@ $(ECHO) "sun/tools/util/" >> $@ - $(ECHO) "sun/security/tools/jarsigner/JarBASE64Encoder.class" >> $@ $(ECHO) "sun/security/tools/jarsigner/Main.class" >> $@ $(ECHO) "sun/security/tools/jarsigner/JarSignerParameters.class" >> $@ $(ECHO) "sun/security/tools/jarsigner/Resources.class" >> $@ From 6c0e4804276fd48c5ffab5c1330be3b234360727 Mon Sep 17 00:00:00 2001 From: Andrew Brygin <bae@openjdk.org> Date: Thu, 7 Mar 2013 14:05:21 +0400 Subject: [PATCH 149/180] 8005530: [lcms] Improve performance of ColorConverOp for default destinations Reviewed-by: prr, jgodinez --- jdk/make/sun/cmm/lcms/Makefile | 3 + jdk/make/sun/cmm/lcms/mapfile-vers | 9 +- jdk/makefiles/CompileNativeLibraries.gmk | 2 +- jdk/makefiles/mapfiles/liblcms/mapfile-vers | 9 +- .../classes/sun/java2d/cmm/lcms/LCMS.java | 137 +++++++- .../sun/java2d/cmm/lcms/LCMSImageLayout.java | 295 ++++++++++++------ .../sun/java2d/cmm/lcms/LCMSTransform.java | 25 +- jdk/src/share/demo/java2d/J2DBench/build.xml | 12 +- .../resources/cmm_images/img_icc_large.jpg | Bin 0 -> 430301 bytes .../resources/cmm_images/img_icc_medium.jpg | Bin 0 -> 148164 bytes .../resources/cmm_images/img_icc_small.jpg | Bin 0 -> 16258 bytes .../tests/cmm/ColorConversionTests.java | 1 + .../tests/cmm/EmbeddedProfileTests.java | 166 ++++++++++ .../share/native/sun/java2d/cmm/lcms/LCMS.c | 95 +++--- 14 files changed, 572 insertions(+), 182 deletions(-) create mode 100644 jdk/src/share/demo/java2d/J2DBench/resources/cmm_images/img_icc_large.jpg create mode 100644 jdk/src/share/demo/java2d/J2DBench/resources/cmm_images/img_icc_medium.jpg create mode 100644 jdk/src/share/demo/java2d/J2DBench/resources/cmm_images/img_icc_small.jpg create mode 100644 jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/EmbeddedProfileTests.java diff --git a/jdk/make/sun/cmm/lcms/Makefile b/jdk/make/sun/cmm/lcms/Makefile index 24fde37fba0..85b02e4960e 100644 --- a/jdk/make/sun/cmm/lcms/Makefile +++ b/jdk/make/sun/cmm/lcms/Makefile @@ -28,6 +28,9 @@ PACKAGE = sun.java2d.cmm.lcms LIBRARY = lcms PRODUCT = sun +# Use highest level of optimization on this library +OPTIMIZATION_LEVEL = HIGHEST + include $(BUILDDIR)/common/Defs.gmk # diff --git a/jdk/make/sun/cmm/lcms/mapfile-vers b/jdk/make/sun/cmm/lcms/mapfile-vers index ac4e7458b37..3d9074f746d 100644 --- a/jdk/make/sun/cmm/lcms/mapfile-vers +++ b/jdk/make/sun/cmm/lcms/mapfile-vers @@ -27,13 +27,12 @@ SUNWprivate_1.1 { global: - Java_sun_java2d_cmm_lcms_LCMS_loadProfile; - Java_sun_java2d_cmm_lcms_LCMS_freeProfile; + Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative; + Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative; Java_sun_java2d_cmm_lcms_LCMS_getProfileSize; Java_sun_java2d_cmm_lcms_LCMS_getProfileData; - Java_sun_java2d_cmm_lcms_LCMS_getTagSize; - Java_sun_java2d_cmm_lcms_LCMS_getTagData; - Java_sun_java2d_cmm_lcms_LCMS_setTagData; + Java_sun_java2d_cmm_lcms_LCMS_getTagNative; + Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative; Java_sun_java2d_cmm_lcms_LCMS_colorConvert; Java_sun_java2d_cmm_lcms_LCMS_getProfileID; Java_sun_java2d_cmm_lcms_LCMS_initLCMS; diff --git a/jdk/makefiles/CompileNativeLibraries.gmk b/jdk/makefiles/CompileNativeLibraries.gmk index 01dbc2ba417..46f1778a5fc 100644 --- a/jdk/makefiles/CompileNativeLibraries.gmk +++ b/jdk/makefiles/CompileNativeLibraries.gmk @@ -1218,7 +1218,7 @@ ifdef OPENJDK OUTPUT_DIR:=$(INSTALL_LIBRARIES_HERE),\ SRC:=$(JDK_TOPDIR)/src/share/native/sun/java2d/cmm/lcms,\ LANG:=C,\ - OPTIMIZATION:=LOW, \ + OPTIMIZATION:=HIGHEST, \ CFLAGS:=$(filter-out -xc99=%none,$(CFLAGS_JDKLIB)) \ $(SHARED_LIBRARY_FLAGS) \ -I$(JDK_TOPDIR)/src/share/native/sun/java2d \ diff --git a/jdk/makefiles/mapfiles/liblcms/mapfile-vers b/jdk/makefiles/mapfiles/liblcms/mapfile-vers index 04703dffc5a..024511423d3 100644 --- a/jdk/makefiles/mapfiles/liblcms/mapfile-vers +++ b/jdk/makefiles/mapfiles/liblcms/mapfile-vers @@ -27,13 +27,12 @@ SUNWprivate_1.1 { global: - Java_sun_java2d_cmm_lcms_LCMS_loadProfile; - Java_sun_java2d_cmm_lcms_LCMS_freeProfile; + Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative; + Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative; Java_sun_java2d_cmm_lcms_LCMS_getProfileSize; Java_sun_java2d_cmm_lcms_LCMS_getProfileData; - Java_sun_java2d_cmm_lcms_LCMS_getTagSize; - Java_sun_java2d_cmm_lcms_LCMS_getTagData; - Java_sun_java2d_cmm_lcms_LCMS_setTagData; + Java_sun_java2d_cmm_lcms_LCMS_getTagNative; + Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative; Java_sun_java2d_cmm_lcms_LCMS_colorConvert; Java_sun_java2d_cmm_lcms_LCMS_getProfileID; Java_sun_java2d_cmm_lcms_LCMS_initLCMS; diff --git a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java index 5cfda3cdb74..c6eae65a73a 100644 --- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java +++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java @@ -25,29 +25,91 @@ package sun.java2d.cmm.lcms; -import java.awt.color.ColorSpace; import java.awt.color.ICC_Profile; -import java.awt.color.CMMException; +import java.util.Arrays; +import java.util.HashMap; import sun.java2d.cmm.ColorTransform; import sun.java2d.cmm.PCMM; -import sun.java2d.cmm.lcms.LCMS; -import sun.java2d.cmm.lcms.LCMSTransform; public class LCMS implements PCMM { /* methods invoked from ICC_Profile */ - public native long loadProfile(byte[] data); + @Override + public long loadProfile(byte[] data) { + long id = loadProfileNative(data); - public native void freeProfile(long profileID); + if (id != 0L) { + if (profiles == null) { + profiles = new HashMap<>(); + } + profiles.put(id, new TagCache(id)); + } + return id; + } + + private native long loadProfileNative(byte[] data); + + @Override + public void freeProfile(long profileID) { + TagCache c = profiles.remove(profileID); + if (c != null) { + c.clear(); + } + if (profiles.isEmpty()) { + profiles = null; + } + freeProfileNative(profileID); + } + + private native void freeProfileNative(long profileID); public native synchronized int getProfileSize(long profileID); public native synchronized void getProfileData(long profileID, byte[] data); - public native synchronized int getTagSize(long profileID, int tagSignature); - public native synchronized void getTagData(long profileID, int tagSignature, - byte[] data); - public native synchronized void setTagData(long profileID, int tagSignature, + @Override + public synchronized int getTagSize(long profileID, int tagSignature) { + TagCache cache = profiles.get(profileID); + + if (cache == null) { + cache = new TagCache(profileID); + profiles.put(profileID, cache); + } + + TagData t = cache.getTag(tagSignature); + return t == null ? 0 : t.getSize(); + } + + private static native byte[] getTagNative(long profileID, int signature); + + @Override + public synchronized void getTagData(long profileID, int tagSignature, + byte[] data) + { + TagCache cache = profiles.get(profileID); + + if (cache == null) { + cache = new TagCache(profileID); + profiles.put(profileID, cache); + } + + TagData t = cache.getTag(tagSignature); + if (t != null) { + t.copyDataTo(data); + } + } + + @Override + public synchronized void setTagData(long profileID, int tagSignature, byte[] data) { + TagCache cache = profiles.get(profileID); + + if (cache != null) { + cache.clear(); + } + setTagDataNative(profileID, tagSignature, data); + } + + private native synchronized void setTagDataNative(long profileID, int tagSignature, byte[] data); public static native long getProfileID(ICC_Profile profile); @@ -103,4 +165,59 @@ public class LCMS implements PCMM { initLCMS(LCMSTransform.class, LCMSImageLayout.class, ICC_Profile.class); } + + private static class TagData { + private int signature; + private byte[] data; + + TagData(int sig, byte[] data) { + this.signature = sig; + this.data = data; + } + + int getSize() { + return data.length; + } + + byte[] getData() { + return Arrays.copyOf(data, data.length); + } + + void copyDataTo(byte[] dst) { + System.arraycopy(data, 0, dst, 0, data.length); + } + + int getSignature() { + return signature; + } + } + + private static class TagCache { + private long profileID; + private HashMap<Integer, TagData> tags; + + TagCache(long id) { + profileID = id; + + tags = new HashMap<>(); + } + + TagData getTag(int sig) { + TagData t = tags.get(sig); + if (t == null) { + byte[] tagData = getTagNative(profileID, sig); + if (tagData != null) { + t = new TagData(sig, tagData); + tags.put(sig, t); + } + } + return t; + } + + void clear() { + tags.clear(); + } + } + + private static HashMap<Long, TagCache> profiles; } diff --git a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java index 3695a163211..b53bd9a45d3 100644 --- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java +++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java @@ -22,26 +22,19 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package sun.java2d.cmm.lcms; -import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.awt.image.ComponentColorModel; -import java.awt.image.Raster; -import java.awt.image.WritableRaster; -import java.awt.image.SinglePixelPackedSampleModel; import java.awt.image.ComponentSampleModel; import java.awt.image.DataBuffer; -import java.awt.image.DataBufferByte; -import java.awt.image.DataBufferUShort; -import java.awt.image.DataBufferInt; import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.SampleModel; import sun.awt.image.ByteComponentRaster; import sun.awt.image.ShortComponentRaster; import sun.awt.image.IntegerComponentRaster; - class LCMSImageLayout { public static int BYTES_SH(int x) { @@ -49,47 +42,34 @@ class LCMSImageLayout { } public static int EXTRA_SH(int x) { - return x<<7; + return x << 7; } public static int CHANNELS_SH(int x) { - return x<<3; + return x << 3; } - - public static final int SWAPFIRST = 1<<14; - - public static final int DOSWAP = 1<<10; - + public static final int SWAPFIRST = 1 << 14; + public static final int DOSWAP = 1 << 10; public static final int PT_RGB_8 = - CHANNELS_SH(3) | BYTES_SH(1); - + CHANNELS_SH(3) | BYTES_SH(1); public static final int PT_GRAY_8 = - CHANNELS_SH(1) | BYTES_SH(1); - + CHANNELS_SH(1) | BYTES_SH(1); public static final int PT_GRAY_16 = - CHANNELS_SH(1) | BYTES_SH(2); - + CHANNELS_SH(1) | BYTES_SH(2); public static final int PT_RGBA_8 = - EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1); - + EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1); public static final int PT_ARGB_8 = - EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1) | SWAPFIRST; - + EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1) | SWAPFIRST; public static final int PT_BGR_8 = - DOSWAP | CHANNELS_SH(3) | BYTES_SH(1); - + DOSWAP | CHANNELS_SH(3) | BYTES_SH(1); public static final int PT_ABGR_8 = - DOSWAP | EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1); - - public static final int PT_BGRA_8 = EXTRA_SH(1) | CHANNELS_SH(3) | - BYTES_SH(1) | DOSWAP | SWAPFIRST; - - public static final int DT_BYTE = 0; - public static final int DT_SHORT = 1; - public static final int DT_INT = 2; - public static final int DT_DOUBLE = 3; - - + DOSWAP | EXTRA_SH(1) | CHANNELS_SH(3) | BYTES_SH(1); + public static final int PT_BGRA_8 = EXTRA_SH(1) | CHANNELS_SH(3) + | BYTES_SH(1) | DOSWAP | SWAPFIRST; + public static final int DT_BYTE = 0; + public static final int DT_SHORT = 1; + public static final int DT_INT = 2; + public static final int DT_DOUBLE = 3; boolean isIntPacked = false; int pixelType; int dataType; @@ -98,25 +78,30 @@ class LCMSImageLayout { int nextRowOffset; int offset; + /* This flag indicates whether the image can be processed + * at once by doTransfrom() native call. Otherwise, the + * image is processed scan by scan. + */ + private boolean imageAtOnce = false; Object dataArray; + private LCMSImageLayout(int np, int pixelType, int pixelSize) { this.pixelType = pixelType; width = np; height = 1; - nextRowOffset = np*pixelSize; + nextRowOffset = np * pixelSize; offset = 0; } private LCMSImageLayout(int width, int height, int pixelType, - int pixelSize) { + int pixelSize) { this.pixelType = pixelType; this.width = width; this.height = height; - nextRowOffset = width*pixelSize; + nextRowOffset = width * pixelSize; offset = 0; } - public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) { this(np, pixelType, pixelSize); dataType = DT_BYTE; @@ -135,102 +120,218 @@ class LCMSImageLayout { dataArray = data; } - public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize) - { + public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize) { this(np, pixelType, pixelSize); dataType = DT_DOUBLE; dataArray = data; } - public LCMSImageLayout(BufferedImage image) { - ShortComponentRaster shortRaster; - IntegerComponentRaster intRaster; - ByteComponentRaster byteRaster; + private LCMSImageLayout() { + } + + /* This method creates a layout object for given image. + * Returns null if the image is not supported by current implementation. + */ + public static LCMSImageLayout createImageLayout(BufferedImage image) { + LCMSImageLayout l = new LCMSImageLayout(); + switch (image.getType()) { case BufferedImage.TYPE_INT_RGB: - pixelType = PT_ARGB_8; - isIntPacked = true; + l.pixelType = PT_ARGB_8; + l.isIntPacked = true; break; case BufferedImage.TYPE_INT_ARGB: - pixelType = PT_ARGB_8; - isIntPacked = true; + l.pixelType = PT_ARGB_8; + l.isIntPacked = true; break; case BufferedImage.TYPE_INT_BGR: - pixelType = PT_ABGR_8; - isIntPacked = true; + l.pixelType = PT_ABGR_8; + l.isIntPacked = true; break; case BufferedImage.TYPE_3BYTE_BGR: - pixelType = PT_BGR_8; + l.pixelType = PT_BGR_8; break; case BufferedImage.TYPE_4BYTE_ABGR: - pixelType = PT_ABGR_8; + l.pixelType = PT_ABGR_8; break; case BufferedImage.TYPE_BYTE_GRAY: - pixelType = PT_GRAY_8; + l.pixelType = PT_GRAY_8; break; case BufferedImage.TYPE_USHORT_GRAY: - pixelType = PT_GRAY_16; + l.pixelType = PT_GRAY_16; break; default: - // TODO: Add support for some images having - // SinglePixelPackedModel and ComponentSampleModel - throw new IllegalArgumentException( - "CMMImageLayout - bad image type passed to constructor"); + /* ColorConvertOp creates component images as + * default destination, so this kind of images + * has to be supported. + */ + ColorModel cm = image.getColorModel(); + if (cm instanceof ComponentColorModel) { + ComponentColorModel ccm = (ComponentColorModel) cm; + + // verify whether the component size is fine + int[] cs = ccm.getComponentSize(); + for (int s : cs) { + if (s != 8) { + return null; + } + } + + return createImageLayout(image.getRaster()); + + } + return null; } - width = image.getWidth(); - height = image.getHeight(); + l.width = image.getWidth(); + l.height = image.getHeight(); switch (image.getType()) { case BufferedImage.TYPE_INT_RGB: case BufferedImage.TYPE_INT_ARGB: case BufferedImage.TYPE_INT_BGR: - intRaster = (IntegerComponentRaster)image.getRaster(); - nextRowOffset = intRaster.getScanlineStride()*4; - offset = intRaster.getDataOffset(0)*4; - dataArray = intRaster.getDataStorage(); - dataType = DT_INT; + do { + IntegerComponentRaster intRaster = (IntegerComponentRaster) + image.getRaster(); + l.nextRowOffset = intRaster.getScanlineStride() * 4; + l.offset = intRaster.getDataOffset(0) * 4; + l.dataArray = intRaster.getDataStorage(); + l.dataType = DT_INT; + + if (l.nextRowOffset == l.width * 4 * intRaster.getPixelStride()) { + l.imageAtOnce = true; + } + } while (false); break; case BufferedImage.TYPE_3BYTE_BGR: case BufferedImage.TYPE_4BYTE_ABGR: - byteRaster = (ByteComponentRaster)image.getRaster(); - nextRowOffset = byteRaster.getScanlineStride(); - int firstBand = image.getSampleModel().getNumBands() - 1; - offset = byteRaster.getDataOffset(firstBand); - dataArray = byteRaster.getDataStorage(); - dataType = DT_BYTE; + do { + ByteComponentRaster byteRaster = (ByteComponentRaster) + image.getRaster(); + l.nextRowOffset = byteRaster.getScanlineStride(); + int firstBand = image.getSampleModel().getNumBands() - 1; + l.offset = byteRaster.getDataOffset(firstBand); + l.dataArray = byteRaster.getDataStorage(); + l.dataType = DT_BYTE; + if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) { + l.imageAtOnce = true; + } + } while (false); break; case BufferedImage.TYPE_BYTE_GRAY: - byteRaster = (ByteComponentRaster)image.getRaster(); - nextRowOffset = byteRaster.getScanlineStride(); - offset = byteRaster.getDataOffset(0); - dataArray = byteRaster.getDataStorage(); - dataType = DT_BYTE; + do { + ByteComponentRaster byteRaster = (ByteComponentRaster) + image.getRaster(); + l.nextRowOffset = byteRaster.getScanlineStride(); + l.offset = byteRaster.getDataOffset(0); + l.dataArray = byteRaster.getDataStorage(); + l.dataType = DT_BYTE; + + if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) { + l.imageAtOnce = true; + } + } while (false); break; case BufferedImage.TYPE_USHORT_GRAY: - shortRaster = (ShortComponentRaster)image.getRaster(); - nextRowOffset = shortRaster.getScanlineStride()*2; - offset = shortRaster.getDataOffset(0) * 2; - dataArray = shortRaster.getDataStorage(); - dataType = DT_SHORT; + do { + ShortComponentRaster shortRaster = (ShortComponentRaster) + image.getRaster(); + l.nextRowOffset = shortRaster.getScanlineStride() * 2; + l.offset = shortRaster.getDataOffset(0) * 2; + l.dataArray = shortRaster.getDataStorage(); + l.dataType = DT_SHORT; + + if (l.nextRowOffset == l.width * 2 * shortRaster.getPixelStride()) { + l.imageAtOnce = true; + } + } while (false); break; + default: + return null; + } + return l; + } + + private static enum BandOrder { + DIRECT, + INVERTED, + ARBITRARY, + UNKNOWN; + + public static BandOrder getBandOrder(int[] bandOffsets) { + BandOrder order = UNKNOWN; + + int numBands = bandOffsets.length; + + for (int i = 0; (order != ARBITRARY) && (i < bandOffsets.length); i++) { + switch (order) { + case UNKNOWN: + if (bandOffsets[i] == i) { + order = DIRECT; + } else if (bandOffsets[i] == (numBands - 1 - i)) { + order = INVERTED; + } else { + order = ARBITRARY; + } + break; + case DIRECT: + if (bandOffsets[i] != i) { + order = ARBITRARY; + } + break; + case INVERTED: + if (bandOffsets[i] != (numBands - 1 - i)) { + order = ARBITRARY; + } + break; + } + } + return order; } } - public static boolean isSupported(BufferedImage image) { - switch (image.getType()) { - case BufferedImage.TYPE_INT_RGB: - case BufferedImage.TYPE_INT_ARGB: - case BufferedImage.TYPE_INT_BGR: - case BufferedImage.TYPE_3BYTE_BGR: - case BufferedImage.TYPE_4BYTE_ABGR: - case BufferedImage.TYPE_BYTE_GRAY: - case BufferedImage.TYPE_USHORT_GRAY: - return true; + public static LCMSImageLayout createImageLayout(Raster r) { + LCMSImageLayout l = new LCMSImageLayout(); + if (r instanceof ByteComponentRaster) { + ByteComponentRaster br = (ByteComponentRaster)r; + + ComponentSampleModel csm = (ComponentSampleModel)r.getSampleModel(); + + l.pixelType = CHANNELS_SH(br.getNumBands()) | BYTES_SH(1); + + int[] bandOffsets = csm.getBandOffsets(); + BandOrder order = BandOrder.getBandOrder(bandOffsets); + + int firstBand = 0; + switch (order) { + case INVERTED: + l.pixelType |= DOSWAP; + firstBand = csm.getNumBands() - 1; + break; + case DIRECT: + // do nothing + break; + default: + // unable to create the image layout; + return null; + } + + l.nextRowOffset = br.getScanlineStride(); + l.offset = br.getDataOffset(firstBand); + l.dataArray = br.getDataStorage(); + l.dataType = DT_BYTE; + + l.width = br.getWidth(); + l.height = br.getHeight(); + + if (l.nextRowOffset == l.width * br.getPixelStride()) { + l.imageAtOnce = true; + } + return l; } - return false; + return null; } } diff --git a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java index aa9d0bf054f..de8a77c75f3 100644 --- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java +++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java @@ -161,13 +161,18 @@ public class LCMSTransform implements ColorTransform { } public void colorConvert(BufferedImage src, BufferedImage dst) { - if (LCMSImageLayout.isSupported(src) && - LCMSImageLayout.isSupported(dst)) - { - doTransform(new LCMSImageLayout(src), new LCMSImageLayout(dst)); - return; - } LCMSImageLayout srcIL, dstIL; + + dstIL = LCMSImageLayout.createImageLayout(dst); + + if (dstIL != null) { + srcIL = LCMSImageLayout.createImageLayout(src); + if (srcIL != null) { + doTransform(srcIL, dstIL); + return; + } + } + Raster srcRas = src.getRaster(); WritableRaster dstRas = dst.getRaster(); ColorModel srcCM = src.getColorModel(); @@ -439,6 +444,14 @@ public class LCMSTransform implements ColorTransform { public void colorConvert(Raster src, WritableRaster dst) { LCMSImageLayout srcIL, dstIL; + dstIL = LCMSImageLayout.createImageLayout(dst); + if (dstIL != null) { + srcIL = LCMSImageLayout.createImageLayout(src); + if (srcIL != null) { + doTransform(srcIL, dstIL); + return; + } + } // Can't pass src and dst directly to CMM, so process per scanline SampleModel srcSM = src.getSampleModel(); SampleModel dstSM = dst.getSampleModel(); diff --git a/jdk/src/share/demo/java2d/J2DBench/build.xml b/jdk/src/share/demo/java2d/J2DBench/build.xml index a36aca8cec7..c29611d0f7a 100644 --- a/jdk/src/share/demo/java2d/J2DBench/build.xml +++ b/jdk/src/share/demo/java2d/J2DBench/build.xml @@ -52,7 +52,7 @@ <javac debug="flase" source="1.5" target="1.5" srcdir="${src}" destdir="${build}"/> </target> - <target name="run" depends="dist" + <target name="run" depends="dist" description="run J2DBench" > <java jar="${dist}/J2DBench.jar" fork="true" @@ -60,7 +60,7 @@ </java> </target> - <target name="analyze" depends="dist" + <target name="analyze" depends="dist" description="run J2DAnalyzer" > <java jar="${dist}/J2DAnalyzer.jar" fork="true" @@ -80,6 +80,10 @@ <copy todir="${build}/j2dbench/tests/iio/images"> <fileset dir="${resources}/images" /> </copy> + <mkdir dir="${build}/j2dbench/tests/cmm/images"/> + <copy todir="${build}/j2dbench/tests/cmm/images"> + <fileset dir="${resources}/cmm_images" /> + </copy> </target> <target name="dist" depends="compile, resources" @@ -88,14 +92,14 @@ <mkdir dir="${dist}"/> <!-- Put everything in ${build} into the J2DBench.jar file --> - <jar jarfile="${dist}/J2DBench.jar" basedir="${build}" + <jar jarfile="${dist}/J2DBench.jar" basedir="${build}" excludes="j2dbench/report/**" > <manifest> <attribute name="Built-By" value="${user.name}"/> <attribute name="Main-Class" value="j2dbench.J2DBench"/> </manifest> </jar> - <jar jarfile="${dist}/J2DAnalyzer.jar" basedir="${build}" + <jar jarfile="${dist}/J2DAnalyzer.jar" basedir="${build}" includes="j2dbench/report/**" > <manifest> <attribute name="Built-By" value="${user.name}"/> diff --git a/jdk/src/share/demo/java2d/J2DBench/resources/cmm_images/img_icc_large.jpg b/jdk/src/share/demo/java2d/J2DBench/resources/cmm_images/img_icc_large.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6d61c9f120fd60e556ee88419c641f5253249774 GIT binary patch literal 430301 zcmb@v4Rl=PdG9+Kd4xT-h=H-|YK344%V);1xE2|x>ztEH789hAaYth}b+ovvwhTl= zL+gB)^yZwiYRO38ff7j>1Oak73?o1(x3!z$9D3L3DkvCA?qyXH?kP=s&w}(`()i}A zHa9uFNmiTO-~V~uJrYUR{aTl-$n&xHyWhQM@8AAE|L1w%{gbzT@^)-%{-Z-5jkUD2 z#0L3a>?c2tec;Y}#_qi1jyvzzdFs=@c~|L^ckcY`ouB#aft{Z`@##<8`IB$9{9tHc z;MWSpU;gOOp&Tp5Vl99B$&>edCcZBgyXQAP`|0AX2X`L(_~_0n-io!x-XFU%wj<Vk z;^b#e^%n|<Vn6#I>&N*2Kl~^Cjm6&VQCmN|*#G4xo9?*tGbdT%@A>~-Cr^F)vov{( z*X^JC>?yq-=XL7Sbc)yiMz25NuV?gn%wN}SnWM!4mU)raTR-8i|5UHX{PkOU9k#{G z*p^S0e&fy)pWgWy_F3=$fBo;Xcm5WAkHvoDH-F<!{i|cDe`B%l9k657vi*s*&wlgK zSZx2_#bT{rSo>`3=~(PP{7x*k<FD5~+x28D_P(>R*uVdeCr^L+UT@ES#MuAc`=9(( zY#^3s-LPRpYl1(CM567AEgP@kzxQq4ylKl-@4NcytKN6jRo85P|Ib~M>ezPGRXaL& zbX<Gwb=O^Y&Chl1>iWR0_kZBJ52%qAR=uL_iYqs6yz&F7t5P5MfBoN2UW#3{acgXA zthJ>p7Qd>c^{SSiyb`;PA1=XptW!DKuXyVQdbx2^ax)9Our(HMX>E<ue|CVS|7}aW zHMZfZ#MPa>{cYEboVcRvQ>hy#W}n)4{lN<_Z!50+{jLv<eR^_Ja{JHi`1y|R-Txw; z*^|BL=3m(Viw6d7$$j+J!J+(-qrdX8U*+JQyyMQhJ~3Xp`!k<CeedUf>%aT_+54uZ z?|<N2dG3pqN9G@W>`RZ=o~|!E^XzkrU-`qYHeUGm|KY_y`X83Q_R7UqU;ES7zrOnB zr9b~qfAQ8|e&d~Q{>}gLzrOpezy0>*@BZ)K`~H9ZhyUXTKm3vQtA+iH{_`E9-|P45 zD)uYR&$8hP?N>|ubNs*cstt+G-nOgzN3J;WscX7!oY<H;IQ!Ivmp5Jiq2k|f8~gN1 za{I3AJKf*auGyabKijd%|4)0?+_AO&`bKO^YYRVK>s7H|ik&IGnM?n{U;Xm8Ue5J& z$0u_OsY-F{cXQbziyKFVZ(B&+*R%h~c)j!cM{);dyUL^Yq^k#4SBvG@&G}5DHgRRD zu`)b3FqNt_?n^JEzA-X5d#Uz#rnK>NYI1(&{^aQRLcOz8%H+C^HEMI^gV(ZF<G%gH zH~SargO@WbSST$$p2>C6T;}ef?UiC7z4h|QZ42AF-k&MezC1XeUU;TFdQflZ*E{)4 zI(6>kV(#YoFJ41iEw$O}7jrwSM;|zyerC0N%fqP#n|+K$lcTp>$Q@A2$qbv{y*vGE z@}6{k_*(X9TbKUQ&Q$uDH>Y+FZ=av56vt9Wrf#kroqKI$Xn3$cmpXbrIWU|XZpmcE z7ms(RMv5(b_K@D4yt<rTJkB1oNPaXw&livE-8z!nw)X^!oGBJpk3N*HmFHWA_-Jck zyteRAK2zFrEI}hL@x{#6m9Xr2T6%7W*4$7l`vUvw3-!h0Z8NJY#h3EwT2)PIvBe#q ztCib_Tha^l=X~4x@MJPwTd*zmPO0?_Z*ALgH5#XNy54wXtz-M>@t%)rchr-4ZH?we za>Fs(F0Tf5RP<IGi(c*7u~g2edqws*U3<#6U^}Kp;>DGrf;DGbwH_z)>F2z2p|w57 zUSSt^*fFqP^4qT+5;~G?JhFujFK$q8*mA!PaX4Vfbbaw;D@VfjGF_WnI8zv}FVf3B zA5A6sksr*ZlDW=YYGkn9)6?CP*jXLPXE+7R_9vauNl;2nmeZ-!RIQxpeJa<pbD>^L zCQ`M@nc`}3HN%dTlgZIUPuI*yE>%9rq753Do1a-8$?+izEf<p<{=!HuT^-Mi*Jk^N zSui<Dn`eqExz6fBDml_WNISXC@mhJHKi3nd@s(U+=K^mJuH@pjN-8xnJUE`{Nfipk za=P9-UYi)Kry3)DYa7~ED~~4obE)Ev#z?Mf^3fMkg?$UDk$!D)nnedW$n>t9DQ)p? zr>iH1IdAP_HO~vypeNeQzS?}bjl<eGrERh|ol~g>pO(`*=v|kN63xs{oY5!tbx*3I z<CNCsTa%gbItypEu+I}ysp7JFH*od5uinamo1o#Muc=Pbw;0W|vPdQsdaKQisuQuO z`&&2{`Z%%1qZN6R)`o1cR*tJq{>B-0Q0uiO`B}D%YGeG$d{b2CWA@Exo^?2uw3O2F zR~%n>`i0b%^g?ZhHq}g_B^RHM*0duN<6C{8tyWLu)3urF4y?Xe`t^V6`la8!;;wnf zu`^X%9eI4y`!oH|tX_KHG#C8U!062>J}-lkR}Pf(qqjUbeA~0dtu<aA)W`daTN^db zm0hDStlqga|HN?L6y)g<;1b(*0jQP3)k7ld;x+G2*Ws&yDSHm|B}WhHZ|25Z;pVf+ zgJZ&NeK)i$m3otzr6=;4s}EF)BZCLuoVs~__WG%wY;pA(p>ck8?<qKWYH@3Ao~3%h zGAN$kZyoKtRD*BboGj^Wd*^8&Y{#jpcG4jB&>;|79w`pOSS|wY0|DUA7VkJ8(J9^m zKKgY1o(X_iOy|>C!@|Ou%E+*wRlQ`u3T)~a-E(Xcm+l3QwIOYdh7OGu&fB|>Ej|4G z=xct!`S{3iU<xOMH$bBf+oKmA7_XJ5^+n$rMf3_zIhh~1p0n~P10&ll+<h$3opN@a znN};-XrjBPdw55&xKc1~wZ1?HU+o5$#vwuWk-hP=xoum<qJ0(l9ha=Ox`uza)ZHV9 z&(9ftrz8B{WMKDhb*p(!R~Rnx()%4cE+T5(@c$ARI=YXyj&P34P@puY*K|vN?W`X^ zJM^5>(_uMlL^q;XDXcr)l80XH3C^$jXmVr-6zXc`cNO%uPe6bwfK2y5hhj%^WH2+% zcirj5%w{eX&JRw2NtOa!oS|joTt7GH@pO8jTHHZX^&(eJZ4z`Ob{DsE1=V}fFl-tm z<pfY8@UT!&n^|_q%+0g-TzP;~ytrH_h@^Z0lZ0#V(!QBXbdm;2Fr!lJ*bW*p30<J` z<<T5BpXDq^uZtalL?!y7`+94?uvZn3U~`ohVp?Ba?1SdUlXN<R3gLi9xSJCR3}a$i z6N&aodWWsWehc&wa2n8U7zCwjlZHjzF@Q~chQ1jx_0`Np+r+YSE7dI~h6Pi$9lGEU zora_lnHq*(E)Ih?+=N@OcxuOjAvJaXakUz@KJlQqUVGHP(t>BS+X9?5&IdEEu<HPG zxKA%)&TMbom*+y^#kxg!V+U`n_{|8>;P$-VCv^C^2VVD!D?`J-_U+Dp{DG^yfyL4v z!8ashj|3LXyT4fGD5L2TJ)pJiiTs`+1R8sCWepx~Z8ZLR6;`#2G17=n3=bY$E%)a- zdtX|8Gk4&N*QB5vDpA_6-gyaCIrP9Ot+{Jd8d4C<rS-)(3Z<)&q@`Tvl~RU>2A%^{ zv)4bz*>~S-t;4sa{;2*+`dPjo+B<Ssf^<M?akdL&BJ!+DXhx7Z^VnqwuzT<w*10^} zo9hWkJu>yrO2(5@S^&(ZzHzGl`q=7fu{_@tmE4WSbm5*Uc8m@n!y;|dBJfQ}TAlQ- zxx&wYHZJ7MZQa8i_MzzFh?$!Y<a@QvU-C^nLYlogxlUMFTP(q^FNrvsZ(?Wh<iU|V z@@h%zLbQ(X&0NGMV+%04_4BAy!%TLh@TwCp+TIpx*Ay=27SgTTVYPq=2DMz7?8S#y zg+Xb;d~{RLt{6d~rGQQQ4tiQKu^d#Kt>74SO&RdE*8KVojpX|5E^^Lj7cny4!Oh2! znc;vACb~1IXF)cmE-%f{J-_jAlFvYI2eKWQ7M;9ZGr%sDnyeIpJVf}RCUOE_l~XEd z<V++Gbn~-)nG#@xZs1NTrXJ_&2QH}wCvvK2B2yqWWeMN*c_TWDGh#82<T4-U5-+k8 zprxY{kcpmF*00SX9p`6xRmiej{~%w!(47dNl9nA!a-?UL;elF8W~7FM;7q$(D-@T( zvSib^Ft98z(9KF?T7t03wps=1s?f$yG1|tO>9j6><Ga2)fxHwX)CqA3E(8@;PI5zW zY_Q`e_?k~@jw5Rj*3i3!>hX1J6~$8P4FVBR069~z?b@kcF>rZ}kB%_Ym7{H(^bTxs zZ_7wugm3lH7L=f+BhBTwlb{%pflgh$Go{#Q>du}1fpI%^<;%W<^Jl=EcDX!o-kb34 za`voYeaW`klZqjPBh=c48fWtS%Ds`0Jodw{BLjaD8zPn-=OB0XKYP~`eT2?;0njO< zVC~C?h&zE$BK3UdrDXr`;34pafK+h2;Xvg`3ApL}*{!hmlmRwABLOM)@#Eg|a7~T1 z%|CIN$edelao1`6Rm=<kLty<*j-%b1+kYgp1ef0|SzujU?kwfH<Mn~Rt+&BL;5$4t zx1W1I4CYcmXqpmT+%<ZNQ2NlJk;96pFVKpyHnoyRn7Z<Pt;ov7K{_49_=DPh?Tglp z7j|7(nisiG$N9U}_&Rrt<1A^;McCfW)d`8DV|J#dVP2u4E4ID>Kr2w~e5;tzB6f1h z1f23KgrNJNMV{+LsG?knD^qMN2PK14?2Q^|4-sw;6q8z0AIcC?NK{8479nnPBfZX< zwPqsttq-;{C0bQ0&Cr%Ej6|VuP;b+{?b-)+eZDtcT?r`EEx{C~k<tSC3)*DpuiZ*G z66@6<eLNvYAs+4Ew2lz)4a8HlKHxj$(Ry>Mh~-!*x+Pgp3e$EpeFdOASmJK6tQ%1r zbrxdPLGUs=$lYqVpOZwal(LfAOQjTK^S+#iQ+x+__*nD-kggmdj8T*ib&e%AD?;ZQ zq;VQ36dEJ61(XnfGHrlgm1`3oEYpezTr1PIx*$A>a7iMvhHWoyV6tt3I3oS_nD~Q4 zO`vRf$(B(#rX@u=KJM;;2xvO}fqv^WVM7r%$1cGpEQl418wBY&w5cQ<0X$zBNCt$9 z6m%wPbQzUnzZ{HgNWwJHlSn}Mu@$%?(?L9)yl+90PSg{cS(moGk?|<{H8N^pmV>bD zGu#%`gk?1DiLf1{n#J1$v7AI7W?K@-qLoBuGZfd_dH)nXp%QB|U*qUmw0p1Ja;^?* zX)~Q~v8ong<3eWS7tmvEVK9ycoOp{Lug&@d2RRG<F4En@{^#i>pH%O~iwXV4G{6{I z<M0)4d>_U+9Ywyr=X(^s3J(iyGxv`?4h#<>1$#QLOw|<WLN`;D(ujX)Cg90Mgl2Fk zFBeJ}i3b#?vjXQV;kN|jt;Ms0Vx^mqY{5*yZ;TWnDzQxO=6rj1+)TrTMTP1kFtE5v zL_9{Yy}xKOv_$;O`ld#Q`p~p!(l?Ns+=CY$80Bm(T@5$erF=Qj>iCCnZp<u7{6q6R zcke&4IQe7-!+?!G_E_T`^BdLw`XM59fpzK0jFz~_ExNXF?%`;QT>1}ipby1is{-lF z-F<n*vi!b}El-z^458Cp-{j}xs~zhV&2fWi+%9A3M@}~V`7aV+O$aHnUW-Gg_tmqF z4#MpwSO&DT3E0g>8+8K=7w+BxD}$*?pj)1{)(t`EDo3sn36Ax2JBZNNMA&O|ja<#A zCX=`X7lh$xK_l7E%1CW8n3R=goYZ?`ijxhLb|e%|Pe+2*ZX?0c++p_;F6N_w=4(`K z$Fb#tGU-}9;R={zwb2h4uXI3M#KPB`n#;P^dZwf4ZXQ|Wdf%xtV>U3d0ZBS@Tr(aK zmlZdcZk$>7aikC3HjEVL{KW7eEF*fZDe&ENn5(-eT4kl-*uVr|0pRLW<8CktnYBv6 zgJL9JKX2_b0}P=$E;!<}HuI7Z%zDJ8tK+s9Uzo~6iy3B#-PHz1OE1_I9X9v~r;>qm zM*2!xQr&FD&P)-qr{1%T;0@A>0I!SRXbTr<S4gGFUUAjbU_lhFO;ov6Ks5_vYm++B zWpOqM+m<RcJ;JbtND9O)nD#gtT#B7StB4vHWbCvz9u2Ga>)I9Jy(M!7)Z2?YgCJ~L z1jbMu8xdGH0WCY+x5>B2p)pa|)4kJ3?Td_9?Cqq6r$id2G1<Hw(|U`JGT^l4HYcJ! z(C;ljd=ZTO`akXdrGIyE;f?OpeFr9Tsf{ovy{P0zqp|TcVd%`%f|Q>uzY!GVY5PQZ zn;&IJnauVJFdO#c`|P<z;ri{%o!{rzyM<d;ZQl4(9_b@DgQ%2-E6={KW<pIc8?1rU zQjBfYDjl~xY^ZveHb#}Ysm;5>Yn&s2l6t{YG(&S2aT`YuDw{%g2KaH~9w(nBwSt@= z_{V@eI_DV}M{{ql5&G)aBo0iTf?#(tuQyxMB6U`JZ8_5-TS4-2=COB%S^DFhT)F75 z72?nQ5%<$(xOde-=Go%cMI)0|J2~7+m}HM$cuE&GN8M8?l81Zx@`_@c`p;yQR+|p# z4H5B#uhHH_fds1OeIg&Q!ZwU>8>%bH7LC^yCa=acv~~AIWOS=f!0V)M9a?!!tG1_( z`hqO|-0`z7NXmAvvmsr_Id5Sh_X2Iyl^*i-DR6Woatigeh2js0iiYU;NU#FdHu{{W zuqMmxI1e4dqHwn%t9|KM)4WaX4I^A#Z;7A1_4CR?g~NHFTF>H_+Hv9+kOfTMrrQ=D z>08u^Pgu;-KR-S?+Anf&%QTGDi!EG1sVTv&+}{Vtg6vaRSLe4z2VztTJDkFV8$`-N zsp4zors&dH=8B)3Asn}bs)Xa5#)`)kUdvTnsG_87rOkjU6aF9tftRo3YtsK>dK3bI zBIP{XQOvR1eM=l`harAsDVTaF9hM|vQ~U={v0$S5+7=rVimzC(T`!o4#{L_`Kr;3x z>X*PBK-za;`NVLaZy6`nVI>Tk@C29n(Sg7ZnWKt-dyH<K4?1gP3J`>1aq^WB#bG)| z9}I5_v?n;u#T|vrr-Wo#k5IB=j2(S%>PHNeuG6O$Vhfi>)b-hv7fq7(aeNGlNJLtv z@6E89?OAZnaxje!IHl>|cIRcPc<rQj0);7-#st3*Nt@OMxlwi}(w35^I)oR#_urxo z|77*-55FS>-oCo^^5{LF5_fq+PdYnUo;`LdOP&RAjy8p4nR6mol~b|@G5-1pgl9N1 zlM2t#Irk?KdKR8@Cz;}=UOss8Vv2U|yBP8*9V~!YCHzHoR>jnZ^%wR@0bI{tAS_Os za=j-_Fg=<d8A3GT!IKj|v#QJxO2KVM980;Ti$-#f_Iq{@r(}v;lQIFhiG&g2b=dRY zEN61E_9R=F-OH_@a`b^nPGTM`!Cj&DLhlk3U;1J<=g83u{7fE08}gcIXbVT1N^pMR z%ruAK67ginKUm1<sSAVEiT5NRJZ|lFFoc*FCnQVCB&fkXJ2sBHlIk&Fcp$7G-6-sN z6y>wc8+E8D8w1tl2P)Gpk_0iTop_Z~VjyHs=FoiFx%C<{1ob-<j%zmyVASAAR%R5* z=FsITQCw}C&7uI|ok!AJR}^9k`IxNgRQ3_yOKrB93%6tz4uTeo4iz?}DRijsnz<4} zcevU{zAI$NbZ0@s;t}WPCEJE$6kF70mT?(j3^<S$G;eWo{)?H--0Mo)IiZR~wp=0Q zzCgCP`E$wS!Lr54n3M`|<DPXU2`-U`@y7{ilC-nRNmH$+xTsV7vAnVwmW}ekBG;hM z<usNRnNsqlp=~KK4nj<BdN@5#8c~XE-4~m=qz&9=BC_ttpl!}VRtY;akFZ~`h_|>5 z^em@hLB0G-v516^>oS4HbL3`ia!4%5l+H^P$dg-wUi6cS<0c@?!V@=I`Q?6EJ@yKS z=+~qc`dLJ>hOm{EX*oY}j$=%+WgbZ<Ta_cjE!GW1!0p*_e5;25_i#>bqBD)PEFC4D zTG$@QS%@^HEmzmw&c8v!FO^4|vQmI8#VQ<h|C)V!#UyuH0r^4`idt@b$0R0$P&rM8 z-d2deoD2Q~CzKtGh_HnZy*sO7mmgPt_s_;w-<_Kv6XHcQDt@^S2M1@76R>ekaCtPV zyhLt;DZW`E>ek_Yk}3=J_`855H+21CKiQTI2PPE#Vo_#`ElXcM)J6bn4LLgR!@=Y% zzBS4DxVv+SH@J#D2Ncb7jw#oz#1J4%XV0t@5p{#<`s-}H`sS2*kTNZMRC!b=U3&R& z>YPXzEXe*vD+>~x+ezf`hIOq4eW57*M{+<PyT8D;aRJCFfp((!r8;SFYz2B{3p{30 zvOfPWL%wRAupHt?m540Qw~m_^Ig%SR?vRa{Q4s7(%%kNEmS8ZgDGSpg=w>8ISZxMh zq|-KX?ymbRWRD|gj7e*5zzhlY-$0JISfX+-odFo8(3B~$pcg!5o39L%UPvQQIx<bG zt=E)djcpU|A=1>8y)vZ;l*&=&2n+OLT_$Bd>YD*gP*mlRr*B-WT1yp?QO${kVzzfh zcIV6`HbIbo&VcIQjxQR$H)@NfO)X<>;*-0^O?%g5x;8e`I@C|2EIc2}Tr!-MEZVM~ z#+L+?Bv3d(E>*ZF(xkHC;$WI0jATET#FqvW(w>Qsb}3Q`1B6lpP713NM5C;gFlDDd z7Cl2ZyU@A(at73$wfS;VD4ZSal}O__tS2W+vx>IUkp#si#0q+4&?9i3a2Sr$Dl8^v zy~ESqn4G5ml$4P%YI$=}FxM(h7)GU>jK#uTKMGmFZJOx+=@%fNv>SV^{_0~0SRLuR zsOHoi&K=pEZk>V^En~!SZxa8{@+b|Owt#e9Qpi5>f}fB~8PSfHrM+m`3<dQ=hr;CE z?YwGkP|Fnd=`PUx^lG{p<A~ZZktkKiCh!|CS{F?zsxj}2y8sP%C<8$Ir8SEy&ET78 z+1iq}^<!}DSse|o)4uOSHwFZ0aaFMxt$U^^c$+xPm4<to(Hgndk9=YQA^0b&Pyg`m zt>O{voCPRW@+f&o4*B5O;m8P-&QyV;gcgNAf}^a#m0_~l+@}W*mQN`Rrbx1o4!Ie{ z*attL;G5D!Wzzu@`5P<w5e%bP{<QFS^OJjSxo82kX}%7OLTv-2m8l}~Es@gRX_b%J z;w5(uFP$4JE0IJMqxp^(Q<sVEcc-(L#}~FKAET-uRN)ikd|peQdL}8g37Gc`jah&B zw76Q(A}%d02Q;e{V0TzSnev6jv6IB-N2YcUHh{`jCl{|w$XVufM`65q*%N15>CL{@ zAqAn!#xyarJJlhHRy^7}A+bj3%i{qqoE=7}4kS_~Sd%0^REimSn6M+HPeR^%jkbYu zLRB0UeQzj2RD|rlX^@X9sENR2;k0nOMNB6p6zUW$pA_j_)dFE(x}<!StHgz<8tHui zy1Qe@iR|JQ^%y{VKG~iM`FDLA;7JG9^sB}4B-D$a!yI^z)?AudUG0c^YKpab$y%@@ z-9d$_d%5nSZVFqMcC8+LXp|^Zb&Qt88C2v941wRs&|zX}E;*Na{dw+~#L8Gh4Yr=3 zT$ej2O0?hdK3wzA!lHPBZGEcnoO7SG$W+IJFR4#Q{EuaXlpR`4!bCZTf|{6RIqgER zB~LQhdZ2nC1=SS(Aok*x+g4gfl|~kS63>HlO9`n!$U0+DpeM?$#F3AsK@)7kWu%kT za#6Hu@#o~3B60V0TpCJ3n|qG+sBgKUY9tBWGg5mTfG%zfQfED#(}rvbM3gLYPCR0v z0e)KporEA53Uxz{wu`n*1~m47Z;l8*`is>NjEiaFu&u_MM};tT2`H_yNmGb4zmVD@ zo{8{l3x}?^vh^9KUCqPvD<oP4$-eLGhIz0)GroD#Fgx&oBTyTG*m-q3rMO%N!ONNS zK_5S)2+jd9ZJMs`4Im|-W9u}E2wxH0;T_f~eE7N>SI-g<|H<lCfA}2=z6nMRpc_RG zT)#%8VUaV=9%r89T=||GC=Kt)cAW0qoWl&;d^q*>Q*J^Y0&3Y%&R8j`s!_Qff{|LC zLZN$l;_@FcH*+dhobj)zlT?g-$_mfJ`k}(-IcYZhLbnasR@bp8E`Jj_+f_cTav-bu z4k>hCjcqy$VTry%6{qY4Vtm6p^^w_?{GN|fE=hDnPN&8hZjpOfqS*OO-5IQUbAj?u zVS9Mjzg2(L1h)|cc%o-`mlRFQpi-`hRON-W+V5BIs}VQ`k!M=2yQfW_np=$PC8C#5 zw}-Do5~VX}P7hY$uo-euQWz<zib#*IDdK5gCo-dihqSMR*;+njU~AFE<BCkl5a>(n zdZaANGSvBqgo?%k&FocVN3MCQTTEXEW0F?l(tQ${&B*(v2)U|AV%xELc71IU<}EC@ zEVhz9QoXlzn+3a<w%~nahDLfjGFpYqzNNXd;b3wVsHTbjdKDI)&f$7C_><(d2OFe$ z4OpN`p*W|7QZS8?K2_foS5cgtRmy>nwoTR0lFM9=EC2`mQ$_7@3Dw%{!7{>T9Fo~u z)WqnL6F}`x0pdZ)?MQ=3&M7eusj$o|z{hpT_SFy<^W@CE60lw$q^icEXt2Z?k^t^N zm4>Rv^+f>%H8^gopgH9ScyvmPPk$#p=+39jh074=dM;(TK})+xSwK7Mhu26WV?7CE ze%`j@de;x&6tU*m3*|AIDI9Jqc(YS$p9WZ}L19$@lm0VMDLrn5nj9UIsm5oK+=Xdy zJJ+Xg9&)G_EHSO`E$w}dLj;uL7QI8Yh6VmYRwuX`RLWZ(qZOsEkIWs%R;sS9G{b38 zSlA9_lzb(^Mly7?&pPOf7!(z&%VI#)p64f1j4pX>M@GHCFj%O5;(r?BZ23uS_<i5H z0LMtu95_?T+)a`OJZ_|pLB3&uC`$QdTmcH^D3(+mPp<QQW;Biog(SQiE9lMAB}voO zvLb3}vMz8*mCi<U1P?mfwyMZ+!-ItOgZG!E00yZLKaBYMa2E1%ueb3uB}<umXkJgf zu<JoILF!Ai`NgvD7@4u?}yu4JuJyaPc=etbwp=c{Ke<-^b#-{2h=F3GWc<uyyk zN6_W0!^QL^x`AOOdFaroXOnmCFY-><?Uh>~NFPqUd{}kzRESEdp5BMn9OkrMJU-bJ zj+-QOIE|cVA>%U=av&awOKK5BhFpcEO(ubr2JfIr*BYoe-PQu)thF4KarXy=a^e!A zTgWd)l0+Z8TZ#<>Qm%jkU*0yeB)%azjx;aHY1QhHbtp!XEm{{jp8>K1Rsf}tJotoy ztQi0gsex#>WUwM0x#FVw@qb23zEX?InvSa`9JQmS5Vy-kgtm7^-F;~w*9Po4SQx1s zF_-D~O}Yy4J8h43+|lBX?2WBTo$62|++S3boP?W_bL4P}FcG97$eQk?3?`I8kuV)d zhJiTSC&|=E)Flw8D*z5Y!nQ_Z(mczEijs|G0;!}`1C3%aQi??72!dAiNM4jV$id0& zTtI~tq}k5ECf?E`jrOS*)Fxcu6E+v5C>Of6V@4*+WKEgcXZ)F{3YC($8u>E}?4{zM zQ#pBX#XSHg_xi#h)q<j`pedU)A;|eY2#BS)oaem28>MY2zLHypbU499Zae~0t^rZy zCjCgktdo|VQ~c~Xei<@Sg=X|V-1jxkFs*7?6zEnC37xlW(V+BLz#{U%M0DAeOQ3D= zUIpj;o<gX*h-gU@m2NhmU1c(Q=}(M9FmPT<S!@@5T~_iViFP1cuI#98Db~M2%kW1d zG0ZZet6CpbJ9=T#c74`dJxNzL*sUgAd+;H$K?vRA@`v7q9v}Rt8yJ_Pv3XK}tIJeF z7Bwj63@;6(AwRv#1|GtHGSctQ<lHJ$Y2-!DM1f0~5kMu!rf6w(?AkugmUGwUc4iy6 zqFHIscK$g#IJ-1&u4(S(N3$xegil1_+*}#gqw*k^pC(lsk4;&`JxC_Xd`VfX8fp{8 z_bx6C;<t#dq3~QKn`+Uj(BCO`E=g<5%VoVAp(*_K_ENPe_fp}#h82-_|A6lG;91hr z#_g<@=ZCLT%3ehQQkwH0p`qd{!cVN8ZA_br?Bh4Xn#+PIi@%o~sCHos3(f&81B66C z1fwqY<E7y1x$LrRM>9X;iQ%BV#2SdYE;c@AY>{wOn+BpWwHcpTjhJh$;j$2A188iS zHFvdJc^sop+~pm5QLl_hTe#}1YE!x|vL}=3JX?Fplyi)cjF7fN3=_TR9*0E39w$X< zR%<5bb<5DY19tO>_N7C&4PSR8M~S%|LpLxV{`01Ir;pRYBo0SOsUPcsOuuc{a|<)r zNiwczNFe2oJ)GXF7M42)ZET`);^LrLnb6TBB;$BmR0U{UnnZMZV@6J?yQJyUvK6Y6 z2+DE2*LxsFvj&pfkLQViYfO1@TC#Z8a@`oCRjO>zoeaF;YJ)V&B2|&KiO!r?>k!QM z!-Hnrj-TMfvQXdfo355PJg7y?$Ytr^Nx5B1KqehR=^kTMk;BZ#$mz)mB$@WCUu_45 zxb0_ls+G{6;H##nltf=sjjj(v*m?rYl*y(2GxCvB-C}nKPo%LYrUWrD(6Hu^jH(%R zI8w<F?Sr9~j|RCXnrbb}k<(xZzN1Z`_J#*VG08r}uGz*GUqji8sf5{;ER2QfnS3o1 z)k>P?jH2w~Dkrab64K0P(3MDBl&vXWeq426!urp0>1)66=-(1f{`gU)dsbU>JFgWt za#B}fqpBrgLLUvlhiH^`98rg~GeeVDSBj9)GL{!g-tvW1G1OHq1s^n8&0<=^m{3Zp z=DydGT*e!z8J7%I2<>gm-MWI1?e$zaD-gk}u)NjQ5GscQYYC01jfA)|Dnt3@t^7`B z83C^H_nW#xV9#hC0{4@PzH^+#bqQoMVe3`YWa@1iT9~uwyYosCRF!uCD$VY><u&Yr z{Tc{Ka>*nnyN$Vdnj+Cd^F(`Ir5!hk)B*z}F&BO(p%~Fbk6?q!V>qGoqbt9k%GC&q zUX8vMp}xv_FdWNPXy0@qzkS4_Vi-i|=oKqN^e=iro8b+{ECDkTpX7rG?AONI08NzO zODnbrA^t;|^nxeO*Qklzswy4AW!uFlGM46KWiMZkcFA);O}s0<#;BmrA$=aFe&03V zcskqB9#G#ODOAB7D!->76pUc*Qa-TmCeX|)X*ZF+lo5q7^fCvh1&-Nqsk{(zbBQc0 zLathQ^TBenln9IxIk|@9+%}QtwxzF_Q&4X1rb$$nj^kBXnx;1^itP=nXrgEocU97q z?S((`LAB6OWs+;2Gh4VImR0zkRCdS}uW~pVU4yg)WlA8UEaejbRZ!5-3K(EH0NH0@ zwxqIY$epfuh}jvzV{tGmTfQ9RqR=ubelJ*WLS?qsCy6hn#Z354g@7Auimj4Y91jKN zY9rmTeNG{|w4MYV;c}`BP{d<{S(NOFtVxukIj=MTW}>0e^AtV3a#0;$Q+#G$(niHY zZRhEjI#6kt>SQn3FU|>b4=h?|qlDzDoYc{evO*BfT}iVr*IAUs<v4ddb_UdThpnqq zmeo;NIt8kz@B28AQkPBevP~TUQ=0533@0KF$`z0Fx*JsRv+c)^UH4}vpF?5*$U`fG z1Il`L=5Db1a*ej;gH+>rz-S@1WTfhidg7FQOGDyjo~pm1EVvIc^tmXOZ6xGQrDML# zNExy*%$q@^&H!#;wVUybCi|3(_Bu*IjUk38xO+<sI5%c<F74H*Y%9K$H=zD5dRFNU z=xmioQmng9c^T4#7{1so(5jqC!E@KKnr^~wh1O>oZK*P$QTYo>2w8$$gN;rTd*haJ z5TuZYuD_^u?|4|&=a6RCU}*U3C%=tFOF_MWyx6UwNMGD)Y^pz7Bux>GPVqYQ0w;v{ zlAj?1;)xm`^_=Jo$#rtlBg4*w<_sC|roBhBdkEPlZ0)7)D6%I5Rt8unQlx8;BeEA) z3-C8pA-l9BWOYOJD37D4xvpgLc*t-^K|aJ<&qkq$Gbd7*_@=%f1oJ8Y3A}X!z1J+w z^<b@23$@N8O@?7QlA=waYLc}dnT^&CL&EKDBPxf|RIC?QrIN)~tm&HEJKWwK?ii?n z{HVd`=sb7$5OW)&h?W&dj&A2-uuRNaNNtthp4%zso+_0jA_>*4@)Gb8j%f`a{}Uo; zd7sLo!xiRTX;z&R=~_gMYl$><9V=wlIY;Rje-d5RFIX0#Ip|;j?zy3+pDF1G*)8Ih zm;)nRfsv#{G1`{{T+EFW_vDg@X1ui$A<R-+hhWr2vBi~jK~gfx<tS??Z(bc+@en-N zpJAEFNzPqrFC|2UM}whJ##JQMoDMVVIJgIKn6>*Zf_ss13x$@>*|+kez0JyT+sK4C zq?*h}UbR5qvDnkPm7Vtf`5uX4R;=!>f<PX(p#6lqirTBNLuw+|lS)h)^|j>%C$t>M zXaWr@nPRyVmgIaH|8o5Y%@n=eP>P!qp^tRdcfUn@bmhw&+TXw8e>}>M`jgn9FMR9e z$V(`buK_*x$l{SuYU+mm$B}PIW=^km!U8j5Y9brbH!_O?stfa7=cziNUTQNdV zMV?1v5>bR+Ag-Z?;{@b3qEYe^v6#gcwVHN}Lzer#WNR2E<kqH-djxSB_oy}GcB&pS znmohO*+Cjo$Vp}9Y2uu1yB@TW;x+@u=q+y<?Ie+BikB|*+WbVjtpXjFK%x8KRLaKl z;4c_^)t#I6&Z<8ejP%Z-XOp*FV2C@C6XAJS&M2<wQ3e_jJarxWt}y$hE)?4qqTm&) zVh`SBi*)4!<Ll7@(x{kRUvpC!x3E?5x|At$HF5$KvQE!cR@Mj1jJG7(24@!P9@~VF z@c>mx^N=3b92nHnn=zX44?TG197CLO4A%yI2VMiLHA_;0Z(SOQ&Vo2=-{WQ=)?wxM z+Ku;w>WaQ!aSf{Ul-*1WeqwpIsa6h2*!w&L*AeoXP1?^!pw=PTx<a*(Q<7%3$gA{J z)DpM9ORm;KuRSmyP+(3aU7T`_x<(NSTj?G&rrg0&LUHY~5P}#>R844#E!0Nl;>6fW zlLI1t9n+r=9xM~;!70vad5cz|6s64-3zIufcq#{{(*{2V71^z-9ONMz))+>xX)&(0 zOKx0ji%87I)q{2xFX!46Qez%aWrR?cK$Pdmj&NZIp{k(2!aN|fZemVOr<P!LhsKB{ z>+O~DRm(v?f$9YKOtNWZgO_!PfUHR90F)`<wn7uT{uO&~Um?&Md?ihmuKr#`5@_e? z6FH)$I1^p)N+GP&u_zOqOG#5TJuwxxq>`<m%1U!Lg}ocXS~gyZaoMg#HHa~w5eqWp zbqx6S2B{lbW_#>e!X&7L^z6G)o36wh%=|Kv=HjuXsv@B||H!MhdwF(^gVMyQY=x*U z({?T$<5Y4dbeQF&b!%^P;5)VRe>N|0{Kb#%`t5)9FpMDp|KmmKxm9AhN-cZBG5R6R zt7e0JQq@(2=AvMuY{^;sB3pcy5Sx%U)J3XV2+b#llwp);Jk5CFQMmM~%tMm%smlkq zQv_tPRk1Z=9}BW5pILpE`7jWphBy<Cta5bjVjBwa5+lu(#J=#-n<_3sHkR|eQ>@-T z=$uu7dV}gqNzMtUu3~W!(U#b+uzTrChf`njs`U#<&n6j*n#zsxlW7J`hD|Rlc7H)h zE{)DaC^Lle@(8B?uyRMFxUSysleK9Irum)X$Hr3T(j!ebE@(dPb`Fasd{i0(B&DiC zq;1jd9OD@+!NQOF-0@BUPjP><A}C@Lsw<eATH1x5>s&J3k@eZcY6UI&9)odhxMRq@ z6TGiutB<ktQI2X`!TfuIZwsv5_@pO;cOT;<_5d9NfK=5(k!5S9z_BGwUZinJ>oQFb zwRg8seXtIy61t$0D<JHy8bx{so5L*8-`S)99}TjHO%@TPR(LdNg8MR#b%Z_S##$mM zDIbz@OhRN6hp7S@G|@9e#-<`#t*cIAXBsIk1p;pqogRKmIa+m67ltRPOVw=>wxfIa zU^S`n<>-`RQsqgTwdsSZXXggptz}VfR3}+wXm>O!+`{lp7zILAx}(J{gP2A9=6XU( z4uk_)o@J?B0Q(i8*j`CRLTgK{6R<-b1?R;yyEsu5ztwYTH8)T>0UOhtQ#NQ5AhJW} zX@RJ{TiT6oJpIS+0-!eYKFbkn2cd}4*7l4U7x`3j?nPLV4uzd;)I=<7v?RE~=B9UO zMNMR#S(Z+aOQJrMeYOfzHUUS8wOgFEusXevy8i?XLb`Q%Z$;9b+Akrxnfz{pfsvuf z%xa+x7&zflmk8T+Fk}u1cMg;ScJet58}t}>JAdZtibF9cHOv+q=YCh<PR60;ZpICK ziG!#EsU@cW%~u4wKY8;AWk*WkY`x5n-kDU^hUk<82my0nc2e|H@O<9Db{~c4D%E_W zTZ;9zwn{OKJ)e^J#Nez_7}SMdN!_HCcxvp;3i&4E9HmO6x<e$4Hl#jYsdvtOAiYmv zHsTXeYLjkgeEH4ub(MlL(p$(1F|=0-<ujY?GgZJV;`UN>5NdK#>T}fc;r-7R70N3U zPc+^Urf3_TlY(UAlH34zEh{u$H}z=)*D+9UJf>oJTu?B1BPIHliywSU1yGow%4F?l zIOduFKRw(%CHqq~L2H$qkvXV}nTk*ChQRuq$u8wXr>S8YH>)ueoF9~YlK~jQ=V`G` z3mRG#v6}L9v-5#*wZLa?Nm@ma-lAPc`h(ZV<zrcV#H2*wCf=&VD43xNmCcE4Qgqw` z{&ngXRt7+t9UvHE9?+%vtN>^AKfarYMAx5y7s_$EMQy=G%iwzt)rE7`Ezb}2hq07g zC>Gj><~Iu5I{<LEX;1_8tM_HsBq`fy!Hh7b_Hil3nP~%B_8=5Y%HcT9Ym~1HO2nw7 zsU>&hiUyooUfn3DI9uWUDA!%mZGa+Igj6bAvMDhcRs;;qzErY@xgj{OtRP<ba<098 zM5}WYn0m}#k_4u2qOCY9qGFSa_F9~51WgkPYpOQn;)qSomX?m?dY!<1jA&_wXBVn> zxNn)gqz1{CXZALBoIi%INl{kHZ<afR#$Qu~)Syw;LpSlG{Y*wEvJS0HxMjEnPM*T4 zJ`L{CV9k=EkYut2Xim`c5+8nT>nlh`ZT6&U6AvVsCZ{ErBqzO>5pmbR_WR;JjY+8b z0C<yw+7o>e6{4#?-4j)swSxt#{?2-xkazj3KfMi;wrWR{x~VbA<iJ4=n(hbUaL>+U z?|VSYv~co#t#(wRH!&#z51v&b@1rU|a<n#s1ikyW{}l(lQ6-<QDcQ{Gyf2+K?uAd< zW;!%4Wrw11K$6qUmy(dPrG8D&VR`ATHAU856Thoadg)CSEU|&rYqnR4N#vR){3VKK zem4F=(h-`!u2@=0a!q>VRsrQiXAe^j%H~OhE5|OQR9IGB(AQ68H5oDQxS<)biNeX_ z2(M6B7G)H)Z)VUhV=OgJvMS9?y%Bm<xuBxvmJ2oQO8b1osx<9Rpb3EwJce~3uM`3L zaO(2$>^tz^4AH&6rF+RC%YfZ|?6J$IR73wd@a3L!Xx7T+>+=UtL}Q!@gyBBT5!B)q z7INfkIE#%(o~AxKZ!tQr9x;IjrJ5CvA`LO~->C&imd>Keh?m<9TCxadF0pnb;VLFL zo0)Gk=~KTWXs(Uj3G7m+udv$z$SEXDS?#HqO6&pwLm7O~mrHYeZ8cZYq`v)Q%N4xL zX&)%cZW?%x+K3<9;@X^*E@b^sbStXgN_KpG4hxZL(+xNGE2v;g6EWdOs7_EZ{q$26 zPGZBV?g*4NNV%Ti7caGMRuPgV)a&v)t95yhN*h&2`o~9<Yan6BX{oRol5)vX;n{?5 zCMm_2n#2MvZ|=`?gT$}VylfU}s}Z43YZI9wJ|R+5+p641>nd+0pwWs?DW?y)`k<#W zDs*qp%Y2QAK=iJmmmboyVgzU4ssLWYi9Asi66jE$6qn0P+qe(8)QXy3qfjsl(xfMh z9#gH7M6S;uYztBFWHcnQ?F3BXX>CSkD|(dmCD!<bUB61>@sXv2lA$iXY!pO~viqhC zX=GXOvxb%`@=OC#Bdz!z%hL)ZBT9NbIsHKOaX_G)$K~w0v3A;yLwPi>5%V5sbHKG( zuNk5<{wV|T!`6K0<{56GR&XC^9tZS%5|3J;zp=cmU0yh~+0zydpeKg3c^NY=Zff?5 z+m_x;vu(9`<~(=L>L<RQt*$0N_)ov^OaJaWN~{+<nRcUG7~jgwL<(Z9jMGU<=x%jL z2|RRMQpQdyX4gcO4!0cnl=#g3Wr<jvQ)2X##*0JE;D>6mOrrVnEnm>dyVYz?sof(} zLwlM1qtda7+l-~^Ss{C$&6&Z_^ASnef9Z8g8Wy>`Q*&)9=dR-VI^D|B+S@kP@=JTU zJdBG>x4EtBB+i3RPV|k_SelKON=plKuOT?Gd!3Rt#RuTkbVlTyLLof1C)5sA?_Sam zWDh*4@LrItSTbI&fT_{TcnWk0HQJNr(xPd0>MJ(E$NA(v2Y{RAyR`T;R?jw^Ed=fr zLlFUYGmdw?<rAO5m!B<J%1S!ou5!XP(?<+HdT_90rJF^En`iq4z#XqtS3ULe)I*0a z2{`gg-OuDq_lbjjoTS;CS<ViXaLPW-2cz=BR9hHm6nH4P`>GbSERYFd>lM2hR*}99 z1XdBJ&tYsaxOo9PT54xmTOH5=@ySYpj1Gq&x*2c>3YmDjL3B&tbCFGFDO3s>C(in5 zw$Q=!A=azdvtUYUFqvLA{M=|MtYVb*kE@(rQq{+ZD@VWcS-!JzmTrD(xDYy4?qtNw zq<O36Jt90eBU^g7kSMS$knG<Mlw9SRM1--FB4rW)%7m#;v*{^!t*O;j4kVUKa=OKd zjbEqp#Lznz2p~|W-SA=9NIQ-atsq&&Wno297x2Nmgk&C9#!j?jA9sWy-do9b?wAQg zrn5`%ilWfkgbfT5YP;PY2>EHFtdC9dicm38y*r_9ilXMas`&}QuDbBFp@s<Ah7Pa~ zo#H4SgLgQ957i3VjZli~EeoXb0wFL0mo~*GO}RPqoo>S@z<P!HvgPdpyjI>(c`<CB zUI}!@ZP}<5+g-IF>fVsvyfL^6nwQ>i+uD*hX{#}oObxhYWZlRiwcSD>AT3SBrmgxA z-CN7T6VAw=-7?DA>5P{EZA8c}r#B~L2?TSvaK-B{y*YK`qc{EdNpkXxa?BQN+RIr^ zCp~Q<g!V$k`_s~jDp#tw1*+GC_8{aJvW+vUOn(;-^s6>u2O<^p+W5@blHpmOXihg7 zsPAY<`B5twV)TwB=3RZ-<isTg#ivjNvsbpE75mYxs6%C`P`rxcCq2T??-}|)n%lT$ z2VrA_O!-D=|C+rSc7JpBoAZw|Yh14wX_7aWUc82tm=#1C^&8AZXS1`<cUsO#lOZEL zt`4&qpJEB>v*bqX8EP^(OIvpjowUTiNot$n$tDc_QyoC8Q}YSlDZWmwbKBnjpf>|! z5)!BPWvwXOElh}de(MUOHFt1<5Xm>KQO+FGr#BJeM>!-9*e8jdg9;nciq@!St=85a z^3Yz4MEka=?tCLBR<Jl#zZ5LbbhA##T-vIs-E~}5Ilx+OiE*d@MV>(=B<<JWyASN$ z<h85nkyjH$ql`pb>k(I-%mxyD51{?5@7~%vua%q0Z4$`b6qaby%~dW2?kH_YaT`+F z!f|CFsEX#rcijkhjE6Kdt8BYok)I80R4`3;n?i7p+>N7`CPT3k3L!-zlrckA@F`co z2<0>tWHq0Au4i{qIt||0Y$4*RR9HU(w>Sy}AzY#-%2Bbw)ug@*t=Y801olENy2Ugx zl9R-JBvmE2Y={$j)vB3H++qZp)I&NIOf!O-WEh@AiNH{sgF`6iYlITnFvu?Xiz|6v zF}lV=NpKQ~_W>6&V!^0|NCq1Un-J_45z9|-U1}S1VhM*q)<&NqTN&3$EvdFhWbFVa z^JUSsLC0$(6)3l&1SR}LKAUSkOoQ~0=cWq#1n2i6m7kCPFv^I-C04TP!bOeGY*YfN zna_z`SBePMB9VRXNgV0MG0mU)y(C0U)Fvh;0zFl=bOT%R`P#+Hz+lov^i*PV*hgw| z=d!4u>yL5qf#dnVVROw*HcRdSzATMZPj9gXJ)SSeUwfU9<}ZHqX@dRs{T+8|4CW1` zM9Lo0Q$KhXTTlkTAK|2K3-f0rM~}leSVLqjFH_Z=0v(R%;d=b6!g!_)iP)=R^yh>z zjS}j}Z2CgmyyEC7j!}|zWULMbEV|=~kI=6qxrV!EHsNt{9PTfV9_O<%9wa_0U*EZ3 zgWu_bJ(Gf#@8?8L>>j2=-SIDOHAmp4U9LFMs5WV+lxD?BJT(SM_9yS?H5V0wl|Za~ z1qLtcGv27|{@EnOpQz6oP3AMzH^1_6tGQAQ{e<SGv)!a8-?wB|BwJ+)NVe|R948Xg z(ZJ3yGzb-E#2}6)Mn|$n)t?D`$1o5`pMk*OkrpIGU#Uf5w&kcS;I4G9TN#dlEHCi1 zDySWlQ`Hym6yd`A=#@6@-m8^2DUc^kZemclG!&vs*C*tAr)bPYZX{*H)N)qZq;Gs2 zeMIr#hO&Rk3dwm8v@fu`Y%ZdEbVGP1IIJ78rk{mLW9m#0+FolL*qPGT)s?}!f4*P0 zENi<GW|xD|wYe`3qCKf4T2{1{*&K!+aqeJ+lCW2Jo_mUsNG50jtR&%qNhP!ar_!WW z$+VrWGS1y_$tv<5O?ZmKlgkZPnUb0$(#!qSrfRU}TA+`Tbh{yZDkHIB@-<!_&FzxV zVbzg-ge6_Y$?U6+m8}Q*!=4p>WeT}Va!KFMwWxA*22geB4-*lGLFD!L1bHCmFDpu4 z_7B1g`MYQ@tc5)<>tfgTG+~panh=V?@tjl*EH^C8e&OM^pgb-jcJj+Di=kqe^tj<Q zVdND|F;Iz!xe=&MCn0Fc8>6%e1MBe*L^DJ4aWRjgr%1}066K?FCcRDS8bt#otwr0$ zLsEpItltMjJd4orA$BZS&TE2SDjKTZ%;kH_(OLl0IV)#WupWs5_sA*k9d`TEIr&ZH z=&?p_R|RT}Gmd*ms&W4b_S+l*Sp;-I+~v64%Q;9ViWH;T{jE0fyWPcd-}oPV|MF|! zd+Ra+_v&=^?NX&mK5En_h$FnNNi<fmC$nUw&f8K4<{tyYOjr!gkf2InVN+sWe*XyA z^NEZpT~~VDxCQ_Xn?4VyCC2k+wt{6<8?~B8NeTSs!(n<Qn$&Q1{K|uGPCQf29Amm8 zhA*)(yi%V{4(@UuH}E(8F=+((0MYaKs=CVUFW$id+|G}^jbyGIWulP=0+i|L$|@!} zwUAmaF}V^B7PkaB8Jx8!*4t9=6kYE+uNfpNHJa5dQ&D42YT6NIE&U=GzKq?l*FDzV zyTLcb`!lZ{nabj-9y*o1%q?NwhJTLfacl!EjYbEx<Pi~YH_2wB29<o57ulTMcz}ZY zz_{}&N1EQJ_aQL_T6`W5q^OycKCOp^$C_JYt%BdCDSB^N=X>g-L_6bNG-$}_iI-Vi z{n#f@=*e(#6y`}K%su%Pjh?d6|8AK|R%av>Z3jXXlRtH60~GT<#7CmZkjSRtor<pJ ze2(c0z1q9MYzzHKNbgz|Y<T534kCS!JB??!gmZ2Ss9Oz!f9edkVG=#0#cTBj$05`+ zX)Zc=Nrs*TuT9}eIaJW8wb|gS#<`9(y;7=iBiVYAR*fDZaA))&Hsysh<S7=CT7Ae| zY&lb-|IO!fhU;B4Vr4;LsF6%kd8%c327&CRCrhav-n$X%N=;A)c7q{B`Al?2SH(*# z1m(K8(Tw!1N+A|?>B~9je6WxHh?|XV$7|(6=1P8luOqdHy~^ESlF){E<WZNMyjAhO z(F?;fOp)Zyr*<9m_AOJqP#vcg(qA$c0M?SeV-HMmPMoR9T_hAR1ubgYQ#f{jR-+xw zc}l8T6F;+5;hquD=xK1yD*O-bM~O*?B+Q4zhNj*OUs_)1MR<=sm-ER!0B2P)eJYm< z^EF9^@*Qmz_EE-b4r*^n_ZGUiIqat>-}AwT@+z)pTeftIk#*iphucqZu<t)!n=i+- zv&t@6v-cus^=KliPf(M$7vjZly0Vq@)-3`QzjR19k0~7{Zbw#QDwMObny1$v8Dzq^ z+;2a7|M&i9iN8$pYZT`*kw^!#zgJh!>oXn~nb^r(?#e*5Ym$%#CF}?{0&EgUrH!}C zU+kE*iqwrVOPTH?E*BLP+ruHP@~XuA$}UYk9|g|(7333Q*|fx(3mN<sN(`<~@ec{B z4x5e%{{R#UyPLkC8vMB&b)~e9ltfHObFK{YBqK{~4Qr$+gX<3~VI|*`N-mzqM!Eg) zR-3)<OV^tv>ti^JyFa1~SV(<Q^>5V;p2gD0c*<MDWK4_xz__D-$TK#%_EdZNc;?S{ zdHGeBY61Llnhoq$>DB}FSuH`+Kf?R+`AB%O+v#qo*qlP7Bd;1x!DN$YYa_#V?BxBi zr5WZy^5L8n3P-<wHPbGK_fTldhAepH#0e4eD>5v({FHDqKQoejuUK1H2aYk$Qg<cS zm6dK)dnzbk-eD_5)z)n}=2Rkrmx<uK=ESqkzsG#-R_040G%vPQwBe_-W(0u4bhCuN zLyNfUz(57dke%<(wVkz_f-M+<7RJU!^Q|ipa>-A%g{FO+sTJpHb46Z71^{+9QZg?P zXyPRLWTTk!qjSbCue?8_=l58JR2M&DesuG}WzP=j@of;~!>i_*Y7VBvwr+$Ub)l-x ze6T;ynXJL^H0?4|Eqz^LmB1aM+oU5%N(nglEJbW&)Sq2&s~-@@rF`LGCV^sZJ7eYm zPQs`uOqmBn?~>b^9V9tAK*e@Yw#4*LTSi}UlA&13W-CCUc3T7mY4Va0T@FG^NHJT9 z3(7juGgLwW^g1T`aDSfx6tw*c>!g(<^I<|&`irK8Fii_Wt^l8yjcbpk<Aim^CXNgw z*^H;WD!LyS>=eNRNehe(<5Akj*7LEIC%`xlFA_4-8u}DGg)3jS5$y}Lx#**4)Rg2i zyNoMfDEn03v3$YchyRdwk?S=H-i7)3nPcH&sZ=lvj?Z)W&iJm&ux+f1`X39~e~bFz zyykFnp{w1DzdXz_+)5jUQtv|;htKIM@oYC05@+1CK73tQ8Fc)?_kZx?e+`e`AOml% z<dvi<m?EABv}x=SS*XS)4e+TSEaQ}76{yZ?n+5TXB8J^Fe_Xpwsr*M+1<Iq_@c8Tt zT^e~R<%$V_1-l5U!Ltpe*T^OnM44AmHOWW_-u7jt&7<BF?R#Xg@-}{^MnV+^*OgR( ztT49;K|G$sk}TAVHV`Q&U7y`_7ix37+HsK4@HU<lOlv&8#(2(atSS5-d%p&NQi&>* zQ%&UwFsn-F8QSt&knxfaf->~VB|y%T8oNl<zlNJGeHs7vb-GCYZP+$`YH@7Lo-cPt z?>A-79((Ma!zvH>Q?p#-A-?tJ^bp>zC9*;-Q}7T2ZGoCz9qZ(`HSOo+nwBDx@d;K0 zp;pPbNa;!1Hc>h*-a)jerga@zWzSkFzX?XygeDywt+)hU`s8-P65FB@A7ZxSY52%b zN3uF$Zi2pj)d|ct*L$;itJJ;~P-*bh^u~0Sp<=eD3EK0l+DR@oG1f~0^s0MpzEZut z_A6el5IWOzP|_NBmeg?2M(VQt<&?!fMf+q_15(;PWpz^}bfjKpQfKtUj;>`PBs_h{ z%HXgPEYUAR!I_*B;JEsuBoqdvh{q+=LwJZ6!1Ye8YbYJnvQ=fHv<(|e4~mtNGIHt< zip|D?S~b7N_gt<>v=*_|`lHf&pIiwbYkVpVqQ}kAu%Su}+0=|g$jlT9+uE#XtSkXK zE2vI@I|WM0m?>OBKxsvZ-CU}ug`kJ!eyBCwfexDzu(TSt0n1nc6fEDqDmMYGrlmDM zyNTH-QLoh+RscF3Sqz#_#KG)1rTD=Z7ML3ZC?IWYk>(@L#;aAkY{5ZyZ?bnd_j9_3 zOk>@Wc_Im^cUCsa?+(VGmj+H*f?pt29?OcRbO+I%sin-PnlV2~Fsk3~l}8=3mfVQ2 zaRm8aRbfQS@tV=sYipw_0BL+LPuM9aYdBS5`?@XIp5@=Bn~^6l(sx}aMfWJxZ+-8r z?}TAYNrH5VHkX=RIZq$ivn~6cSLOQb=Eos%ZAnua>v5FmG*D%!Dr`?@Yx)i9=Pm7S zIV9B;BuF8J2}r1?N>RG{hAh*;DxrRn*_ghqwEi{QaYB)T=30ihzghakCfX)#xTlXj zjUGdU13HYIV74eS`=m?@N#1A0b}hfKZSMfwlg3<<l-YGE3oe&*lep(Vc#v?UF-_Up z{LUIUJIpjG*u@=(rm46h@8z@P&stTL*$xaI(>9RJ8ZY}cjzh8g3#exXQK=5%!0Z-t z9R8en0NT}o-tRL3jOMm4Fo{vm&5p4+)~G-G63T^HnJum49&58w$>*|r_1bS|Zi|ZE z8I<Zm&XVgpB!3Z@=)oyr4>#1mb}rehr6!D(*#D&t57DFYRpTA<F(n6rE;TDjtyq*u zU%h^HvdL==0{EE<skmDL5qzV2K@+dk$aWidwUOA031zD;P<9_=M(H#l7~Lf_L5Ufu zR^_05%3A*z6fvOrthmbD;eD?qAfmwnhSCEX#H&Z~G9L}ArZ7W6l`I~jF@8HBDU@=J z@dx{TQpiQNf}v$nSZGPmR?eSJNQ$})Ru$@?Y==m;s!_JWDyu3gZPuyE6aci!rSl;) zP9jiMBs(b*DtA^CU-U=MSdu-=Lb_3CfWB98c@cnF5dH;QT{m-yc7pApNtIj*d|ifI zT{BI=T7zov;f8dE-*a%B#vv?K4_0!jKP6yJp8%7MQmD;*Cs5WXyqeB?Q=XzvbFX2} zBbUXBv=!qUldZ(Fm2<K1;ms1R^lX4#yO@COl8<IBkotF(DsJ1*PPb3x6F_MrZc19z z0(?9OuLTu|t9x0Mji4WSbeAkxcU9d)UASn^>KI)&qKSpfV$dogq~q7z447!sFe6Y+ zc>11(shADVf@h<MJF(6#*emTG!Cqc*{E?S992_s}xD86Us5$yZV?T^@=l$*HuK3>D z0_7WBw|Yq_2^{5zENIVh<}nyRLKdk>kln|qC_M@(O8`IakvYqj$9Z%cresZ(^a`e> zQO}HD(6mZ64`^GI{8AYI3|X=;v7RO~4I9?8K;)}ttyGJWQJJD<4$$}q-<L{`XD{=J z5JGNCpve%(HWd7uIXic2Qsc6C4m@XxZG>|=l;@u#DTYunAo3l{pQXg?n=%V_o4rcG zf(?QqGleo{Hfc@dtbX&0Te2%uWyxz$0oG)tWA4^fc3Q&Mbn_j~@GzmXD_KeqG}|-t zNe!Tq(Y~*QDfm={2ORGI@AU+u?v#Vg#-?^m7b+@8Vx+%HL5X_rL%r(RyTK*!!X<w2 zW<bq&eha#dO#=0_-Y-l_24bWlfX(A<4$}(u>^hVQdR!w`92>>_Lt$)|)TJrv;3qV( zyxt)&1-eNs*hcfBq`wvT_hl_Z<>qev`M2nNQO{&HvbqRvRx98j%LH(f!5>Z9L~f^! zgzEfF!gDJL+Mc@Gl*%liG=)JG=4vJZ4vb`SVgVQ&aS2Da^8_Rxaj!g8-h6<}cGs}- z0a6-uDqND^UF{(UW@)Z}@p&SANuS{1#_=yL`qvzz2+C0c`_o-A55!2e%S_QS2BHb6 zgyb+LAmLIsE_VQ`i=zcxu0(Ur6$SxJHRZ5a0F}hsxYZ*d<|d^R(ps+|;b(eSAZB|; zCU&X`*d?o;&Cy>Wvp{Q|Rr+Ek>qS5(B1*0vu(mqcu=wZSuhOUu*YEF#ozoI$oFG=h z+KOtn9Mz*Czl7zXe%yat@I?7Xde2MBS`nI-4x<+?iVdJ@MAn1YOjfKi0<zRD3n4o_ z99N6Hn`o9u`8cSkPyh|f`a&aZ2+QvogFkwO`V%t_4+B+rM|#Q@zJWQJ^#z}iPF@NP zoXOt~A35mG?6>683bhe8A$tI*9Zzy2xes!Ou?C)LVJ|@L4QZxL;b2=%%bNPZ4?0Hg z+4ke=@BZ1ns&rDhKFYR>4p%6&8vPB1^xs=zu;)gGlP<K?EwiP<`^IvK;@6C(Gj-5j zzWq%N|A(fR7{v*is{>z^gzVx3LBMf;w46SZqHKD2q0LI7WO!m6kck?kT^xtqU!$^V z^=y90x^nLQ?aYPRA7((=dihlL8;Q<i%&?4+YL=#Lj*+Tg5OV9Y3`F1*>Xqjia#Jtt zlBOIUItQr%BP*G6yO8?p)$*KWuQU$#5~|ZY2<A8W?(m`1JE9_)trzyr8iC1kX_9}> zb7@X$n@OLVtS=qrj$ljf>eZ6!15SmUR_<0Rt4&jA0P3Gj9%pnd0B7jf&=$>ExbOh? zekK;}k8A?s<}i`74Z>dwqs0`V>H^Ai+m@}s*OqgWbt5;P2#74>_5M6hIkY8%*RoNb z0YgpJ=GSDerQUCPFIWQ>73izB3b4u`@W3B|8@AvnHp~ex9*~B%##l$8{d?bf?rJS{ z<_+3y0NqM?S%2-TDzwEm$gaC-=mAn4LCbch)(ub9Jwrm>>nVJOd^UVq@pp>}!zrsw zCCCr8s;S0<)Y4lqmCtSx*W~v}w^6+oi>O;f(U2-jiRGH&Rj%mH1#D7Nop);kQ~|J` zKoZUsU8_FDyim&;vC6R2WrM6<_Jioj8L-i1f1XFXCK6PiCe@_n+swe=BA)#iX*hPE zUnK#P+!8vg@WOIh$v(u<<P3Nml2I^Gt?`%=gq-zQMgL5dnj=A`9dN;0V%wmQivh5f zlQD^_C5!^{`bLBLuPBXgbW>xN>L*8L8j)#2b(82HF86AQJf=c`p!*5zF_h}{W&01V zpI6k=^iJ)vxe3DeL{pwB`)-MU8?lw>;Zg5i`9%6hb}&6QV)M?kLWq5;0mkSn*?OOv zS%an`7Xi;<5@?!|gyCfJb$A5mW09zpx)ngflSM|Xp|X<vF06rWCINJx+4uAdO_^&W zs5IqEnKQx-4i28FT35aF<yfA;<5L{o<qvNZgA;aJz>UC!@Zng2<*8!qBA5CVC;#R@ zVj1-R!GGQI<A2TYs$dqBm2Sc?rFwrzqg9`I7wRhVenU=cS~O<L{i@-X$eibh=vnb^ z5Lq8|gW!2fDA^N`dNlMN!N<H-c?iw;1fNz)16(T|Oht05rSh4mpA0^a>V%S1ylRZU zhV^GM{q@1OOF0c7U8V=A>Z%9rGxsx0A8E}sH9_S8Mg7%F4``ZuwgGCnSBzduip%se ziLpIYP%S;KX{M*ZB$NADVT0z5Cb)v=K8%6jUc<7i^Mj9BHtgIum}F)ZL$(b~IQ0yZ z3!vF^JS4@dv>1?O4#)5{15+9rHr)BJ&CT+d#&A)I@Hz|Q795&4t$g$kcYIgAFhd#2 zn%>|KkBK*NZmE~377f!f^-joR4ctNjdTl<L2`3t})dL$AH}^9P)S7M?Eb%b-4)bWa zvjU@LA(cw~!;Dos5~>&N2<w``K=}e%7a2G-JoxK3+p2ng@_Jtsc;5ADN|}02o1bzT zfb4rL*Bup~|H|dDMfW$MR4FREk&_zBppBb{jMp%5Hp>H~Lv`3%;~MKvr@}JquDb+b z;sN&5A^Z}<g*%_SlM~&?h#gyNSGYN_EQ2+@*rT9zl$X$o>lr6N_%jFg>j!l~Ax9aT z0<4&5Z=5+UdG=i*UH>~g-JZCFs7N4`A$C_04ot(GGu^9CM=b1r5?z{LIm5crWnA+7 zZHE4mtkTr<p=-%ZQYZnYO{ofq{W-CjKa#5vpfMmxdeP-Vp<(2mu%atTY#fMo^$Qit zRmt7kACGP-S>KB~J@^^HrDbi7A`=V-0=u-OljdNEZuW?HO|Q&Md0MorxSSV7^FS~| zDL+zK#_Y%R#aK}a5CvP7w;2WOMnT^Yduor_o0wM0fBM?zYL#T0h-u{G29Xo4Y)f0x z7X#<u6DpP;hns{Xtrdu+f=UhfBr{=|=SsRbs@7^~VaZx1aEW-kRtcc{5<{mSO-;Vc ze$iK}98k*3)a~d$Ys8}Jtq5UkVk#ba$B{_oW~9mjOU*H>499i@d!Rr-;O}WYUumqD zvuv=>TnTv$F@n^#fAd+G(=qaEmplLQA8aIRG=)AUtT_P;GgY<LCP-Xey`<#*>e)V- ztdLZE6P6K~N{`J<$<_T#P^&f-OOzh7%2g(G7J6+~02OPQT}$-MBj~>^i&K+Nw-Miu z7D@@F%o<Xjx&ttDz}S6GZ^*A{SOjHLo*1(#Ee3GOiuFlc82rV83~znimcTmoX<1FX z56RM?!xw^hmC1_U{4FypZaj8bnYX!Io0ral^-7Ir=Gk+kHa*Plap7)Z*%eKNpk<g9 zCiNqVbJ-$}E{|v~BaIo50p;~f0F9G%N0-^Fx9ZC__bMcH_nt<iy#fq)R5E2prdd_N z8fI(`RzY)!|B}sMqGXsA4?JWkD1O8MpuCD_`D5m3G$wY&s!5}1oqL}W*El)c&6QnC zcppjV@K(BYO{j7fxhYIFZux^ZueT3=inUFVi@+Yd+il(MR48+O!bfRku_~U3n$%3x zG8OuBJQGS23iv1l_gift-3LNTsB4_v=Ga#^qHQ6YqQIvQP#so%9I>F-RY`8Dv<SGH zUO*fdpeL?@Tg16Gc8ZEEd{upH^Q3G?3wb7tF$u-;9JT_r2mSxqJOkB}toAU|6js!n z5G=A<HEbc{`LroGts2;#xN(u?mTd-?7U;C?I7u8}94fv-9YY$~2)a203?V~}si48c zHl~82@{}oKwq|*(+UyYbkA}@vn%D`s27Dc%{CVq(sHKD#cLNHV>PY31+(|3yk`P|U zT`X5oZ@8RD!R&H^8KcOvX~*hO5fnqVNaV?6xV^Y%X^fkN;Z?ehvnDtYpwa3^EweVo zP6oDmnG~{B@qZA>F9On%wLyID)Yd!6Z++}Ttj?SIHkF<0iJ2G`&YCQ?ZjfqJu|w;5 zQI2_2l-}cqbXcRmH~r^zy|q$b<FY`Fq7C`DdwmtghDqsq2W+IosLfy1{Ge&Qo@Zxt zL$ERfvrJ51U->dek*;#14}v&dZ(&P1^yJZgzFxie=du;Mjbz?>-@_$T*kAnUf#3d! z)Zg&qdTg??_@A+nR5%CB8+iKWP<L?635Ftokk+qi3?JjQI18s>X6il)qL3U{!rl68 z|Fb+5MfF}BOU&GRn6ebgVFcJr(oBTKUHa<%9V1M}XOfyH06g1@VWGKMm`g=P2oTN6 zV@KyAAzY*V-NV<Buv*+`Q>sekE^G9HW!h|tE+&-WS$>l~tqN>Z8G-!QlZ#l%Ut~Bf zk2C!Wpf==s4OZu|(;6qBDFxm+q%K@k4sA~6ZsYPnlfYjY98;yP_v^3<yKp*|zKEPv zSuQRth67?305hK~kl%kKu^&0B7T&?l&@^3)(8Y#cZ}6%bVVI@a9HVOYa<<LKi$@j} z(ud&*JC>)*YmdguG9`+f1%=Y8=*pVM&^@q$N7mmI3b9N@x|b`Fxqen>6O7$=Nv7He zt>@obik60OsK(}7PmRI0mEZ|$TVboA2J3S;3G2|QQLoL3xtp^XfO4^0W`QI!<Rsei zvIod1V`M$cxob$3JL$z?kQy1lYj-1{@AVj-{(Fk24wA~#9jm>q?9;nU?`sZ}&D=;@ zOf?5a!0`mpu#J5!p+2piOZ8Xa5#xcB7?D1YmC^^~5Hysl&!nv?7x-8Sr~hr}urUmU zjPbCFNF`s@ti@FY0u0Ovgt;oas`4!9Wwp##42r08&A5@ftm&^ZJVBbsySl*9(U>li zo?Z0GdKH<uYuqI%hoA+l{TRMRDKiOXhZ1x<&7Wl=A@fNkCRr4ziJ5E4R*pfxfIBVy zSw7zYR>F8@({PTsnZKdD!D;OZm$19)(_#;fV=<c*s~M}A!oZ*iGk-6}o(_OL#Hd#V zSjiamVaQIiR8P?KG`~@+KnksVH$_T5MlA0blW!VQWD~>XHpHM!r$tp3e6t0cg$5Mu zcw+(Kbm>uocKXm}o3Ls4Ih2a$Yk#AghmAUG0esvd)|H>J7skpnQpJ%`P;TqK0sG}` zn$oa|hpcsHXad;{cRg5$RnYt=yiL=>bTt(0vZXQZAI%c4OnS#%W(jwvUK-8k-8BBh zYuUTz%0G#X{PMRhTq6ECc<tk(5^dWb&1xXm)7i=Si7T-W+IYMk{;rdB_GSlaQi)u9 zc7S63cF264&zN;Nqt8Png9ZDr?FPUXN=nVVWn05igySe@en(^~Rad*eCPUY!wMGwW zM*d9iF}cG`YY?7ob#{=kRM+Ln@7wSNGG3bgMI*(awcR96Wq~%81<Xcsc`gUgDSvnj z2r^cG*XjKo<JF^cn$e}S>8T~<9qtf53#uo>npNT}i`9V*%PpX|x)UfT7=h~#P7#}J zI+@gED#lRQOH{8>?B(7ugU!^=2ZG`~D^nQvSbCmWU%sq=ShT3RgrJc%_RL%g6TH*P zaS1t=fA=X=#3pL?E&DYP4Y=Kc8)37pj)(kycj}M79m!py&H;H0K4)skS4sX#1DnZe z@>0W6VZ6fle@47MPc}<KR}Jy+rE<4E!;O9ZEg-17gwj<JU<Y<gJI$qMwJRZWCKCXp z2Ip4~X$6-Z@*27`wXd2{{8NK+*X|^1m9$&N3gf}Kh2}$rucK2`#$ZlJ_K_{HVWNPJ zWe}^>Zr<dl<1o>++&~iWxgH6<UBAL1$0>xgDXQR$MnzdEL3uNCwlF75f-Et^7+|IQ zwJfXf9dv+YdqQfTK2WH?UFK+_lY6Ecu9K=<IOW#tY>9^4D+a(;TN?@(%6syLRjxDf z(guamLYK+SVt<}1NkzMYK40qLrmECp(Mjd#3KF<;0wtHL1U4NjCaHkZTL<(IpRIP_ zFv}kv&9s9L8~k;}arp_riDl(;=$@o}6%!ap1&*;kgIR48;@oim$JDNhsa#*8=iPcW z8I6bfDXTOyQ7pw+NnUZBAp_vwiU~$@0=wurffN=3A?vWV6cLQ3qtA0a7NDDBfL6o< zurh@Kf_Br2<6IP`Az!4_izDKCRQD0scdzVW!Bhz@+dlM{0w(;|HY&g0LQf>hV=_zv zJT-0hH_M|psB|o3#%LKuZ2pI>Sg`MC!I&;vq_927ZsSKcGkJx?&Ll@N=-X6f%V=H= zfZX&OO|{E0yz8-x^=##?GavcIg=bcN?Q-THe{kT@tk`uLIrBV|#CZK`j!6o5=2UkN zUc5e;)$m*B_)*R$6s~Gel}1~yQ&;j!qOi?s_~zo(TJLsh%SKE?tCn`ih7SZ4tvL>v zfB?gypAiY>Ysk)(w``9uKrZ*}tQO^)cHGJEEKyMY2eEu@_U89z`X#{!mFLQAdJ2!V zT@SxvBRq-f)HB!(C%;{)QYN4!<U!b21txXT<NFY}hJ299jzHgwX+7};g-oNT7ViM& zQ2fy81Na5Ql#nsVtJO1X3yXKiq~IWZX|FlTE_Gcx>zUbBw7YVc#g@1SENt6r8(z{t zGLe0+WdRYw7gOJ*kZowj(su5OtVv+i9vCgnNm#Cg3AF{h@Tlf3Ck9InU`@P*&SeUK zrt2vRvu1vpYjhjD#$0t2n#N6-q?F5GUu*i+yVj{+s|Z+v@q(KVZg?UZY75ut!P@+S z4$tGFGQE(k5Iy<jt9&T+Jv1C#;dPYeLca^`?xu*U4}3OpS-xRPm<;!mHk=JNAl9~M z)<{$o2GccW?NzQOH=~&rmwSS4a+iLG+S&w>exorNCN5BsmtM=h)eMEG;LS>mr6w!I z<Y^5Tvn4O_S5*#L7mdM(2-GQ+a!I^CneIu%tr`rQ*D$Slvc|)#ggv&=1hkZ=P?G@G zAB3;fa+#3EYpcg~1K?wG7U1Wot4$mdjdRdqTsdV^x6329ejcwwgWH60fV&+ka3`>; zGV^Ow(`HA^&|M%*?@W6SX!Xg-3CbOmS(;(oY-BS?1S?CY+?JIlutfwLoFUgYKr7Y( zvtD^t6;Oj<xVqfCj_Y2th0zpNv5S-?z*fHAs=a(BZ79d2h?1OAnn|+_ByyR85StV{ zTGc==PX%=TRST+VZ9sVlO37I3HQ|dFt0(k0E5qkon$W-&X{zU5IxCXPf-sy5@RovW z4&}A%o6la*X3h6%Xe~F&SG$8YwtWnnwn?+NC2&k4)8U&B734vfLZ)$V_>A1>`;TkO z>=ux|UAF}<u857~cCg<*^vtc?8%iHi&+4@=pJ@u;csY}K=tF=xHu88rGbPS{;<ec7 zyVwq<hW`rxpnS_)(xwu{ne-d+YagdnK~ogG$)K+f^8G{~uQ7Vjrx?LJ5g<;)wC(<6 z;uo^DM^q3&JVP}tUp>f>Tjn~n8M2@!@%$|pK0{CrW#8c+%>YBb4o~<7;nH(-k&Q5} z>RA~YvVAqD^<ss@-)W?3R3mXgF2|CJ%t~a{(4=2t#_h*#Y{TsJ6Wjm_DBVl7nF4dX zvfI%k3A<6hz>=9?RM)0DFW#LqOM(HsRzQ1+sb&z-sArohR)(+UO4x;at4av^&IK;i zCr{f5-s9xzus!7dzIIks9D5m3EVF@Tk<t5A%&=IiFtI}0m(j+Q5c`8%8#W^YD_K)r z%D<@%7H%}Bq!}c4=G6iU<cGcXma`8`38r3Kptl>xeSVdp!pr2EqMEDshWM~G7yx61 zQc3o$AdPZ8dA0uuX}7i6XFhl{^o;a#C3w2)yo=^@ug$T2<II<zGZR6yL|*#@u+P7> ziBpF`8BXM^5qsq0o;$Q%F|to}gJBz)?3QpCNFgA1M-N``Cv(RPw%jL#dQ>@ApXRKk z{$a^fc+-mL%@O;1Z342F%iAV8%<svQCQHk02=)OfvlYZM(;b?4R)UPjurl0s27ZCt zgXJ{MR4u6$mt<|kxmHDJISs-$;EpRdR+e1>t}8Z@jlaMG+~-ooJLN{O1W!$1QZG)R zIk8sH)w0QNkjdL6UT64JVp*_O^E<^dElJDrv5~2EYjEj`U0j>+rL}iWhF5L5cCG9! zV8L{Uf-&J4F<&kILp`g!Pe!)`LU8vmT*;=?0RYH8O(LIf9~TDOC8B@N=*L}PKn#|k z422LU*hlNml-r)gRm<sf!<e6VK=P8`rh0;V@66Z!-u5Z*osk(2`9oi92_?}4N7dZ+ zRqu^y2dA(pu8`EGW+Ec?dCfD(aw0Kuw(M)USFrS`n*~&K`G%VXx|AGPH;}>+_p2MU zGbWWyiF-<oESlXBUJS;DeibVPe(@z_ugnQEJQyQ^kNY*tp>cV}*e-PrJ2+TtUhmlB z)>HWphgR>3GJHcHExi?gXcbA!=<R4}Uc7W$s&b_DZ!`?;rXSaS_s?qYYH--cc#I5@ zcjsR!-Nx*)q`j&GD8`k+k6ou{vp)Yp8!nLrzsz#DaN^i0_=i5O>LD`(_OOrwT|Q!# z1y!E$WSDHFxb?fZy_z<Qb?U<dswT5kS*_ABdnHR-%|bEBNDa9dMrQYraTK<Gw~zDg z+<9O)N$xFrQlV>GA=c(+uyh$uf3;^>8_5|kp~-7BvJAPsJg6H14{gnq&b&DlDtha) z$lMm@_kP&4u*Ph3jLr{Bvuj2MN*VeCx0_Z3g~9NaC&g+e+?(()F46hv{T+J9m(8Y# z2{SDw+vE&JabQcwKTb+c#TCt2!3A*DMuZyz|H^A-+69UK%ap;9i7&p+>4HjDIROB& zxxoW)?O9#Ym4y70Vybd#VW=<=#5~~GxzTaP6z4d?7|4of5d}kn&EDd$`jZdJZ?L?K z0~fp!xYQmzVJI|10_a=HFi6+;=+}>Z5-VlhFp7d6Ufs;znR>=exa(E2xX5*ry44j| z&u{o1E%}VM^o5N@YqqVI_qT<FCEu@E#M3_1j@{G!zy{b+t)=JT<-w<kQPqN#MNt{E zJ@KXn_OWO_*mt#@H!-V4%pAtZNRA$IPoYY@E#^M_eXI3Nj?OKcB~g-1hd^~8t6lP0 zW=PkCRsiZC44VhI@I0OAL{qQAL@8-_ZZ*g2a(mHYAf4i19`6mUBPMHwm0T<Lf>fBv zRwf4n9jt^6==l?8XJlXS2W$Agg@t-OJ4J4?e<&fxq949leZ%kZ%Z3acw*-shleuGt zGkVF)43dJ7i+h72_r@569G5n~K?`HHT%m7sLN+dNugqq9;!I#2$vv;3KuY#>ai$`7 zg;4q{y=iuELkugXL7lY)BUN3oYJ(U|GHb3KYuFTbTes_Cxe20lcq_5m6O*SLOk|WU z^40jb4^T?{ce|Ev)6GPNNhER^*cZ*$#m#7eF&fP^Ybt`^-bxB_)ZA*5<guE@rdiG| zU5%I1Dmn{ExJ2r%Iqq`ec5&oTyd13H6S>{v+3&QNBp%B3YJpg~Uax)ae1pZf#_l?k z{Ls+j`I8sE`;rRIe)UJ?-~PxkAr&l20DsKte#f`ne;0YS4>G9j=6OA=i#cxI_XcEX z*LXDK^+87OHi}z+lwgKih6<Zm&<guBG6NBevi34xz|0vtaFMi`oC#^>a{Gs~UoQag zXOAR$2B~4|U}BG3i|?v-_SWT0A~kj55?(?n`88MtH+P+mKi+<ze#jkWFFT_wLpOvA zZ?C?I9_88Kl?LL}N+j&DhnHNqD+?!o<=plsWi*Sx%cbzHJlkuVq2TQ>70Edql}kp> z2;sSX+)M<_j^kOc2Ie6RcQmZbVp!t&t|#Fvh-R7{=3kVDym0O*W$pOfvvnbRhc5qu z`XTS)y^{HY+samKF+aN{@<A?YZgQLrVRUkik~PF7u;lbqVDCvh@l05Df?_&*ahWD; z{P+c{Yt!=PN61Mw!eiB%G>%%57)_0QoN2se8Q7!22Ji@i42Sy9Yd8dXJDJQX%b-?Q z776E(FZ71h_fAGW^#^Z`kNB`-p9mtr+p6AVtNhfRf&8KQD9dK9%&bKEx}~0tHo|`2 zv}K%5ee9E*|C)}$d>GN6(Z!J&)2{AYBj&bLbeur#=|M`*(3yHn;v`;0l(&mhG!YX{ zo&pHwALyk_fn~01rQ;-GIeI+_TLJ>(QfQb2j<LHG98YVIIt$DV<nOW%-jz*IrBLH? zuG0*Ne$YYvaV|bN2M<+qA(*p-pe)i$?Mmp<&`yVRLk9N{eJ%f=biIFY)c2j{sUNg# zHwd%1Q9yf65Jp@#Mn13_kI&>12_d3x2_iLwl~vRY!nU^CvFGgg%%$cgGm=2UG>Ric zTQ(xewnYn@37eDcc9q$G24u^QJ<*=jC>i2QO<|{o*)VKvT$5~NQZsw^dfuN;x5&=i zA0d*u``cg1())S8pXYf$9~=6q`Sb7*uJ`52GMYJl!(KwkR8>wl$N6nYsHP>=`toPQ z9gDCSH0uQa#hgo`l?PywdEO7IR2gSzHB}R<C_ZVUcVR(rre!HTE#<nho_kmXMZl`> z3Sk0LALo_%0x3opia8@%*UkLA=~{licN}tMl7IyY9fmQ-LU2kAOAe~d!~BdZjeS+w zr}P=&VSTU#l4<KqyAi60MGKmiJ$R`&3SGbGoG{ke3yGphsLrly&G*NF3hHgPbE`ik z!aD6dd(3?A;F8tbpw(GfA?SLY@d84IYZQw&90L?Kl)7Um0)uSh42KSvD2g!<D`jAn z>3by*%J|-$V`e+b7Gkl9Lk)b5&LLcuI~UE|V!yB6zKOE%+@@6I#hHazYfTw+#i2j> z-=vED6@~fBD?@!}<6+`p@ch!k&P5YsH|~RTuvLqr^wG9XJfxilrF*9?O*ukVX<^v{ zt**LcljX!gdw-efT;e<ALAch_30pz`OILa%btiLl-Z<gKk9gUDm1wq=W0dB71Ltpy zzvNivT>H+#QGKz%$&G|SaL2VhJ52<nP4_j|nT!>L8`c^JKoC3eov9G{;(mP??qM&V zF2WW|q|=he6`6mzDD1Ed6v%-pxQ-MScih$@vjykgS}AAQ0#5p9d~?kF!w=WG_r{qf z69#)A5FS<Ix$)yL5>OrDIGC=)W{@>Dc87hc95gZ_s#wZ?h9HLvb=)G(yhml+Q0N0c zK`bA(NT+}@cI9Tw`}Qs7<f$?K9`|qk*R7Ev%S_GOz9L&}e<|DEalt+sC(+s|w`Z5} z3+C52D0CE3(HPd?5^xhW1Fp(+PkhcX*Xq8XSn7wBdnS@tuS|#4f-mTDrqV&<LPUrV zj+@*!magu*;z~Gm-cZD@EUAyhi+YMX^om>{^;Tg4gv(S|XzHT<?J+7?EjLnv4)Dk= z+u0Xyvx*2=zzg;5K*<ChGAMz4qqqlmSM%iPqGQjgdjM{cpJ3uO%UW<u;$9~4#H%T} zf#`uDi0A)*T4q{RT1%^XwqpznVf=!5C{)XW{;>d0gCn5i^K*g0pzvde8{*IY!BN^3 zNo_r4qK<9X!|~IUGc&DGxs9aAbhQRHT7le%^rQ;xDsHHg7fTUjPUc?~Rds(G#`tQM z{@b#|T<5(Y?M)?`pC=Z#!;~I#vSDnXvThWUY;<z3Y}2FEy}F?gMO7GNNP-p^&UHf3 zhHH6u3~^Ln<<{seZP16tIYdnif+e$N4{j>x{l3=EuS?S{o_rgDA$yusKnP~4IsLMl zSSNqce5<JDu`CQ3?U3(^{|%Tik8bAT#wcP%pRR6!J2a{pCc<<;w+5&3T&$?=@n4i` zIK-~?%6Ts$8ZDy^|1eFu3a`GSWmB`jNAX4CL|#^3&F$!aOa~_TsemsKbVJR(29y4d zYp!Jqs<_f>go`tKly$`>sw=0@kEO%YGwFC^2Rub-A-Q_p`SOWKB+{SHh<%QP%Tol6 z^j_N+Gl&`MuNh0nADh0!-vfR0B!xZExeX?|zWlLY{IQD5Uo1ZM55Lt?*8qJ0zfTvD z0O?Gjk;jaDfEIqZmI$*TMu~~0R4O>5>W0aelWQ+ao=a*AO|iRboU2}r9@~L&0o&X) z7-M`BR_UelP5e<Zx5u8tQ)NoHUaZy)D?>M*fK8c!T1jj=j{Np<qx`#|2<{JaQv_#l zoZ-GuKyNF%B6=&gYMkcG2Ybru20Rtfw>PSKLsV~DB$t8g2e=DU8=JKieV5u;uMR5a zQ7d|v7a@Fmo_<(aJB~9>W5gpag1xt>&xf@12&GrL&`BLk=GNhS{I2!CEG_rQbU{^h zHe=3@G%KCygg}7*|J;vw7N%~Q-CUn+gtIUqbQ7I$;~QqnNKnX4f_!7fSZd2eU$GNU zTy;y63LhuzC=lI~uMo+#w(`a=t{EXz%KoP(aU)CBTjGV;+ACJq%LQU6=e)K@P4=0* z6hIl&ti=1%&Ca_1Ta1URk}%g^;!}y|=^1s|D$z|WnE5B&rTXa#bFt<QN9z#-&sxTg z2nZVLsJ)Y_zjE7d@32p(YwqQXuFIcZU5uF!i&J#B@r&(YMn8!6{7-|MlkH<0H7Grx za?FIkZ-{>>$5h_GgcerHj*8()8e)1}{<VBazK%`Kx@aqn)E)Xt+0n#`sPs~lAc{xb zbBc|15bC-@6!m<*Q{1suGpM2gy`%Zp%;`qQ{MW{OxN0l^u#9)*@|>x#LSd-mrN@RP z8PrXTQl2)*0!Kl&qTQ}a?N;;jkX7nZ(MIm2*iH^!<W`JnW^02`p-O_!1U6J|WsO4` zvk@p=FcTD)owL<H@eGm)O|Mh3B{Ai$QuDhYhE?3N{K`#E^%Kub$q;dnh`18&dPx>G z!v9(7-pdq4Dx(#<cXFLp=pxB;YNU-sE`%{+l&YpRlPy899%<L`!uZmeyIN_T_O!3@ zgRJ7Yv&y(75er4NPO7ACi0bUR>w}$?{aI5QBTAE01KZQGin{B&WVOWn_={a~(^R&S zZ<i|WmNsm>Fmp%+Z^Q*ur9XAXxy~A%#a74RQVTs&Aojx3%hYApAdk#%og6LfQ(Zn^ z^SS65W2$3K%VVwe+iok<r=w@iMc<D=19w*72Bpu)%~fJcrd%hTW*7;t`|NG#jK5fX z?jQc^yBFw{Il@tPH8swv+;;M<{A@fRW;(rdI!~Ut(j^rS@j6iu_uqMt<qQ_^rf+t& zRfkSY-*hJci2#wd_wz#fz(!6!Uzor}H<65D${5%)HFfwYDR5l&Qz%=K&)B*q#K$P( z0^#Q8gI(0^eQ$Ljv3bD{yL2c&)N5PKw!5c|VtFbcJ$@~AM7V%yP8)J6^J-cxXj1I& z>JRo^=vTkXLWZ5E%QD^2hP4*zv*CZJrf6O^E=2jjs-?UhB0^H$hivm*an=jIe*z|S zEE;|dSFP`Z<ftYqIEvRA>j-Nl(aDLsqc_J}?%iAUN~CpD+h->Ez1jVlQv_dB@9YXP zq{wPtr)_VKm%Gh8GJo|w&}w^f1fttAfyXSevSlNyXKS`pF+7+uMqa}b15sQVSxTUI z%lXfi8fiyZh?Yi9qtSN7&TsF<tX(dd?5KV)7zwCi)o<^t@Qt)_ACy{^-Z_?2thJ@m zU#?zq*oE=HiEf@N7EhyALe{6>ZgD0_a*eCu{5kRL+R~ID-<|KFU1Se`GOFRlZ+;u6 z!hIc*MI^{5%=?4<{kki!SOyRPB-#rR(P4~6C=uPs9MP5NF{|9VWHEa}q=Z~)B|9Aj z$i6~R_q%mgH|cb>JhI;UW7TCi?gF1`Bicv{`&cBhJ+Qn9R>U>iwAt2dGrS}Kg8ytC zzVDnxU7t!VS2^uZ(AKiKt#@;!6ke2W%E^&Z4Jl4V@<ZJ%b@UYENIj)nb;oUxSoV+^ zI(n6a=@@5PH7ew+St8)08T3_Ifgsglw_Had=a`#jD|p$&Vn(HFn&K7^6>Dp2mKnVA z3h%^4p(wxw5yRAd@)+s_k9Qp6Ejr~-hBn4Lj7(^K@L^+K^c*Xtw9KL<N<>C0Z{a%F zN~NLI^-p3W(NrQF8PI2R)|`GGKL{D+J7dx26~=n>w9rxaw8-M&AEfS!@}7Ez2jmLo z91b<zr9NDup4sHe_1*elHlx-P)MvKnv|i}=7)gbI4`1U)QK`GebF$Qd_nnTeyfWd; z80Vsw>52tXG|%yltJ9S4NMvYeu3k_vmM-gQ5ewZDx8k2M%ktWMsYXX2W>nJ022RFW zao5pc-)gAG&Y`C?{^C$d8Im|T{_ns2yOmbpT85l~jt;r)0Kbe{EJ4c~y-3q6QLv{c z9=IRU141{s>XyvTvHJ!l$NE#KhM4Yd(4Nb3M)X<$GtnKD?GsO6XP|$jf8KN)K44*@ z=s*5eg{!hr-s;r#1&MV#<%S61b>_|V&Wj%%T!iuc-kxkN1-KY%LGw&T5F|Kf56ftm z>%gu2bj2y>a^u_|_BWo~HGe&Y!y~fV%yf0#e*HO5c01<|0S!N6|M`NMJ5<l5*5NOq zo`-JkBKjQ$qHV(YmQT_Cf5N6o?i6G=Tha9|npK({A&6^O4sk4$bdf)k+A6$o`6^Cm zmIk3yf>@ZXImUY}WExuw2Z9&yL)lOELVn}sgI#&F;ckxHz;dU`j0CCoAnphsw5Ee_ zuEiR1+<v~*wk%8vQs!pd5`I;y=1ppIHCXm&_<<;YZk`u`&3Fl3q*U3hK^4b=)JOmA z*pg)`%J0`J3B$fvyIRH4wbF^i{MR3%IksIEm<<c?$=C%eidA22HoP+KV`Wb0{7f!j z1p1?I(AzpTnzcRC4&A-ES|5SasW7U=6Fa^n+x1GCWl=^PwBDW)eYRx6vt7UmD!mGK zZ_KB=4_9<1y_K4L#&jT7bUQ0Y{XuVZw&uFIopoTs*I9;ciYyMA`A*F)H6&=vHBGQZ z2#abib6Y9qI5vZxj%YLLLnWt3X{f=qemsX<*Se|4(t;e3A<A6Vj7);A!H$XGV=TqA z)vdD4$<|?gH+9_|9u%>HY>#WhFUvK#ym2MAGy()zo2-X4y)zD|v{R{SDLdNk>oj^< z1)INS%3X;q;d{1@G_5KfqOQ3Hl_f#StSlLH^Y)x}9AoyO+GFeBBlbe$ZzIbY4(zZB z(H^)6HLlQ{iWr6p>6CieTYRhGdJhoRWz&8-t&iesEJWf{E~M&@nQrpbPSr?#&mcAX zEnopIYU|IfGCS)u?<v3WNJ+`V>Sitr?m#!B9^Lzm)nH=|NhPKA{eGAQgbIS92#zK- z%`IxOK_GWKPHEJ4EDe$CJ1RTD2M<6?pOka%mB2cRHSjk&zb!demz&%Ax#(~@-s^em z;gR`msYv*|`f@IOCOcmf<Wu!1hZ^cbeS9rL(_ZZi(Q{k%;EupD$P{1{RwOKXWSAp} z-p}VhKKNI^d-2b{{33Db?eUo!x6DUR?T^2Z0mQoF@iUI!9_NTkb+^kN?qY(ZTH}hC z>RmY}`4RV<8SfmEp;&m=xYv$7WsRsgpJ~%obVCv#Z@@TH&Lt^oFR+IQ%+ce0+Co`P z*>$$)=N}~b;$oOx!?FTmp0&;XD0r>BKy8Bt!Jbp9%sSEnZX4)vahX-46OQ^Qzz%~@ z@D|k#T+ebd-3}t26JL3CQk$5Vj`8CKrUbm$596V$<x_L)X?xpRcF{tda7--^U4Ifj zJF12pqNMg24Au0|i_Y{+W=H0F>Ol;Gjw!iHLH_ec8&;w#s+>Ez#-+ZIrU6|;I{Y@8 z`zp*Kdh1qJ31#^M3wV{@?URJ(w3QJbd2(G{oB5&XaE+|}_MJ)RDpns$DRmXyT2f!2 zOT+=c$XX@L{`4s`yGe?)o*mOgOFZc-?FnNwLJ0&tUG2`ey5?2$NoQiFh$@4EKPH(x zU?f!Di(NH+vV($RYtBncg5&}Bro0FagkKSmL41e5r&4E*lp%V$KndqYaEJJ9N0o8g z7B80ZDt{>Qqi<kZk;hM|9M#Uc$5P7XDpZ$Do=`T*Wm~@T-#1h^L6AaCFD6g4neSA~ zYlgh1gWeog8#=-noFz1h_N4%OgLR5Oy>acC&~f_!w{rEy1^5wHcA;H(eNfd^HI^6i zY0>)u$G}6B#GPrYx3q55`y%5(-^{*qGu<<&VRpP=vpAC&y?R>JTAHNDc;95x+_tXg zp<r8pp+`?3`clPp%;dk(F2`KcSLRfg&7K#WR;70lL(SAQlH}?2V-yJ0Q5tY42G`G9 z2diE>5zz_<^-7Pc79Qae%mA*wyUpn!9R1|LNs5~_<i{mot5b(W*~A;bA|w`?577Tw zHI)o$K8?B){O|(Z+<g^w(z~XO6VZEkoslu2NPgRBpioM6!XjumuIY9vgz<*jUwRi- zlmG!EBoqpC5P;^_#KwY8xr(8StI_kef_+dB!<CKY7CFNSZ+3dSaBP-9WMypns@}PE z&NbE4URCWOE3u8cQ;i*gIa=hI8CZ@=N-*Drym;1O^MTyZuGZ@XP#^u%{L1fOg(VVR zzI=Czl3m4Dt(H5YgjXI}v7p>!Ond{MW!2pN;m!Z~w`ExCl5-oLvdsAPqDA<GK9N@W zezZt2))?)ZhTP#rCHr()p;Batnr&4$^N>g!#Dbwyji;z)RAYz<{*_}StEhPzS6B|` zo(@Onm9lYxU<^4ypk8F@_`S^*r3<r5{fI2m7g6(E4Hr40-H<q2EXvTpd;BF8eLgE- z352hXplT-CJ}Y+dH(7>x<+w<aH5;AGm~(sxlr|)`%CD>~P&M?>ACdenf%ED>j`mo+ zw2vj)<w)^%nsw6RLuc-jYN{$rFRjYGQUP!rJSTX90avhR`D^=e;DImCY^UO1hka5y za%evFWSd%P>#$vEUNY>ZC63DAN9*lKZlTIJy*KJ5`lPZro^Pq6X&@!JL>S;&_Q$Gi z4YtsHI^!I_vsT8*tq{v=_7CcxJbP8J8~+{UK^tqSMvmTaF-X+p%739o4^zGWg+lB) zVxr#EapRvB1SqUSL<xfcl|fFC?82kdJWgAFw6%(wZ<duVCus61VWD;u(p!fHN1;C8 zrlHGu>KfZIWKYqumvmKjBuo2+wUO$+kL*$+w70I3y17<nJS7xWpb9Q;4F#7I3xgn; zBs31DgSnFW%1Ipovvs(oz@mj(jyv}%wbJ}<*a~4*Ch74U)!1p7^$#c5xT1PctoeNu z%^{Q+9H+#Y)|ba9ZC|IQrev!oI**F_ecM=3wU!&NBGbhyE3|m7%AJT%#JxP}iYvFt zS9!TO8Nmld{T<^}#Ew|Ep2_RTBP-noCt}3|b|0$TH1)(E<*WJLDc#&-7%K|KI!d?d z?O%^rDO8!)awN^VeU2pBt^8$`_29GuM%Bow2tV6eH_UrcOo0^D>v!m~!Nin``ws%4 zchq^)ydPsDQwpb?fAr0z#Ny3YD3fa2$v3u+S!ar7&>?>z0$VkmiUmQTH<PPFFLq70 zE5^WSC9H)z%_wDua!~FmdGZn}24s|`!kXzenWd|WSkn5wutd{G6D4$ZX#o(PhBuZS zWQlH{EjI_ZNEWw*-Md@g__b|}0p*zRTutq!I9I*WP0I`&lJ2;=Hh(5tfS^wFrF### z0^hOF%J({!=J)+vlp5TY@?MZRoYVYKcF>fEbJ;D}N3?HvE_x<=q~>%qAx7NFc-NsI zT=!PKW(sC?8NGVugWe<@jMUcm|K#7QbpP4wfBW~pg#kVn_4Ybh`!co5EKtrYe5n*^ z9ErpYa*mwcndVy(X0vP`z7ne{Uy=+-vx+U7T^Ut&ZI|SaeTlC@j_9%pi?O4?Cs@U4 zJ1Z|BtcV;Zh=}y*;wfyK5n6(PrUXg$=GMmSVT&;^@{1prLw^{hA%PNd$Gr}2rS^Fk z__41L>&E-x`V$z?fImdN2cFFPJ==hJZ@YXcI(hC@N^am`JG@EO4Y3)fVg@-X1pB#* z!Be;g!-`|XYZcDyS!msheLBE`4Ah4T^UX1B=!i!*ofGDSae?|=t&88(BF?t!1({4b z#=qz&6OrC@=pwrzU~r6!oYzLV9<PNv5fk&84lXI4SYog--0}sZ(zgshLf*X&#%p`h zoYk&3r;>Uu;x;GUvPqYqL65r%P4oA<+CftiBij46D(rX<EBFB?T>6|(YrkD5ZLV(- z<HCv|Z4*iar6TLv0F3;Gu7WSYis*AV_Y#{j?D=!}n=1K7^cc^;xYwscPBj}qY?}$@ zP97`Dn6dVc)&1X&JV&uBHc$GU%0v7O*yGsOYhAbh=o?ftx>|~P{Udf}{Z#HRElqCs z3k)RGQcBg7Qsn~fS?=EoQ6)_jKx0A*F4zN4iQ<$eAyUPQ^B}wdujOAh71@9R3FHby z;4BsB{26-WP-jBVG-;AW9BwFol7C_4v5^2SS)@NKB^Bbi!7;!^C7C*`!n|IMu#qPe zc(uzE_!1`2ty*<nZjJSU8Y2)OCPaPc0<^W(jl;XB@7L$l-F!m67c+;r4a8hDlqKa- z#LjL94UQ2vdd8}?u9B=RkB7+vrSGnl7;9y?nRjAUQVS~xr$%^}Xq0v;rz`#ZXzo2~ zVyPU^xIIiegp%PY`IT4FVK^E+Y?axHGTk=sV1*inMj3d}`_yI~++in_r~sc6Ft`Id zXnv`(<@!(BOVI^=ph8Zh8Gk6XwEyi|1TWp72$lf9X=?iag?fID2QyqyS|xqIwbp)^ z2!zf68#LIH?*=1{u?`n@#JlaInxBgvo3EJYD0Fq`8{xQ;>d>uXgDoYp&$~y)PL|;? z!KY1thsbTumYjj`egMuT8^}eAN+m=MJ-dEpd_Yw{Gx@#az0bv{<e@I<o)eL~vWIVA zOF2^ciw<jyrD*;mb=PbnPa{MUiA=eLrv7;W!=N-ws{K|<HNhYx=~GZywNWG!CJ<XB zrw6ZWH}a$}voBdCK3zvd*T1T$XK9VmkGtYC)M{!i-WFIHVwx)VWO0B?03}PLDcY|? zqX@E-hh&b_y-pn5GPa1nfy}lersLJDHY%>4ia+$oM0m}{YiNkJTtoX>tno2NXUOa) zFsY}Tx1*w_eKhG!vEe6@bj)}ONh7(Q;=SwL<~rH-u<i8q6F@>^^pmz>?YU1~xW_nZ z1_Wcru>=Y})b?BWos%Y?kFAhv1ulILRb17Z7e6CYAk4OW-B2hX%f2CE`Hh2bUoYmU zq;R_UQxIl_`|=iNa~UW)S19tI+GS$6$|26(=j=!#nDW!VIo>3GxN5;WHacAlJ+;!R zHQ5_fNih+b{P3%yl4;*Fc^58ck|T#LVe3;Vq{%ihQ?*naN(L;bu+s1QW1dAhuf@Nu zVq31=8+dQuN|zJ9d|T<4La8#ly2O^B5bSWh(Vt42bfo-k+d6hts22ki{^q1;nqI2e zpf()!_hPyy)VsbX)*Y9K7rR?)?Cr_?#lEzn!oCL;_3(vSk=2DKUgb~PxNaKdq_Ht) zEFCY=V|max`qaP||5c`F+NFsYaif!?q<K=A$W5Z-$9+fvu%#Uu`Ft?2f~H=K4Ip6u zifCCc=@Zt4X4^ONMMGdiK;8f5ICVMO2?2xb>R+0pVHV3Xmg(ehG2Gc82Lvv#kc#}D z_)`3rJO|^5mS%c=&_aE<{=p1G3Y^$?nsFX0q5$_mhs*%sPtX%o1l73PIen_{e&Vo0 zO$V9@nznY^Xdu3cs?ozhkj_L^z#Lveigkl=8Za)j==_#hCr&_~N;YMXzF5t5=!czM z?T(CY(Wfh~P#+CKW-Ei-gi-Hi(9>GG%_LM^-psT~mz3;6npC%CF0|I#<slVYcIlAZ zzmY_uNQ|P_U?6fwmAt{TDRkcccqgy0x+Qs6MeWo)g;t9>zeBHnX9gy|%_2r*4n%j& zO^%&h(Sr~0#ThDVxXkzJblbLB{^Awu>g(%wtem;Qs?FLih!k_ASZ^N4O^#e$t1B%J z@W*+Jr1hh4;+cKibX*sUSJ9L2n|AbjHN;HC0$j^Tm=?Wz3t+=63zC#w%H`(PWe;mQ z5aG@o0oDH7|0wIo|Mi>o|5))Zg*1UH#p)mDqt3A^d90z~p_l3De+DDNsynNV^0g>o z1bet|uJLNOX^CClzq*xkn8lAa-=|JqM>EkO%hatFeyCTAjwCau<DE`1r9D1C5D6_3 zJ3#a^b+`(*syRMBkK_A!BBTpf1CJQd<2Z6?pPYJmx?#2U1{Y>ztk&W@1V$|RO()g* zb)L(G0$ULV3c?7O8g=!m?GP?B+s^Bv9h{pM-4~_sQ{nAND%NVfD`}C1EY8b<Z$zE7 z>8-Mci}m4d<Pg`h+0;}6zW+@+c;fqpHX*j!?hY;&I{arYtp64hiT2{vc#~13G_3t& z^PlOMKi$#wlz?D`J!>4k$n;dJ?Cg9h6BQokCmUs*aqYZa+|xZ;1TxC~M~}VEmiPMe zS1-^8^QS{Ot|f3^lBQ(IqW62PQb79o%kT5rrD}AAaVXSXlSSoCL_FoU4Evt(-homp zja`I?I0!)1d(<D&VugIWMV9i`N@jI@xbVUE+T4Yo4@3=FCvP1&ER6vQgS?i8DCg1v z9-Usfh_EUE(Z)NBjcU3*K?M6gK6hkK31FPkE0N%AS$2VmW=3x~BY<+>Y{mEJmT9~* z3I0nsS9p{jo}x?9ucxZx$_vxhFE|2*f0Kh5(JfSRvFrbxJrTD_*%TL}xYtW6O;hyK z9sq1sfXE1)Y@?2u%THRXK6Jddyo>Yl7}8!_w@Fb|1eN-GSG-~C>8<T%WM$#f5ng^$ zWXzx`rOtauS#}-yf1!e_y3^w$gHoacfsMv~ucr=Ec*8l0tMt|ZI$$2|YD=k!)`x)& zV>~`<|7KHM#Y!vHna5>QDNBUae*;j7`L7-0wp5+Damx#t)=2O*F+OVK6Y~<_H$daN zjYIZ>a3+eUp!ufm0t>vp3JyF;Coig7+|<e$-d~<`Se#q5vrdC$v*sO<5ik%hhsxXA zesEXXOQMu_Rb75(5i}bVX6G;<3{JQsP5l0Oi|qmVlKpZB?D%v%&F&?@AcRm5H6D{v z)webMR?(eJ-H~T^-`2UqqoaSe9Wir^Yu+)dboCB}hDWYyu>ry-)^WIikEOGGqS0+h z%IG~(*mtjYu1N9Rlwzz|!CKB%9$JvUCA_?xT7HBEUXtgT-1!~LWAy2;J6(tHiFaHr zS4N4TFH@G!^o^-+7dcPQRTWAkI%{g!kcX6~?CWb7%Fji4c6~^j%AI$-zdzB3JMr|d z{uLYS570for8vG_*S;0{`PB<|cERH0>Iexzx$QoZYGt7ZQYMd8d>Mb`A0J#yzpISZ zENsj9w8EkycpAm5KgXKT1T8S8mxIvg3N!if)wc{B&@5y3LDi?1Av3a+`DAM^Ai;A= zMss>+Jn2KdzYeP6PTzcfD*$9<3v<9Tv^4u)V9Zc`rJBO!Z!8vj6H(R3V~4j%0B<-h z8GZ~$6WYy};EGX)?%7uL`4n%;FPouQw9^BXLa%MHQ*0GQKasy>9M`){HM~2tO@i=1 z%r$HhA*XV1fH`MaEE-UiuS|R>kT^6II#c;ec@~}KX`A`J99P<@t=|5qVz1*1+Jrl} zA~C*b^%S<oeXHXwdNbTJ9z;5Z9jnuVdMki>a4m*MW|3FX4VV|Y*azhT&a#g5{m9g4 zNU4C8{Qdg?Q;UwKGjg``_}sSx#@pMnj1}?qQSGto8E#YFfda<ENO38%j$YqZcvN1a z)Y~D6lhQ*S18)vPapCf-)4!WiiW6NsLKNr(UAU?)bHZjZN(Y`w>RBZN;{pZTihEFB z-3j9ZMhS>yttmcD&P83UxJX~o`Nv(&{+cte^lT2P$ggE0*^c&L(rmQ!ePwh?;nrp< z@LNwHF=p%_*FeL4yDF^Xu2AL6H&p(6z<g3GHW#!mAG+BA8?KI=$MK6#j*op8`b29& zB>zdXq}6r}d%75BlEfEgUAxSSw7p?7#O%+QZ;&etaFU^DoG}F1R{Hpx&1%@y<L4-G zvb*qa4X0=c6sSmpg&L#H9USmV1_PS>W(qRbvGNZiPxWl2(-&DE4_mpPbhbuz^;NiI zfr@?+|9V~#3Unv5`=bSVKc<KU)$SmKzn(QdK;SFC@(1`Y!tn5HYp7ZwET;~rNe-eW zvgvP*7~}BysK*oeMwI9v7%@4AjRNN)90Wel&wE?p4RiyI4V2SP8g#Kzd^;+Xmi+o` z)2;PWvoJkF{L1MXpa4IpN{Y3}mLeSkhI$U)%#LoKXmAjfwEPfbO8ghxH=nvv&8dMV z0Zfjc9EpQ?p1zT2+RL}DtJ*|jNK|GM2JQZeZTzDG%M+Z}GMueQH?rVFO>Z4;peWBd zyCIiv?C4c_FI%>NDN!vvRE;BKRKRE0%$z8@i(SmV?+v>hdgEsLv_9lYa%SaBp^uGB zsxujYxLqvldP}HJ0|*U#e?F7x>J>F4lT3%MK2qotSJbhv_j0L&?}<0IZk^^r8e8Dx zc_nvKA1eRsB_&1u)$d0Cv|>ke-*Z%QI`0Uq$#Z+=%uaq~uN>zEMiL7;G2>!{ZB6kk zf0TNT<SM#lY%*D1+;-se@G3V>-KT@MytWFj4~Y%$Go4qN(vd5I1Id><L}mhc7D*ST zCT~OzSDw~BKHHZYL6|5<%c@dSzwha#(Z`rr2O$r64NqSinWXm9%NJ|^Bt}G6?C(U1 zB>%to={>zL+q$E)7g{loS0NGnuB)T!d%^-Lc9bQkU$WHGqbpkll}a1R!s^&N;?aa1 z%G^ZXwe~xP%s`V)002kWxWys4hsL@;qfTdFjIQI0`QK%Vg!;z>D%BKT=d>jTV1coA z9C3CFJdlQksj(#*o<nXh;Mgp&$RRT3o;(As{{wrT6?kol>d5m?@vs{~^m>umd2|Ku zG_r5j>ja-AoELIuZT$I%jI&wcXp^j}t|F>SWl<mUn-A~KAK6mH9(JWxJbT;M6|5qq zwDdBL$?}c2U!|W(S37Gtg}<7MxgOgPMeVgSMsms9_#B8A@$SYTSwl~a2V0^xQ^e;+ z!sxQD*_W{32N6Fkcr1|+n~r$WUUk2SExfS@ykpVMq_^Y{C&R_pQn9-dQAmeGdiM)~ z2DFfTMMhM(oq2fQE~~#;{MusdRoAmq904Asx7GlVhped?rTAl)DbqFJ)TzUC_>R>v z!kv1&Nt6pjy#1R9Ivgm{I&{A%qf~aSx0}g^{{s{N7nSo^8AVraoRF{P8yhH+Z13lY z&k}iWf-A7aGoW^4(nPf7B{AyzQcX|$dfz5}Axpo{Js+TpmexvA3JyZhh7P;Esh~;@ z7KkqbI92<%?JhcNY@E1AI)6`#dip>&1>LrP*fkoF7TOa*qokISYFGhlG76R5mZEnq zY^K|kaRo-l*=Kq+pI8m|YA&4s6}X{HCx8PR>hJyNph*Go_zE4i73QxEX1F_5<&x}a zJb4}hzJjeHl{gh>bXgE%o?lqAVIG!yQr>t;1(9dlTR-U4kCiXjv01ZzzjKB+=L!U4 z@j<SfIu9-|lZfRKD{mf|x@)qp6F^A%6xKz;O=@mi(wrQ7WriwzI(qpa#op+qMzQ8V z0G65EN%1s71E`k@sx3d}`bz1kI&rr?bgLY}Ru!B_3?*p&{le%vdjB#|U~bzm2AY0N zD({0E6J;v*8V__Wm3On{xY>ZWh(!9?9(4|PGv+We)R+Cq6LAQX`~NBS<qEBKrdl^V zwF4r2H(a|gp-{fKFSU5F?GmgGBCU2xF`TPYw*w9?;lNR?WzV$dppiP(PX{50oG*v( zR-`?@SZ7zxX;COXBl28TSgu1Fde!q(x1`y#6K2kdcD0>F7}bK$^aMxM;5Rp~Jk~>= z3(%`;$9N71h>lme4>5KWR{e@|!=%U3orfk7igjfy>>Q>D+XAuUNFYNBW)J*4EG@Bv zghjIrqK5VSJu4~da3}Xm;iYM|ns3r7jlW$3skIu^dBcViA4dpeG~Df`3^<o6-8YAb zBQ%@29T$+gc`iWnDCfPHAT{OY%%R&?z{=<c`o=Ci&g>xP=xMrnPtM?bH`d?i`nR`O z)|Lg<0uD;ky6`FMPVIHC@;IOW=&|CEA+(5ZUbljRg1VsB6@oqEZE!nYKP}3(C7aD% z{IaVq7LDj=n=TB1dJH23LnD=SYj%OkTQA2;GeGd<T5`AKCx`4f@Kn|h0u*v>203QO zo=n;H^v&kA^Ife~Zz`zUor>@#1BHLjZ70l<SugD2S5FwAMN<CyUb4m2CD)D~YWDWd zvp(C9)EKJ&7|FQX7{-MZd~dpUpu_Bvc=bRoaSetYNEaD>NKvNb=NeeIPDGpIk-#IT z31z`EQ(M<+w)T`b6no&*B>i~g$@ZNT1<^F|NMy$JT}B0GtsK;`U>geM?bJ*${yYoX z0-Gapt0n^XFYrQTr{v(d;dbyzHroqSY4uvDp(ZM$75hx5PkK=YZ!?7%aLjwtq*=vC zAFfZSweG#y6@52+<Ocis{z|kDf`GSSLeMY{h$FIprY%=xV|`KJ9UKc%?{uaDwO^bK z2%r;qRr?2oJ6w|=i%j(mm9qbvza}qE++&ed)MgtA#C1mwf;VodXz(I6-Bs6XyotS% z^6E|PI-;D8ovKEKmboVWi)n4%hV{-Tj9ubC%W+$FqNsBnc0GX!o)?6W5;=rCzz-%U zx*k)G!w)IHMbnJrT1_E-WmTWjhYSn>6a21O!j|F$^paV7ov!B&O-L*!tVSe?3mlAZ zfp?!{|MMUwNPwVg;>g<CyK-~&W%9bea!X&S5`lBRM&6jpnsl5cestHaL#%`%!vYYH zQgblzPKaH{Yq=U^4|}Z|B<e$F&dVODA4t79YDjE}ISrPI&*)&Beg@8dGR<#ztZ5eR zo()x?NHGJN6`TnuwmVq{a*(gXpwW*nePq6-=BTkwpvafDs*YopKmFLRAZ8ZS{=d~~ zj6TJVuAZWwJ~(gtsD(8{Q*-qp$Qa~Z{OLWAL`(<NaT^&(3)dQyGP-o~PLq-ZF3}X< zrHsVpsS7gPP}K3mKk*2u-_;FU@%oS!a6WiYZU1+xAJoYW=E7&%kgQ9~9w1RM3hxt; zspnTI_!*8y@D%=CuS#@))!|4QZ?mMF@@$U?Pkm9=d!{Z<mekX5y8rm9mYN{>Wyhq& z=F8;dB0)%y)jU8rx>O2mG?aGDJCb~_KiQ4pUT)9(S6iumTXav_R#P8_w8v5E1>MjK zw%;Va=QHs5s`6W+5b>2L7C~4gb^II}(M)ar{m%b+iusH>|I~wShS;BP`8@Fk3_IiP zE#jECrW*$IQfy4Rc-?oZ{2@IaS!&%*mK!Jb4J?fX4R`O;AYm(1zcl@z2VUldl2LOm zYjLu2D!z57E~i+SomR`0s_4&PXtuI!BY;mKa9uo=b`VyFn(Etjb={>F--vt-0!7Qt zQll^GrrrSrz4?3A-J1|A7&+~<2;=V+9CPv7<pO5S57jVPA-8J+2A<ZLJn9k*VEn7s zXp*7DFVaK6)~W@O{Rm@4U7$2NyzxRZ3K_ME%JceTHRA8Jv`WP{qt2R5CkO+lM@Qft zgmtG&h7F=5Q^e;PA)fc%_}Y!(zawEa(ExhXQ^=8NCBP0L&%RxsrSkRQn4!v?6o13= zDS)G*zc&}s!*t4eYA_JUQJ^fP3pS^Wf-Ah?Wk&nBomFH3%@}R!te=3lflXSkIf43* z9Bn)jQDG+2HdJsX#ZkR^Yu3WPsKqu6*l-}$2)z4!1_%`+86kwALKigdsMUXHX^Lp9 z0F?lN!HD5V7b4UZ<0sY_rSHm-u9p7_H%%Xo1D^`kP&rL;_q{&lncA<4epx??1Hprx zfe?`6sy}l@+|e<4>Ny{h1m-6WE@I*_lsmn6dpf8kQDdA`$jSCv<=);*I$7VbYfPEd zMBuer-3_;B#hh619RZSFUitu}0#P7;mQySBkr<tPqVUdplYVj5If!N%2ABxC<g;&Y z+akXv_#uA|#CxXuaDg1~Qd-NV)6rYoo@=d(W@cufP`GT2wbkQ?sM8kYa!=DNZc4}E z*Vo8S`3haUX}J5QXLH#?pX@h%W3uQNPC@hI0D{ZOTM7Xn^H>n?&K3imnRH8Q8JN@9 zS{X7!5UQ{t)`)nav9z|V&P6eVhBEIf%iLiVcaI%h2G77G31UDJpK83|!gA^}IQ+Y{ zxF{!j{@=31S1(_DBwaj|{ZjS-CrC6ZxZE_~Hm$oVUWQt40`O75LxM3@8*}<tz>IjM zb5U$Tdt~@AF+kB_$iPMu-RwCOy+tm$I3GLuUG985Jzf!*lZt%l{0-8`ie^qxN@&Gs z4!C!0y9(7omuA#ZN=<h0bnkU<zsL9kqs#7>Xnbh>n|9)_Irh8vtfZ7?5D;MCsgoFU zpot)WHobdgO1=0h5GkKOG40B_rIBIT_zHA;WxSd=M!ASs?*e-8=V-}F>_0lPkxS4( z)M+3n@7<W@+C&|I*3oJd7m&yR9mOh?slz0ndnW1E5KfL^l5$|NyUMls(4+!y$d@=> z`+24m(s1PaH=r3lE-gULPROX;_K1r`*s}D9ZcB><y3N;u!<hN?CJZJE^t;-`!a-^0 zxF145pma({_31QsIr;Ukq0kA5DXFx>{BiVMZlMTDOfELzIB={tFE;iVf8r(Z=+9`1 zaQTeTOhr_1+pTEB*58wy;9gQJ<mnIH=N=$1rb18gD_?{c-5#s9POb0+lC9oq@VIyl z5{QT16Q5PCZxcw-R8U`~Km_1th1O(6RPn6xoG7RvasQ{XY-QlEnygXMinHp=*V$TO zpb+mO>~RVS#P+h{HcM0tBske!r}$V<*y6WWms|0N_s7u#UQon*+0IVc$HjjKzt@IO zpC*_BUm;1MAJ~B{G8RddAJm}aYNimU1NQ?1&vTib1v79x{qn`j3JNmRrCNE&ntz8W z*2UA{OO+*(MjRHe>}ob3K~NBEbaP2>+w@-sYUt#Hz#qbZUTEk9L)IDPUgCuI0y3uE z4#=rlmWV(}QCX<Upco&57+jeh(_}X2R=Zk2k6FtZv)&x}R>%`Qrf<6WfZk=tU65$z z4q^n5N-Vm50GT%q=!xzL-f>7ES~P?@Sr}LVa*rPZrh>u_W08#MpV#XR&~&B4kW<?L zh#yMr9RM6SYhqSI#ANzlCuhkq_Ps+(ZTSkFJLu41ScEtHek+w`=@bcY?l4bwLj<?^ z!x|HTXVN>FHC8ON*4LP26L-A)lu$JjQgi!83;UM)+?l#)Csmg&8_Mi-bcHqgNA5iu z#m5QH6RF;I66a5L3l0C?cY`E1CfDYVF-xep=dy>HAG8%~k2lS7fqm1OMG%Y0-lbT_ zChq9nQ@<|v+96E<8Z{VGfUj4&(J4a01|J=1w@@Z(D#Q@tuE|WY4+sNf>Z`_1B2A!T z2LO#KO&{G5Q`vtz`|C?^J%4z!>$j4B^NbSC@Na#3VwKGS%nv_Ptu%8cP5sSCBf`T2 zDH;16s}$Jq)R$h4Y6(ln#j%P7ip*Enb^oc_|K~S6#mHWjCMUQ{DurbScc!}0m_;lh z13$NiES)c*B4m*t3KleWAEAwu>AL8br59}9C<keVM=RloDou&zQ%Z2&q+;z)g~`l$ zScy0;*8oT(*vxQa8b3Ztb<AX7{=?d$Y_{;mec(h|!-<oNi{wz-goQ8^_p6>l(bWk> zRj0PN!GLp*02Xmcq3l&8-?6Wt9H5A-o=1SFa=eyyWZNyby(>2Pm7{yt+>3vodXMD5 z>BkuKFQ+)NL*s&_p@D?f;eS)#$94|SFkjJj&mzI6eTs=nJ6<LpLnDcH(ta*OkHZ7m zP>nyL)NR{i(~O@UJbo2lvaY)Hl0QZX5tR73!ZSGgx4n>bY`bbar*N`vWmJrKB~SdT zj=%bQcF>r4IvtxMR%lX+ubW3`&k=Q(gy5p83`>RWvzn-c)3k8TC{*+enVpoGqRL1o z8GTgs6@ugPZfNqnqWqyFjsyUru>?iM(~HC@g|~Zh3p7*~u|2^n;#wbIQP)Nq=ajWg zfc5+*Wlo^kpVwIxwd+Hlu$SAoi(g{&WHSmuH~}q~etP(;UIK~sCN=*7?-<fU$w3ff zaol1fsq?S#vyhN%3WPC2ra-KhfhO-!XkH~c$eyH$7~m37Vp1b$zZHST8d{3-JYY57 zhp43x4{Vx{giwJXuw3kqM;9&VN|n|e!PG&-uS_}Ab=wKE$-p=D^vAiu0Z5u0gqI}j z1tA9gya*vEs|rW?S14x<^hmdvJb=3gr%#R&%ad7Xbxcx=x^@i)-tLoV=2vF4pdzfR z5lKm+Z|-YH1pyibX5A36brPNRT|wFbw-v_sq4GWg@9)>Qre;6K9vH=56qb?oNr?ng z-?*rs<-Nyvu?-uTH%%j8b`itXs(>1MFYrRc(#a8N0var29XiZC2?T8H_&qPE8H)-| zOaMe?8`e+1!jI82OAtbR_(0=#X(*V8hqD#w77G36qQ~a<)Ni#ENIg^4_Xd3b2n{`& z@{O^v^pUlFBMUM7{nU7vrz8tonhK;WOQndxFIm2gf^IgY`t!<VQ27_AM6MlyHL|On zVG%$P4IHh}RaB6nkq!efMqrum=v?%JUa&+!z-e>>ogF~MrljTuxG!50kf^~O4)yaW z->1zJz%dzW6;M~<vU4nut^4dxQxxmJSUmTuZU4YVlv$3@K(G~QWq^_{lMyTuoc%;V zUzEzMEQeBf8H`je1cr3Vb$UN>4LFK$m}(Va+U60&UwghD+q&<qCdDu`ZQno<{~1=+ zT{<$TUwSqKJp9%1V5h_ntsT(GxD7Q0VG0+z<z{s-@rhtTzErI*C=a+icmLfXxGtV` zR_nGH`@cgu*X&224&Z^}Kyhxqu<2b=eW~uHmEfY8h;0Pur43JMnK;a_LFcZZVC`m6 z;#<%IxVXj(2^B=eGbA)@=-Ftx1Ljb(kX~LKB}<;^h0~af%u2L~IRaF6eFrwnl!wpa z_-8>t@mEUF89q_YH5B&lW9Wqn*Pq;)`prfyx^2Z1>)u_SqANBfz(*O|RI70T25tYF z>()#D@nb~v`jc%%p~KB2TwJQP<nE$x3H<mQH=F!A5$qY3K+)1Uf0uf8uTM*a&eExG zKfA2HMC)r?K)!x?kZ8zC)RNY9d9Et^_^4-uY@fHpFQx9^<U$$f`)cRD?YjS&QK=0S zqKmKKT$M+4Ok+liZbPinCex*D%y2LRB(y$$*|x?$()L+#*3i&0EduS)Z9{d4<F?Cy z|4F<OO_he5;?@Cs%L1OVTr@9fT|>~Sg2ak%2S9{1E3gVRyTo`Y5vf+AhvWxZ2x8ag zuZ-%i1z^|BCsCjk+|y-}#3W_0)ac_fMUWLc6^jSZDMJ2bl=lsV8VWPuLY5DgQXL=X z>0K~eDc;4NK#dD*ETf^{+)fivkzOv~Fg&WzON0VUAZ~Io6RGAC;gjSA28y0$n+r@V zAJeeJFd_&j00A08gowaFv$hE+s@fm!4CpJu3OFdiMvuNg8BI?o(!veNCwy7Y$mAsz z^G359E_$v@7vZ*AEZcbV6-B|tG$k|@uo{`|lmn2^jk)pqhP7(nnNyG_v~~ps2+Ne# zrfI^o0L!bl{-13FS(;2p&aaepl5u9X$YSaFa*MjhZP)nO*192Bs+kNcZbt4=`9u`S zv#RL<HVlDW?2$glN?Pxx4FS+UA1N}#H1J~8-XPze#|sMhGB;6V65cmjZY}<iwU<=w zjdK$1e@1!25-KW<JVJoLG&JmI49@Tn0t~T%U_qCnuX0wiOLimrekP$YZ5U9wm)k5M zZJ{!XrF7eKY#pFASSF9CDLOOiz4n3SH3h|(3o2l>WLllThNVcMxscyXfc_HLAa;*n zVzTGiE`%N8REB!amFq(QVs(8v6Amdtzx@x`rvC8eqrbiPco!^JVfuJqMrVqG8PXcI zRH9MC+4#9*25p0-Gh>6KO?)ILD6Ur0dlm4IwTuV`l@s6rQExW}#AN{hYmRqD0-<Bb z-ajwEAF-7%(V5iv;&#!PxFuZUXo7e`@YXSXM-_hqY1AY4XWeBOr!p=h%TY*IH#I{F zK>GxT9vRA@b*PHh-8~nEui;sIncvxmIFy=Ixl`R3{7Zf$=89>X2RKA^;I&Hd=hV`? z!RHbfTqvefv(Y10eUOGsdwT<7$@LV(7GiOR=>E;Ey=wpQ8s5RpRb}K=(xx!c$e>L0 zGOGj32ar|v0ErlDHon>H)P`N6$Of_OYEIB4v|M~acvLL~{Wc<Lyrt#J6jRAhq;fbj z?TS&qXKc!eg6y5VvERI_CXAG3i{cbwtW;&<N5-N-Pcb{05c1YT|4V9-m#jc1BaBT8 zYbF;f)FDd_TWRe;GDN(m#m>gN|Dh=IL=iadOqN_lht=#avyR@GPmzrq>K}jq-V5v| z6n77D(L9)-*S|7f>y1rSxL<jH8wnoQ5l~DZ)CMJdHiIZOg)n-cj?|2ej}>Q+(FJHG z7@}ckh&^plphX~QO9`kXwv(aZ)0CNIG*?XT<kae)Iz!dk1ZJlHhYpkbtA?^-@>v`l z&!QcKGB!uB+SRy=?pW5Q2>#YnlUi9@w1Y@8iM|(v7Z6D}wD(=8rO6*?(%$hveDj{w zqJy$j@`3h*ZHv9*MCtsuSHVOnxgH$^Udk9JW(UVOg*+8Seb*a7B=LiAy9IJdWfDOf z8U{oUc@zjV1YnyIi<wa*XB@3T=Wf-gkqT6Jc$tU0N};@)=@l$6riy!C(kwc;K8G5$ zfm$J#hW|Cg8T$92Bxy<}K*jfKY*)b4023Sh_VXyRkBm?**IrPw0PrCS_{{~O3#~G< z2t$OJr~o%Db>r}W$TCq?dCLD`E^sg74zrM?4h;el7r3Xd0a(w*f1$6c5jGSU)K$&I zL_N>gh#|Rx6F!vkU~HAHu?_!`jHpC>azlcO-2~=;>YYzu%GA`e*Cb#J@OIv=dJiDu z1oOZkOJ~k0CFLOuiv)YapUkFYak>~O+!I5(*4|fWhNJQlear{M(O+{r#^S9uy;6<@ zk=`O|mGbTN@5gFzJXPRMWoLnx+wSmO{kqo<akvw1+fC_+!bIVpcvIt_bXGN=XBb?x z=b)U<A}$cW`AWC&sYYvUwgIQ$&bZvL38oM*Lt~1v-iWb46xVSAOgKyuHd~l<F>)2? z#0G_8q1)_24#!zrcFFNmIvh}sBBbd49{coTO8M9Ssr}2#I2OBNfaCoX7eoNF!Nr8U zty)^>d0MjwdIOU|XEn3Pof-uWE?$$MF&7HH`=93c;t4$wCHx2!7MxO0I>At{1{$NI zAa_PDsy1gyZN_lK=_c;D5*RFvErhv!zFI4BZrfODHj+lO=fapMIA<F9<&@18EJoZA zHI}-w3k#8w@YBMQ#cMi=1-Lk{@ms3l&DON*c|>YxJDKGSMhFxc!X^f!q3<I1lb2(U z(p-{jW3b2;v>9<_s_M+%s+Zil8mrXeh?uwZfEsq~LX-F=75!6y*K*|C`kOQmxt*9K zewC7j0f1;*&z^f79u6@Djr;r6yHPPpsS|JLa*Cgbs`|55VXF@|s+ijU478O&$kOoO zt*zIee6;%Re+D~V2S+JaAaqOJSWuG`YRRZut}E`zweMmTS~rJ8eqBEj=_J4Ayy*vb zMa5L9{U_U=wK9YN*WIfeM}Y||@RABbJ~6_IH$w$hDwJtkPk<WIGwLJSkT5i1EH-Kg zsHv};n)GPk#|}*(ceRH84=+e)?D)`+A=&w)VaX2E4BJK)8CHC?W)!D+lw|q?9S+Z` z#<az3_l`Wn2vWwB(ZVg*FlFD84Ievgwc4TNYK>5{u=4~qhvXcSvO)JBo78Y%v{4hH z6`xVDffQHP70--H4%JTT&=V9zy$)7LOK)QOI~LYYp?{z)@QJ9S0lT1<qrK^gfkz1x z3^vsM<<gr)N*S%?MTra)6H|yiV2ERvV$UKj8cLv-D)SmRtd;Cm1q}o6U{rR&0DA*5 zz{-8$fBkj3Ej$|rFT{gMTA!*o71ME4x=bkOsV(NB47<`4ab*)R9~5x}DO==JIviFw z{f05=&U^)<lvd!@a<Y{;Fy<Pjj1>KH{BK~%RKFARfq*{L_Ct!HLjb}P45$ztZq+{^ zl_S9Om~CwHd0bP;l-W?l*yInp^^1X_+n?iBFpRx=*3S~$Zp$>$8mZEz!~@~YGXlz9 zK!r-my4(`JpvBChipLqvwo3D;k+SaYfpKW9^cQ3e_#4#c%IUr||F?uA5fXnkC7swU zo9hsO*C;!ZQh=m6<2seQiC=_RYd>|pu|u3uxoOSl+|+5r1Up2~g;SK0g*eO=uWF4g z#YuXYFe9zB6hfO7svnlG6+Vk(Ip&Pldikm709d}jYXA!dBEEVO%FB^c-NhFm!&^Yn z3_;R>2xu18*;m+kxr}z{_!P#gCe0DE{nMAYMTtQeY~8jt-&;U$P}D<0U5CE3W$uAg z{_X#E{tJWMJ%mu?`-K&aj2X%=BKH|K4ETW9Vr_!#{)W2coI(2l1)8Y;`Re<TLoDdX z4IQGd7D!FfrkxfG?EDoCA7wZU4!A%HN#jToAx^7xE?SbKWj{r!=p*7;K3Q|ZN@?$a z9lLw#{87|;l<G4R7<Z3Qq|2uOxL+HucIs#L;_Vxf_;!C@&?<M>faaUgOHenVi@1;k zk7GKAi`;6ktW#Xnh8{y61{7A*>~mAF!`mNPrGaH!NCGZ69VJZ?stF??2dot=S0(Fr z@+=7}#f8;ML9tsDNrhFa+`LnQn7viln&8gZ`*^d5AqlwiLj<q&BLeY77<JtO-Zz<x zLT`J@i3|*B?_keq1|fGK3oO<CLvm5swuYd<CLctMO3!pL#%P=33IQ6|oreC_LtorC zyOrF#_Kl%Wy3*e?ht=k7U#&tjhvPCBaiaP<ZDL5N|Iy=v<F7=1vtn4-p&h*FOJ|!5 zM?ee;Gxb`NgzEAOda!y0y}7t24J)>y0b9h!Kf`%j45O3Z^*~1jE7d65v3OFt1bcTK z23tkeD*Mw8Aj9wIZ5yD0GYS1o4lzX9KE%LM{kXH~zChRXVJWtw_|+5Kox9@JT-0OT zhy5ODYO70}+bAp=%(M0{v^2<EGYkvYL7@SF_GklqnaHR8p&?1uIt>x5Ktb1_0K&wn zZwwa@PO(V^XYdJi7r@}$7c`Ej>`tz}XZF9f%dJ@>foo6C1ZSHsjELfNmW&oO7K?Z= zHO>=7f|bX^Tw?iG?2}Muz>uVYf0LlrBMcu9Q3+djV<_Pdota`G4*OJ26?S6zNsS<< zV#`~lc5p{o`EygEqG;O1vb6#PL11eTAP759VRDio_1}ox>S`9x#cSinaB1rB=tIdj zAmYDf8SlaCJ2@yE_&{JVbt9rJJ9YnY(4%b9Ab}oVmI?{pqOu@h-pOg-+QY*&ZRZiI zF+R}d&iuZ{51Fwg?Isx8)=)hUzm~Z7*eulB*AP9H^l=?`%lov@Auy`EgOY79qNye$ zLEMFMNW*Vpf9^#s<MG%OKC8>z6gZ`6MkJfvQ@V+1huRw9XIG5YsNfs=efQL`BxTkn zG%}blfyb3V|JmFovgy!&DB)_}cZi=mgX%CLORX_o-8h|2N8cAuRfAD*ZpVu7T%Bej zphbD4>$IR@2B>OdvWU8~DMf0FO(ka#OW?!mIj_aRP_+=j<x-y%dW9s|BX}UGnBcKH zWk|4G@C2}Vifh`97p!ZW*9)YyCG7r#pdDJfWOU#YOIL>bv`J8C#mM8)N(UAk;=8aw zz4PWUE^7eA?wHMFuSUN9PaR(lSgk#X5f_OA>nb}H6Uk_2ol=rCF(_6^lYnFs`D`EN zDah)jLve8(>ZEgR=*>CAN#j|%+0&HF)%}B17E?|5)kKKT)IJR-^*f;K5~eHUVB^CO zLQGNtUL>iw?2dgX9JaANr&kI`8ul<aX>gc2+~dw>sk<9rl|nMUFu^6|s{-#h;^pqD zaV!4VnW{LC;7)2kFOyIbj()^Co`n49r3-J|_seD^{7Cm6jJXu}1YdY=X@Af0VK8!* zu9vmx!#3o8A|sbZfPIG%&Y`55xg%&K+*!bh)7XI%BbEd~5hj=Lg}TWmd|c=xTTU?? zy#7mERTl11+Z7vSx-pNGZ3K$*Lb>;m9M0^e%NF-L1PPrCDytbo+`3=z8xuIK6q~B6 zylSXn%E)nU&(mOT9C;Ah4YsYNZnF6{@!g{ON~6oC-`7*x>t1A?Z`}qh`AL<w;e<j= zW~mUv*{}c=nVb}qvCOSdS6Y2{!iOcEu2%m)KTIXxL_yI)HX6MXLEyCPs$Gw2Tcg%_ zuMD)9E~=cVR-?xfup9$k+{(yST~~aV|6Eu2X9A1qH?Q2)JgM6bGapsPbS=AIlU)Rb zASe3(wnYg3Jv~D7OCmkU;DGqBfNV|mXHto^Cx~NWOz_Z=WEN#6VM0Mbv00{#{S9_H zG}6c$#Vn(MKIpM2#+TZS51@gBFStVs@ModRgucDHMiwhic!~D9ZJ=>;hMBpNKo@2% zH=fvvAlqvU2Q{b`fXck~M_h1+A&Y&;Ex>>ApG^pYQ~?$_o-0u1P(xSD^M*!CF@-FF ziQNZZ0PtePp+oB#$RiT(!PLM;;hB+Nbx5TPz)(fT(N=O_F)2yUPOahB21l*2R1({@ z{o!aVe~b(&w>!a?1?^+AB$>YSktezw{gmkhen66<j=l}njQ39+^pQ@I$18aS<P|b~ zCXb>*=Cr<IWSJBdVCLZA!%k-rsIh;-8itTgm}wlFNibPKkl)_sb;$XJcN~~d^5;OY z33^~;^quTqFzKksw(Y5lqO3PIn?jvHEAKVgVTkXYS!Iri;XG1CYd!l>c5c_P1+h#V zI>3+tGHkn+NHy-(24X!2gUR-)@x|z}X2~l(0172uu^wJ;Um8#9(Jr225b*~YpvMrP ziXx(cgJ1Prv<#Yy_&!i10Aih)e0Mru8wY*#BJDhCJOU9dhr1sanXUcVN+EMkth5sn zF?-i@5={7wHRVL%PTZ5>51bfJUgy4r8rwK*{PaJtf&FI}j$c3by6xzR$ts(_|L$|@ z{FzAXsDi9~z3#X#@FAc7m_rh1!}DxVH!7UtBJjf=9>WMf9O1wXg{>M4NSCqkMsv*N ztLP<8U(sp2*nVw(p`7n}k-R>ZK}3_;qyhsLc@B+*4!#QRt#ISaL>EC&@#@Ctb+*X+ zbzf_=1ffl7<_qcb-Y)zGYu{$%)#Hd1NB14p9tcpVvB`|U$JpWUha5=6k##E4OzRHJ zDSX6sIhbv9l-d~J^a#5h!RNVBjPb**kh|p%ivV#Wk8}yFR%cBZ*+)KKi{MJz9y+l` zf_s$Lnvcu9m!DV!LLVFzmA6Ar(S6D41&f7hKeqN)auXZZCa!8|Q&BUCnx7!RZb*yM z;&0mx`C{!euU~oXs8kbKiW!z_Hv&+ZPddGhB0=SkMdFzQ?6a=)Guv0p8Bg{N+c%dT z;MLLj&%U~*cH*0g2xOT2$%_7*1Zyfj_@QxRyDBkM*zlOVQ_amz_xNj#7#w5i3coE~ zoL0uSO*v9ofS=pGz=yyJZeav{075g3x9EaLEDQRX2v3(m02&Jm;KWri*$@^|ns4f| z3sT;B_O=&N3M+iiShKqXGfY=#IU&VxzfXyMT)s1>(|G?dvI^e}<33}LUH^R>U&H_g z*b;mVYHX|^Hms}dCtv}Ef6Sb_Ho8P2i)Rc-)@+eJubD*p$T)z4dL6!?ZE+1R22`4L zA^}{(Jcb)M$&BGObLl1Y=Zg~?fiT{vD6;f>^RJ<eNG)mgBB|)uMVLV!iQwX2CLw<< zh%fP0dZrn7ahZW0odE`$n{m@ZB%&kl@Y0vL)xo8CrGguk-OL7)knN%81P)8)EqjRQ z?)rubCKMPmPM~yy5p~wydBl-w!+djYB{0qSGsUEGgh`Ce5)h}H_ZPnuHPL;ehJ`|q z?>{}QajSZLmT)|GI6O0tKuL->b^c|=Y;WT!$_tb*Ps|eFVSJiiY0CY|89r>d|3#(* z(OjnL7hi3U$>}v<<4DqU6N8s+?dg95tnnj8RC@q~(+R*F6=|3Si+0eZIWgGyy*)BJ zwBM%@Dz}MP?72D$_hs!>gg!XLG}6@z7HP{vr$RnJi$D493Pu(fB#OFuwf0ixGkv2z z62$7U!u)h5PM<b02=pM&iHQOJD>n&JL_n(L&{b~pZz-DFcK#sbxHnV~tiq@#$SK+g zoJ=1P%2Xh_q$48{xVUa?!14!!I4rAp->$IdHNTn20mW{Wki>8HR0jB~Vz!UR?^p`- zmb}7$ZcGR4mG=wESRk?NaHcc86;|br1%(PKa*BuV{Z1OegbcyxKi0Azl7fXgk_76G zaj@k?&w*9flZf_sux^}fU3QIg&)~2s-+~=mH`NOi8Bq8jZ{X&~C?$4$&y)hd9geV< z_y^I+0hj+lh}6$?AU!K4T3o?sJc~QYY+-;*4jb1aXPTn-^!{32Wj`*xy+P_b%D=1w zI@;K*%lzd&WVT|Pb(Gb8mbu7_Gs+avnP*2kY?earCZhH|nZ=mJa1RS~!q90fo`X)^ z2rtq%;_v0fVbQcJshhFxGD%ssg>DOiGV(rJFN3gcpgg1P8AXV+TEdjQkbzCnBqVox z0Mr1YwfX&dfI}}0y}+BY#b}%5V9#2ui<o(fJ03m}u*)~dOy<_wF~ONk<1`o@Y@8hB zt@^M2ISPxEevo39GX(%RyFff>w5iG3&sTr3cEr<W_9U1!>~vz({QPv`@dukyGv`8| zbt;gGv8^=tOpQtvFb$t({FU>}QK&h;dUD&|eVq_y@)^9nVoqaC?W$puGGx=bHlIQG z{@CK2e7ux4O{nh~*fSd|%svJ>NV|XkfBa)7;aBT9B{UJ#h@j%BKv!i9VQ15}>M8)> zvd=7O*8I_y+EZs^3j(|Z8S!J=*-9KO%zs@&k%pc&>GjM?FP*N%{?!VC5GVL`TU|fx zwhzq^Cbt?xRawgJiemWnP0-1}P=qg-q0H^zgIvJuOQ*$`eXlc7zBe=|&Z{B(OWeP6 zt7uU|)RwlMF1B;_teRBiUnmno*>Gcc<LI>2;>WaJ$OT};<S9$YIfe<t$goiU+pCST zDww986ivpt$$W{qXT4@8{tabrO0>ZnV5T!8%fKfaMpWyirVLS<?Ma3{PTxtJe&U|k z$>^bLm-5A(jFc{OJekWvWJ5)Rh-flEgyloqN6|59%v)Z-2eghM&6t*>rvh=no0)Ez z*@C<c;!4B)nNh$(nC2~Ct(Bf|%V^V4y8S!39aWNp4gfjM14hoEs=WpkEB(R@Kn2F_ zusa$Ux(q=iuSv<GN$jJZZN_t%-?(D%qDePqDH9Cg0$U}c8~>Gg@rq)^p-vy>5`cz# z>uvY~9Cv26VI|s{6%61yJpR%L26kKyv(=G`B)<~uzCa$inFh?+lxl1W?%9;Ijq`gL zukNAwr^~_Cd$5p5Xo(Q3m5Kk$b?6S5CCBa&w;#xK7B=~1Sn|8el$uax6@!SI8;WsK zW(KBtsuY1m(5;(W=4=m91~Og%L`1Ijwz9`w-s^0@1`=l`WmN_dWEgM~i(Y;Nz`zoW z8<-P<=9rJ<Mq||T4ujr3f>v0)G3YtG2Q?bXww-LPXA>SiOuB!Wkobs0Ag$E9{1XN# z{YU9SW^w=|@{Cf5*1zY=Rh05RXtEjtPn0{w7!jVUStCdA?o^o>z_63at~;kts)!x` z!$2@OaQ9q@5+2YqaeghIcm|0b>zCrqZD^7FADlVLWy8!reVJPANIoMB5>!oq1I$6! z3paQl^!VFgM?Qh<zGhj(6oe~APp)MX{|#rj8t*xAfJtfZoPux9qT*D>H}BFkf&2KO zFH9V~+Q>}_OK5xUBx!_2mpzWS<MNXGxgkOv8zi&8aUTgS0y1c{@iP<BSX}ZV040rn zYRyBKpXC@xcZ@Zg5$&viLabQy%tLN>WsPCS<;BC_<&7S5hUN#M(8A16+aJOPApbC% zis<&b8I4!WelT;CoYI~NHUL;PGYBgl(dachPKZ&eTw~F~dg(WEC_BKy2VexAadAfA zVJ8-L@bUNyPRk+o3JB8F*SP@a_6>MIHzGOck(vVr$+!IJxzKO07MQ{M8;gxnb#_Po z&gCZJK6sFs>65Mt1nBbI)DQN){&?V_?@`z*<P~$lBdr1H`W!MLpkc1@ey+0sfdB=` zBwuul%^1*7rokC$I}ZT_Jf)NU4TKXOeDikWnSl^gn!5@x!wQXGTStzGIuJ5O&8WMb zy2=**nB`6|WN|LF(#4t1{2iHl%_c5cm_bc#v6vtEbXhKHgkd;$vA8x5d4#YZs7uYj zY;A{EW0nznhD4J~4uMeLWsOC0jG#z@&2DYV+Xy6KKB6BXRGg+AhMqYf$qhYn{v!Mn zrwBjii8M1fuYWCw&pA*0mT_fRkM|Tos)y(*sJhlr{tS?ib>y4zaSa5TSh&^&AyOi} z-1g!%{V*rVAY5@OR%V}|vpYcr69RKV5u^k+Uam<rqmSTy8z2B8hLmIT(=1#V^_t12 z)sB;6u3$cDl9U5Cbt(pG=$s>Vdo0Erua-fX7(o02&feS^#k(vPj$+T%m^Q-in4YuY zqMLq@Ywpjmb!4mQMx{BAaT%NR#i+xEN)dDSzqBOQ10-eat^~RTgT;}DcNe1v8f4y? znmqXugTyvK%4OZUm6WyE#(+RcN{*95$<bT|)HtnQPd2dvtv}w#q$2093|8}dcB}v^ zI20ngCBnobWu|S9#gbFs*XrY~)42jTRD&%{Q;R7r$|s*D73&^OuLx;`(Jp*zjb;-a zLu4r^bN(vqp(uqs0J?!sw<OFIH&<jX7>ZKfhgJQh{%BEMl8ocWzy>?}Lbd^IM)r;2 zEE75%0+RZt^FX33Wv%iJnDB!RQ(Z49U+L&GIK<eGL}Z%q+3LLNq&8dJiAX?>r_kgj z<A;Ly1Tq6t8qUDX2AxrA6r>a>uuL-;{Tgfh$WIkBr@8R?#!u5EW<4N4x?}p1^PTMg zqBt-5cM%zq@hS7oSpo{Zqz*jF%H@ocxv|N@5z%81S?mZ4h9s~B0?s^Y7atk1v|S&0 z^`eF%b}%pCE8u$nxIoO8p_W3kZc*GQV^JI?YLQ!k1+%zfa3m%JuQElZib%rH< z8K4gql4n<jZs8dK9#Lfup)rZDA~S_RM?1<x#<oAea(wTEW+}F7>}d>9Uzo66&8P+q z6#l37h?{G~I`_tU;H-V0BpF3yRom%G_7roX$;E&*O;nm#IrC35V|_~yA*3?r7Q@vz zq?c@O68UZ5!5sDwg&Rv7!7K1<=U8tf-dBzXS<T#;roh-IU#&U^<F>%;A<%>3V=OTO zOtc)@O$sD1!HGy;jZiWJyuq{4{&9@y-J&uk6vh9fTW}e8Jqh}KbNkxc2A;9`-$adU z+XAA=c%Ub>0fL9WU)|maerZAH!FB6F&+Soi8y$W3-OcN&S2NNP?mK0i+}hXDeog<Q zC)b^Axe!Udo@|kA;IupiM<2~cHRt5PndE<Q$J05I4KrHNsyu&Z67#d^I7LH%_A+H- zBVR>3HV(dC$_x(*oJ@o{&8nn`GYbHIWoDFYT_e!ml#f6nQMA*hBDa>0$Dok-uaJ5I z$tUVa2;*bHAV{}&5el(f6V<ofjSNA%aXZZdxgp%lAF|$AGEj$gt3&k)DTB{rTgF^x zr!hB&66w>sFrU2^+<ihrknwXAe&<Eggaajo_m3T!48&U_%p7%J%pALvl401b*>nPI zun7rtOMzGdA|<it+Wm<%gc%88lz9<jBKPEAXv-6+GNR#!nF8(K?#P+Wn2n@GiH?(_ z&70<sQ{;3L%CuJ4wX~pb=piuEtmU~nv>$YMpv4J8?wu<PO0d=8V{;$l%FCgmXzF3O zLgQJl6-EJ4CTOxx5-^<Am?Tj}a**?&&62Z%(ZZ!L{?PmagBRs1aNaMn6?FvC^x$~9 zGt3-@hv0`%K4F_5POkX?Fj#T&+v|a>wiE==r%XMd&03paq+xL>7W);^m3Rk6PhU8k z37TfZ(1N#Z@)vSDo23n}0CSRN8J=94wDjBu2<Y{U-$>$9rXbx1tNU<kmD7aRCZ}(O z`pgr6A#AT`HH049pGRRCv(WRHgd@#ILqqt|Sa&%IAf!g*K+~pr<StBM%`SRnLasFC zqEO~?57Ui%2i6lgJOg@5wgP6Fx+qi32>X0H%7khJr-M*Ogl*ffM4XOxiz_pa8zKyH z63(z`s6SzjTh1YSi$s-1b1&GWBi_tF#Ni<9oZJe5!I1(BGMJs^WrI2-0Kk7ix=rX- zIcgAZCg&N*9A@LvP6+8(uv4Kp*W(6X6}E2Gyai$#Hzyu4qogtJnnA7f!?HZdM!p9& zaKg*K5MrZ--J0jWGqVL^u8EmtkqjC^k<CJv5l_}-TmIAe8!z(^vJO9ZZMNhIYQ&SA zG?MHOqEcp<IG%1`w6dzNFfd^W{^(0as0kc|KulUy(tNO6i*IYiOkhhemz>qWhAZM- zlCmoNefyr!C0I3<cs`CG^)OKI8nXZp*>&lB0*CW25pkY3KN_P>lmU!L_3D_7ND&V6 zj()K-0+znv7Hql_dyc1dC-|=a9)BEJEm)_a?k=DpY4XS)W9||1<dnaKUjR=6Bp-SA zyNVRv9xQ7Qz>^K&DUj<8aH(epF9MLrNv%atB7gCn4QLKxHW6O=kHBAWMT;^LxxO1g z(y>`)|25<Fr0N&(?a3bTX;P?I<`<e_m|%8kWAGVK&aumoiA1FZ)sEDn*$ClY=ab=f z$JS}mD#F;09_RKXf8k1iW?T#2)XHLDKq%(VIThy26vt&AkMc&q)vR&?0I+XN4D&`` z+<*A{c<YWI{py;vuT^&bC<(I!PuS8Z?k+8``k+u~Xy{w0z?8t2N*o_r@^GyUOFDt? z&Ezt_9|PUhvic}K1>^5JmPMr&DGJ{C)ZRRF%o(1|p|F$r3nUuL01B@HaTi~y)}uO5 zv-t00%|^;;2WYqiP68N0>ODk#)B-w9#6N1n2O*<cjCVIvLdT&L(j}x{b^!naZ_uM0 zC<?BeBU`2jOCjTV^DZY~Si)5=YbigeG;q1F-ECINjL;VO$(99{{we*No|MJ;d$9@k zDGs<yu$is?QKQ`)tp^5CCWS~IDjwkn8$)7>?XAGF5J$XE7|00F04PSXRGFY~H)C>E z*yNNT0T5fC?h{J5%{<!jA=3Q;km<1d5`3HA<*Z<kgQfF9#3c-3v?{s~-mcGu;LseV zfKbe^vdQhXu|}GbR_eipykLiKA+jC>VuaFU0W@)w_H_iKW)zwYW2?t;m;qTYGd{sP z$|~lJXdIqlIWD%<p9Saus10VtLmT2}#n1!*3W4S^5!j@oX$y0&WE0urwlS(5JhD0i zIO<gJgWj7^G_jFY@HG>AD3Ave3(s1fZ{3oC4Wt8qZAPM>Hz&3CEr?zM<IswLSAmz0 z{yKKmffDb3I(m<RQilt5LA0@L6`2J1Z>Gqv%o#pmio)$h$wgTK*);rM?d_Pak+pfw zv3M?Ja*1ZMO?^WM<d$PP%vE*=_%*wdU;IDM6`1jd8IcAVTyC6>4hyh6`8P+-nA51n zlnVw@a7G9#Kb-0fuvKZqfk1;=v!|6QE1uO%P()?~4j=^ifR>R0o1K8{`+7brHz1%) z29^_}>j)s_ncJPpn*s#7;nd~_;ORqK=aJow4<bS_&Q@o_WPONXE-=a1=H@=oRu3^Z zfm@Nt$Zx-|LFBJ~_uW7JR|=8AucmYV76=yxO~|hg^e*;|;uIj5jHIxCI7hOjq9wKJ zQX%JpJ`;j8YGiSCYd&QsQ{&MdOk~JC4xMg_sX{s$3VnQV-o?^Hx>@<hZU@};Yj5Y& zL!S@B3qH9E1baFhRRWFndDx7>O07_1cP%n56Gu7r)?z7@>|$WX%kO&&Hy*Pc(UJ`a zQ;Ni77w0*?8J2M}ljq;l(S%AxQ24!}#ZIM<DGcl@77ivy!}UU1oaQEBS?2naPubWc zN{q*5WSx5(LXL^1dWReb40{@!Hjc`R02DUd4fyC3LI+WsWxf8S>&ADhH!-0Z&VYs{ z0cmOzq=}L{4P1yCggrzRazvhSe0a5)Tb_yj3jWVo=ENHUS|@NbjPU%1RSWB*lS(OL zmXSxU`9gA>X-MN7V-c_KI;uq<d%lz<%Aj~gOm<+EO>sR!nCji<zi)z(jCa*7kbd9a zjB=Ft@y8o&chs5YKqmM*!(owrf<kWk^}eTZ;~|PMV?Aa#wwXC<_DknbpVn0`Z%ZLC zt@>C%HP7%;cX0wmm>o|Op`NZbKlW)wqEY=bnwm5(VI2tJe0DS*<BK+J#M&|903x;j zv1Qc)xJ4d7ttKUb5k7@I^@q)lml>8TBGVr)sZ=(aF<ohORr?wT61@HR*c(M-wZ|(a zrIBjl1}^5frrtcP@Ee8OpSHuuWr;`}0Mqo%D7BytZqEa#g7hiL_!pP&B<xab9ae{C zD7Q|VmTGZc2YXI4@JKVdZ~qXdgJ<?n08R{5eau_%eH{xHTyvB03xX{tlv79zaMn~z z3g8tD&OT?_mBkAfi#U(-SQ1mvfC(mVvMI7CPXqOvf8F@x{&n(E5ty`vM9Km4Q^4%h zrVokFa|kED8<Wx)^A=B#`Ay@PP{I(T%rNNX&=2MN!!s8M+kB)s4Sp}oSFl!eHOClM z#QUut=haHWf56y64KB=rF);4%;237@bD<x?1*R>#K7@ywdsp7^05T2`_;P5CozZQS zT^3f3vK;7^O_~_v;%2A`J}ix9fa2Pnz%pI?%cwtYwi1(93Mb%&99)a4Wb%+(-?90L zXKf=XM}E2EhZq56v6BNEs5;1S#jT9Yd#s|qvhZ1?^9tA)c0_+plaJdh24}|1!|-BJ z!y?eIs>xAcrf3L2ePp%;CX<!WSycQLlzsL##mt#)yGja^!J9i(Ft>^InJixIE!gWU zDPU7lC!}bs;r=GDxk2#hjY-91VKdLNC-=uwmjf{Mh(3s1U=&YM01lAhFiHd4%*+Cy z!Jx%7B&W5eEeSyaGX-mEO~^nNkebyjw{k`xrCT-~NeRi^i=2HLAWb{tslJaea4H25 z$a}%F&esIZxXm~x6s&zr?{HcUzP>cyy0dO$KxdTXs9Y&&fjPLv%1?XSJLVw$_I^1C zRHdJ8Saz*PV^4R>TQben+>4B(u;sT%yvc$$a}9qGO@LgMUjRN3aE}HA320`BP6CSu zzamQnz;z3EoNNrXO$6J=W~y68&4@P)+I8g#_Xpvk{TyJ?W^1iE_Ozj+5lo<W<0Up( zg<v5iCO@Zr%~cxj<kdzsdMLvUNi4e36ur0yPadG!CN#Az)1PUI$s`C|lUFbP-goA- zhx#*s$?SkJfYns9Zm30Zhj5K}DZbZH_44+I?$K^3<lp_P=l@ZoNp|s?jC54=Dz=B1 z%07Btla?u4JV$C2c%hSf**7&5<C0Hkp~z0bazGUX7UjZV_JRXq4kF|LAA}NdOboL5 z4EKU3@h+z>7sT0_Kvk>B3zNg;!sB_HvTC3CJ8^{aLV#k`s|>sVSxth9H&_W6IZ%<y zjuFZ{7f4Wmmg!SAnz5GD`5_3a!v+Q}^gZQF7I-U)6IP2hk<g)JuGqMb+3YpxSa&mZ zfr=}j4b5+1ul%NscMj7ub}@f3TIyM`*7ec1t5?+#Yk%PBG9AS`K@g`xoHLo5EsvTR z8=HYvP?>@>xM<8-mXq%Q%YryQpu#*A`ifXTBl_MrBx12m^Uw|(i}X?<5rNA+@sC;s zbhEY{1mP%=YHbF2>5WnT9^I0vR)@mEDq-h)jx@|7UG>_$X6ZbhE*ui5dAe}5lr9V4 zd=N5n^ruhv!zi^r{?X3DJQG#V&H@q4?c3YT;te3BaC1*h<bbJ+2*7<q;sY<BOGOsR z-P{|>K>10fdYB0dg$LZhTt5hS0cG}CoZAD!5V_XW=Zfs2aEbw|p~9IOj8t5*PlV1e zf_WM*69f$%8dV59KuvHIa!|w_FlBghJC<Q&wz11{(JXU;m6}2A0NK7RxuP)v9dO5B zb;;m~QH$vfGH@2aI&xcXg0v`M-r<aduC$3yNP;<lr%4$H{W9P&jy(`LsOhPIi$eAU zXg#Iq;8$Sc;*y$vz!>hB_W;GJ>mp6gFky_I1tPca2B(Y}#C|<ra#Y}`i?sfp0A)Ul z*~)1qQITsUPkFu5sR+oy=k21Oxh-sV?<|28W6?UWBuohvomZzg<ro}Q$Ch<B(wstm zM7uPKl4(@1rG%R}mVhjC)MFysY{OKCYxRvzw1^<<8!d49A(Yvza*Y&6P;HoIj388g z^BHz-xQ5_{x53X)p*LZ$iFIsIn3}But+VU|=ib&yj0qt@+75Ja<l6MDbz%?o5VMa? zWxRKYFW6F#nHV-DAuFK{`Dp-d*I@G;Q~@Dn^l?SYLj*@Ux3dIQdSelorNK))p?wpR zmw8L4ZB1~A)6wE`sz2?kKYzy1?*?~6TpSD_ZJ-m?G?dx^hK?qhuuluM_3N@*?3<|k zw8sqMfBVVK8|G?|2jUDMVfHwk^(eo(PI*MAsT4?%g@X#kD0Y`dG63$t=NLMk<NOy; z%p|5QkEEM9Z3be`P8UF<LeILpN{Rfs>ck%<@%4SH3^#)Xxp}VfMketF15z0KUxCHa z2~O<doq)%K5PIg(Bh<~j6O%I{B`-1NY|`bJ*DS+9;*#uwpcNQ2XJE47EA!PHb#U?i zy9tNG*UN6wL0JX>RfxI-fapf1*ZMeYhMBHCvFW(Vtn)N9iyL(6RD3hTk&F;sHoY}- z+&p98bptc*Py0rUKboaNmd0>RUItv+mGPORrJCZKur1Wx&c<g#6RhG_(n1$aKPXWG z4IFmbehQB3&SbN=ym*c2N|KdkDs%LOw>PY2%({-3uF70`03M(9=nc5}_QZmQDX%C2 zrt)z(43eAA4P^F_rZ3qm_DB1;^7X|-IQ!}+TbU4#ezoe=GYpLxep+}p7`ooZWZ3!R zpRIrGsGs08)G>ASEo_*8iu@vBaUdEK9AejQ4PbotCS+Yl|2qHbnKzsF@+`uD@_@!$ z$(>yS7E4sicV<X{-ukbNjH{J4H4K3``cpZ(HB%AzgR7#tLE)Zb<C33%qgm6k03|ll zw(}&hcX3gQJOxa;OcnyDCZ#J<h9LY{-K&b&aT=5$u5jQ%f~O7PTGwQTLB8%E`S+Vl zd-{;!OF?wqGh?FvjIrdx_!Dz?Myf-@%wyyP?J?4D&q%yQc8>Rj2G6`60l_N39R3gW z>hyj}y%VOMuWyL`xsir5wvrU25f+vKICD<TifN$A$|=r^O!;!y!~|9v&%CXI+y(hC zHn)q6^g#Dr=DZTq*Sy!P;SSoceFLW06AGHtz#G{jO8-7<wmsNKsaGIJX>`j6H5q03 z<B^jv)Y-FhK7eTf?vJx}rJC`L#ke`Pk@$}Q1e#AyGm?xDe(o|ag|=Y54RFe16NgG3 zCOpRgOoN>kQPW}%;S+(Gu4h?j5}@KEw^^%|hbgKR7#kSkfU#%Ezfl6SVVv8No%+U@ zWr4!$*=v#|6X2vv`giVcR*{Z4T;zu36W5kg93$gFXY7M`BmjbQg-6_=W&UvnG#LN@ zD)S+LGdlwEP~!>MG|E_$v;EfPu!cH!R~UeNl$%=yLd?~nADL%DlG8Gx(`s-|v;TTa z%90!i5P2>fv@zC!IU;FWM39U;0|%hgrPzeV5#X#FlLdJ>WT$zRN=vg`1}0I{3XCDw zvXf_YAPiXs8r|dvpV*1GW`_f8I~nuf@!}N*qi&5cnfHMziBtdxpewpA(%9_36Lw<_ zv4BZfLwtntWVnqZ*(D|bX1)zS4@sfYcB~Gf=T6J8fS5A_TRFS2ATn{)tvbY*af~f2 z0*gddVy0jy<JZVc?TlOXAq)7?m&p8aOI?u&qnsu+M=vsg@!yeiZZ?t)`ttVw_WBow zx;eVBmLqK#ZP;u@gTmCOY)_$6U}%c8hQX%{!{Rd}$C28jb1h|0zxtdsF@&#z7{N?! zA9f1PMm7&%0$2O}!I>NIlkku7L(JjEL-Jw@V-u+rf)8;^CPO<L8Pncg!X2JpNAA!| z@&;bjzSG@vT#cvO&;~TvjTYXxkC~3Qli0?~u{*#t_K>8&1wYdXHmAsR$bZDwW!pGA z(J1?dW%HOkmqp=nU%)8>&`ONkb0T>}=WFVoBy#P0tC;?VPImX4p;eT`hhGZgKm^=} zCOSbBGAd5$oF1gGk7OUz7y7SW&{$?0v*r!dZ3=J%R?$z)^RAHy5aNa65VMOIEnorx zMq6P*Uc*($m+}l^ix}B?Ru^!yOG*}l<dRje_BQCtYyKI~B!n#;D$B8sppkuKk21ww zUwja&`oq{O@Co|y%URTCWD8k$Ru|#>ta?=dDwrehA^OFAS8T+3fpJboj>^s=xoEQ< zTfBTb_S!2z8T2A<H<q{btk7>>U%WcYO!lqN(W!=(U2uKW{(dlO&FL2GdJEVy3_2#1 z{RUI0gOe}5QWrMnE+g1U%80&ag&=FR&U7v&Hp3c_FJaJ>SepTBx;02eR>WJ{KSlr( zI|(3-777OvIzH#(<8rQl)PiTdQ2Tz14Qeg7eLYB`{A26k4KL=1ZU6v*!P@(4<X!yu zqZa;d-W+`|>XxSV#k${ME{h7+yh+f)g0T2?{$(4kbF7*_Q7Gwa!4CKTaDNrwjbPk+ z5>gKw+OxVw=%-IJ1T6t%4Q0};go0B@W?k*jhHglsTQ!sWj7UYzO#I(X2DOuI(z<x5 zSjh_#z!(BSEIbhR@e2?MV6+G=dDtBg{(p?Ue{@uJn(mu~4w^uefr2KPaWqIWRYF+C z6tpAuOac_0R1!=oNXHz`8Hk!wLG7b5()Qf>kwA!2L_35sLLuB3D?x0=1CpL)&Yimk zqM=8+b2|xWE6X)Y>6V#hxU<@EX5F5?bJn?^=l$+o33i`#?jH@6`mt+QVdvS;kN0^6 zR=lJCXCON&#zn`%(dcJsXb1&&^3{ZF!GQ+1OeYOzY9LsVF1gRe_W1o?MpBSxd34MP zfshzWt#@L45fA~=Kz8?(KrfUB{VjAy4m=5qD;l&6AyT4-pay6b0>i*Fj<j35)`EfO z=u;RP+-(50;-zh%=6ai$<t=OuDmg&%La=06bt~*C*RFd2k>a6*vgw?Vl7$I+<+3Az z{QOg~&W)k?+tUmCEd^L!D+Q8&4iC#jxAZ0moOg}2l5v-(WuXgY6#3N&jZ)zcIHNd( zs|a1!{$VQ!0`uAvrW4&cU)$w;9UgvAS-Pabg&9=pcEk3mN#(P&CLL~4vZ8VOUL-pu zHq?AT%3FKtYb>C_6W6<zwp8dtVGd0XsFNCo1<dfDKshnFMKxdxxOBZ7)FFANIymjm z^iqFEcT4G;1Ha=Va7>O>D&Guvq45Ev{Zi&{Cv-2!uoaX`^pLSx$k@Y6dd0Q`qK05D zZ)ippcer()D$wRteAQae%!KgFxD{!5&OX<^m9;{oi7as{gIz%+opex3DvdZPwc6pH zfyK0D(^J<hR6bu;5@-O!0}ciQq?XQdG2kU0C1U>RMjELT|08Sj17knXs8fs7Kp_cw zUubk_fUfK##=KUw@9qa?E{%Mw%*HR`U|gp)3n>_=T2pItSk<1iXd&j6JT$ij?kutO z%5XCQK_?jkbh4;;pEv;a?9c=;KIA|wuDMCdNl)NHi5)VUEBSHy>Y<P_?@&N(d^o4D z`&`cCBTY*g>cYRQ9~DE5`_J;5xb0;YG(0Jl%&_r_`XRK9!GHkpbJai8a@+7OQTI<w z5JYN(Z_S0ydEV7314O~}&Zg}^q|QNMbP0)@=9;}GI}8{F6jVB~nndBh$t$DoZo^^g zFIC3Su{eAxp37q*NOtSqB8$dXF{2d&i1g-)aX6C<4Ra={G0Xp&{FO1f$0bPW1#~x9 zwu3Wry%9i?u`&4EHVB{DV<L~Jjz;Q)am-GcQzm)`+7-YWg@D3BP5wIFQ3pa$yh7og z9`<ky&?-VK#0CSjxHD;5<>wihQM|6Y;C}KRdnulXkXYQqnQ`9;vsth{-rDDXP&P6n zp9}Gth)O<r@}v1J>$Qca3%c}Bn9@=b<?+@Amg_KB<&!T4t0Wq_p6vaVvc3)mZ2&lZ zGryP}mQ|g6B&@t5%!~YBE2CRxka3Jh^LTah-y%F#KeoiAL|zsgJl!irQ-7L_=?GlX zQiSrudb;Nd0bzVH!5-1-hh(>Mi-qO1C+ST?Yq4M6lTCfv0`bX?5RKijpuONw9{Qm) z$HbHA+cF{ezzZ?c7X@9Yh7P*83aMvq3qE(y?gkZ+77-3XLm(^~s=!L~((xdg4G5Rq zXYSW-n;LE)MWR$9luEwZK&&(72DeVI_ea4+tq+3x$-o*?svg!QwkAS3vb!I^fwjkN z4_ywY+p?||SiCnT@G?O$^K4Km;1judykuOYD$dRtN{fbu(y?{1M3!D*7zM7V2bO#x zB+WTzuFQztZDlL^dx0m!!YCEt&@0m803q;c!45z%8-Q}1tGHh}bSr37#p1WdTB`AQ z)woUZ?xt#J0I^i}2zp#;_fysFYPR6P*cAxZxMa{RqGoe!E;u4Xt?a8s>+~kfM*(O& zm1~LXCAf5Kc5^7YG4zxSvP6rR3)too92VDhWX;9T1rnqSd#!n>)KeGns>o|h@f-U^ zr4XwjV+X;M;Hh~vHK_tE0c}$paU_|cb@G^MQY*`qUH<_AcOLk`HWL9AmoG%v)3Q(o zdojIiNLcv?-Uf4x`QVDk?lB_tKIs!;cxw|l_w^gw_wJ^bbz+Xi-wy%y$}|G8FfN9; z;8KQhqIJSz+W^#t|ECqyP$LmTFdjYflnZy%O>6xrAh%t1*xFo)m1GQ6b>z^H1U$<e z_+~bp)q9PDXvWMWilUlInJpYVD-~15UWN9JmP%qAN$M5&c{0Xa73;4vH6y`$3%xmF zKA(&>PQ)+av-LvOoU{?yRCy9q&<Z@qIals(-^u9hU%c^qpYFo^;<tSCtdbZ3bxe$E zI9Tk<01b_?al0b(WHIp2F0@o;Y^#B$_PA|-n4sRss)mR$5`MRtD;S^sjZI0B-xmTz zb?pVv5c6II(?UC|h`dv&bi&0-vIn-@E(eXm*FOYqvPsVWo936vcEH%ag(0<_bw$@N zR!EC{QkX*ntIN!<vCyRXV%k7j1uQ9lC=4V%ua5`4eCLa3!97V!2on4!<Kfz7Wzd~d zdy?9f6wKJQV}pBtmF)#M5wAnfI2^Jlzxua@opDApT@`0vjk0<UyX|?>8)Pc_hsPXI zqFGi_rCu05S?XsG(JIM(D5l>crwsB$x^aVVm4#Ejlv&gV+Dd)AW~2?>&?%A@l?1#b z99n$DqiT)~8bJi6yhAGwVsAYB%3T(Obik<h5c8Td8}4w@pnHa!E<*y&#l2jKD*8-} z1R@)zjsVjMX|ndPiI(&AMBQ>2`1N{Cs8y`l7y14AjZ8XsgP=`68QK6ihTA|v%_{4e z(a;YW6x#y~-i}21#6sJFN*F)ML|C7dd%ySUzDVdFYXpgNkqXP^qfmMsd*K|#3oon} zCK|u8Fh^Kwqj+Mu4Hy^B51CMzM6^7=egR3_)jcjV!k@#)nc{$jI_mo7zm0=fB<?#^ z(b3}xm+Fm$E&{c@t~&`8tmM-2F=!)9?hz~PgVoU$<xXL>37#&%GJe`lAygoPt?{Ac zUSc5x?ejxpy+q_Us~*F0_xF+qIjEFKegj00+#hTWd?Z2tObyWvbu3BPtW-Kbi=c@f z<u|q(G8(bt?t}0N!iM0CM?H}9Ogbz71Ao3>x=$?{oz>teq?X2vf&5&Mvno;s>%)!9 zQM!asN4tUN!3}7P_-|eUGRdTr<jhD8N+cvnq!6t6CRs}4K`Who=>iYKNU`alfp9e~ z^^<}LM=OV&@fV0W*|JWt6n~T}qhMNw5eS80X<I}RsF8b?jA?$WmNzXS*FKQmO|qUt zgG2lYC^4T59pkNeALhy;H0_<uT{@^5KaNyvDy8!K7Lo_*nN{{!p#ao91yz(>h{f$k z8bP+*Xp(L$8Jb7Fktc$Yw&zIJoZCIE-{Ryv_+2XRjBEKYsl-G*5*<+G9?Y)~B#nPD z!lWIfMs#k}Hi1ag#9k`HNeM!<cFhB3yzXy1d>uUyl0VIpDr68zZQ~r?5)x*sLAOLR zjn>Hm!}JSWzniBtEU}hX_?jz48ntK&cOn~d;>Jw*%^d2m1HzUHwe(0?!VfJTd8)ak zqFy<DR@kxDLI}p>7Y9?%U?RFrPnB#65ra|ELQYa8?agxSvW%m|$<T*$NWG9B;Uruo zh6t^qkfM9@<`LL{8q<AFa8dM5bN$;0=!4p@PZx%Kjqgv>W#BX*U)OrI51dBJ%o*d% zbV0(0z@oF5rusC9OLA(8mf*%2+G$?eue*i30+YcxS5`vJw3l`Bci(xutPCGbnCDk% z98PVWG6<xn>6%g<-h&L7*;<RK?XG`TYmFd&K$gll<m~Ou>4Oy#D>;%1x|aq{7JG63 z&o^?UfLAyRCaM%%K@wK9GR-9_DXWhc@2NxoRMJt53|@y9s6r=x01k2P<R*$oa%uxp zsV$}U%vV%{D+|z&Qq8wboyPoxorcTAAzj9Cf)yErHm4ndGZ7OITCu1#+OmzhKqOar zgiH(wftqY)O-kiqCW{BT>pox)!nj9hsYXK&#Lz`8o-yrAJ6KSsnRW)DOsNUoJ1%yn zrz{j{ylTdX8}ah@=JNq;jBD2j;*#pH#dK4oMeGf*Bg3gM%B;iq!X%8(2V9q%R3g&R zE@$@{REp;*YUz?D$f_lSjh4tf(e}ixbC22EgndHj5RySR5kkwF@aFOZA)aHe5i@~V z@_QUGd_6wFeV<&aywt(KfYp15cou?j0^M^wZb{1r=;(+asK0;nx?=^%oG;aD5J7^c zyKh*iINX0|_<w)s%$j0VZPaHGeS2im+B;H~Wqd0h2h<84QO1(2i8B7D>7|7k%6>CT zk97Yd<s;Ct^XnHPWu~2G`pC@!LxaSEhl}?SI&tzQh8^3!s~;;YxH&$!r&+@UhIX?1 z-qkq(fMj9dm4TQ^q5tU;kI(I$!u%7&6+BwJms7DrZYjeo1TwQJ1&N-o+pdQnInV#; zAc_Sgfm^=6zevmv0^J^v#5p#U8aGfo(RRXt+u=7VK}dR2+$6we&&6}tMP}dxNTr~P z6jEwC9D@{_!+ZNwYA2#6yl>{m9#cIBAXOSd<57%2U@Et)7LijBNhDV>4zy5)twj!X zpK(NEiiBBw+BsqnCskE^(QAZK7ZlV>?d&Wb&&{z%lRz`zbBzNs@eFaRf<2m$Dj5_$ zW^u_F;^)n<OQ(CHcVevZr{GnTP{~ViIlwI#XoMby2>+i1c9|dRLzd(OO2F7|4XM%f z6zk;SJ^@xPkQvmFGXD)APC^->X4*CGRc4H9<sbhjPeJv-)}g0G`>2@}0^@fD-qt<7 zJGY)`XmnN$ti3(R6dEa$X@2o)Cj?rbuRvPl5v;mi{t^7l&Hb`}Pq-kUV}3bRfS1Ov z<c&1I!q^-TfqUj|X_RU!P3ADa_E4U-s!H~g(ZxL2^$@^i>LWBu<PCDhJQux$1l;Mh z&D|@ALB&+U#WYaSE<%QFsF?yR+Q_4MVrlK655c)o7llkQa-c#DBus&DC=Y|qI-s=6 zJEqq{MLC?P=vkqkw!A9o;*$0j)mNs)XNPu>AT1u8IqxrMDgwxG^E8~GpD_fLa};pC z$cbsbSyXg_Jx!o}793Guhgo%?n8Gm~G6XU5pooL#q~r$97Xp)#PRa1l4q_tejKyb{ z60Yu0=^U0!Nd<+5x~^RfT8n`;@XwWORP!{vmS@cWWp@Hp`J-zGe);Hgd|{#Ho7y^{ zs5#hpuZg*VK9^A;zW}pGiHS(Vbo<1eIC?=yW;*K174vG<zJ3c)N+5%EvOQ2T^iFE4 zKuXvn^-^jJ%oeQvc^rZ%o3D*bOJs$u+|bmtReNZ7jY=u?ug~S|z*qK9QC0=s3InTD z7{Y03GQrIeNF3#OZJssPrr4!hhs(rT3|tK|%Jzq0m9isUp1LM`3?x;5uCX*lGi?As zw6^Ye+wi+19vSrFEd0JXmHJ%<0vMQPwhiXU)6LNnk246A8mjOl*q9W$m<T#I8AFYP zyNdXE!vOe<TS_Egsw1}#!b)C5I;zt&?PwlGwKr#Q&5S;S)Eg1d<sqec`b5*_1-^`X z4a%<=+A&XHj$P|3!%hj!;H%R_McFd;;SIK+38m@?u?e_eNE3b5aX&kdhoGW)3Ty5a zY&v2oh^%^`3C1TwutfY7ZYXuN>C&ZW`zIefA+)@JR=OD6tS<OEEOGJtiNQu*Gv@(r zeK$=n$P)`$4U#^YQj<vc={~12rYxrN>b@F!q$c0xk(YWj*T#UFxq&N{Kk4Z<dYSCd zimHc~b&2?8LF~H8S@sF)CIMQ9VfP4Udq3bW5}e}zny4OcuBY}QhB{O=ofSzG5?CY- zX_g<)a@fhsosEbB3nz`+PO1=rPu#%2vV*-v%yY0Wxuq_BuQ(rBOMbtDjN*bblLHb( z0}Nw7X-FqxC&ZJ|>ER`!CII7JoulbD@;{q$((m8l(k&db<X-uSM{P<Qu{HTA@JP;4 zI4H~#W`0^}B+*Z4Isp|1CXNSbWwPHwnmK|s8!;dnWAoRJd+wgj&t=;p`54WcO~X#h zay9Yxl<mP9^0*xwlE?_i$$O@EcK~ciq^=l*+{-Aihyd9)AKVdW3d<IfU#gm!DDVM~ zCU|YUk};Ueu?d(6Q%9%@A-Ea+Y`NOecdJo85TmwATh75XEtg_KU=O5~89BxTfJg2D zXVFq4=X){oLW@DbgcDH3L^A;u2Z4|yzLL=zHm3)QZbFoF6Knz%rA9QNrle)kqLw7- zm9aE@Y!8<9&PrK|@epUM0i?h;6jRw_KqtL~eYETD<x$s!2n3;;+WF+AOAlRN8$O&a zb$|<pli25WJ|)OqZX4{?0zzW`eH{S_u9#@hojowH6b(|GiRz>z%krCFNfGX%<;r2r z#0-qdOf+|`4&75svAo;J9#SQut9ayD>AARd9MarJNGoG#jBxMgmc(bs9r`YXz(Ah9 z6Sy6EY9Vs%Sb_s~;P#QXIdzQ%A>{wBgZexv>{*Oz4$df^Jr}e1SaLd57m^WHZ8%)x z3XFkEJrx%<oV77J)o3yDz;%LsIB%&H5Xw>$<WbwYE2woF*!6a2TMA?q67}WEtfAtH ze9wwMx^@(DxE8d4WG#MfO0xmYEAOSnc4#}<O{#oheH$%NvK25~aVx8)#2cUF6?lUH zr(OU>R8Yl1R(vAo)UVJy#m7jQlodDs8G<ODqtcm|LvBqjrM)o*0a{iPt;`Xv^zPP> zn`Jo78suizBn;3FMm|Rw7c@_tL-9fQ+X$NDRdJ=k19$#hNX*t<N7<SgVhG~A(FXD? zBM9b2ve*O(6x5<m(Ue;JI9xU>0EV~G?(wRUGMuc}!kDy4g9&v=>OhiaLsdo@HN0^4 z(moIOis~0ml`7ssi#&&aGJHXuBaS^X)MoTijLbVM4AH}|*8<{M5=+GuU6YpN$@F`a zzdHL*BLpIqZVVtuO6C`ys`@2y(*#ztF1=9amrTJ~#L&kzBZd(UDB5YF<!mg~1%z)P zqOBH*56%)#A)fesudT7EJi1IW{^KVSMWvL^;c*#|HhYJpy5SA@BmvL$3V1%ddO`SK zDHb*lk(YC;idk_^hS1FZ2No|_z3hX>xv#da>4DedKe8If$-HW&@6z2}^77&jtJNgg zOCLS5r(=a7Q8j2GswoLgXkin45mc%L^DJdk7@!0N)MC`G;W3j$QB3orE(ilWT2^zR zsj}do!$;37WM<D)S1<YrJ}zKr&jVbTVjt4&LO3KO(DjiRnu<fRO}?=F`S`#TuZM%y zJXG^S);}^;@XCE#9*qE9n14qi^Q?-o?X)~Z8&N2`SL1dMoopB}Tkw&+HY4t>+FHEQ z>l*g5H2F;8X<85au!HG=;EA?<#vm~nCConQ7Y)PsL_3}2IslHMdMe*JuhPqmqAVh5 z<|q#8&63Mv1RFs;Q%fg9J8G-TGkF-5=#w{{hR-orhFqG{pJ2#*xBc0b)8F3%ymFt0 z8z^90)~75^E;Le+ml#f4^$4TVhL2=OrGI87@$7XC49s;6IqYNT&7v>MG+H;5BX-zN zdoa%BI50|%Q@eagthi_U^ifZE3aK<5z=dVQ2`?oVs@aD;0VcqTJ!sv&wjsrhZI85q zgKnl_2=fsn_6ivzwAv?Hs3CE6BbIzoBoYZzbI9x3Lp|!&<u^ZZmO-Ecq9@;LD^g)} zC1Ar<jb$~(_yVy-P%i-<{+(VWnpl{gNp9-6GR=e~nI-KK8nN<JjWxKt-Nwg>GwRTY zk?^n@?7^#$CQcy+_Au0zQcx6C(iVvbmsP`SawlS{+(x*baECyugw?|XyKa-)Shte6 zzm2UOR_8nd<Ti}Bo=KaF(;)z3U~2*sQL!DOL51RvXqtVtpqIV8Fx6)4PdERdpb95s zbKinfUdSdEo6}Pm2iHyuROELOWYuYBmTNgU&mq%7yJUh{LD1TEe~Ex<G+p0GE<UQS z@a~t5scejm^r@1PX?9*-z88QLOO^eobSd+G5KPoo{SQr<kkA^29qruAx6S(HUs#Xh z-@IS(i+_|P%3>~B@K?o8;U8i!N;YkGBoL^qjdYc<=1bs5C!`IROHOC*97eduluyW) z+V9E5@T^<a94Uj5dkshlhHB>)shYzQN>%w~b;d?eZ=I{r35TSUao+jQL_Y(bu1a!8 zV|kdZV-|tQM&;DB-PWnrZ=kmh%^e;)^*Kxvx@rU!;}DEwVB+da)J!VQ(%xK8IX?WY z1;Lg5Dn=Z&#|u3Y91^*thW<r+3J6z!>(GScQF5gL(ankau1On=NHAP}MX)?GaE?9b zLYqu1xJ)TC)?Rvs%LHEViK0D8l@x=N5;cvE+LQtm)x|ukJltf&M4D#Qq4unhi?7cD z>QYucAydb8XsO8t6FO_f*ql>1lh=U{J}ci&ZY48!Ow%E6{!cijsG%EIFv(O>@asZI zH!cCf@d-RdH43)tNGrSdRk@EQ*wjt2M8KHoJprE!-WbB$O=6{dgWOD#FkP4eVvRA@ zYq%Yd+<k2LwI-xi<xaU7_#8DA+{Ly0lT>%x<hAv+kw=$TUzRmk{JgNTr`N{%`m|sY z^DkkoDm9W`VT3FRLrzufbhVj>&_Iin3dNj<XiBM4rpxaRV-g~$GQgJrCSi;E0i#lw ziG4VRUrA~Pd@TrwD8fHa0j*|2S{4WL$~_==0RXB9&%?zw)8`XV49oSPB)<quwheuw zW&8!l8&OofIrPE3ihM3EJuOJXTzup?I2@}(1&k6&KM3;s9>V7sWQKSWnvuQ8&-$CW z_B6><OP`vU8rxyBeWYmcCQ(Y!SiPS951~c;H$zIs?kl5o#m$*3+{1mbY3ojAaeYu3 z9H!`?kD*G;H)iu3qE;H&)G)$+`G7$*PyGo&<Q%|V-ckyyg+d4W`*%;%5p47_f|M&$ zP{CAiU0NyPW=!2Hu}QU3>P<M}QXLVe?=!StU@Ed)nHc)@$04}<AaS%h^b{g(ckk~0 z1ZW7!v)S@i1Y6*c6<=c#SaX-NN|;u!p>dnl+u9Jk>ufFq8@<yil(c?*dc2tIoAw%$ zGy7J08WB}n`)7%#izJYyr^&Uz1_4O&peUV1HoAbD2o`~*4kOhktS+wVdbdzZ&YNfo z6(~FTlQJ*kc&Z~7;WLQckCf|=jJNfP{;^lyEqN5sa=_F|0n<dWAQCsz7^M!C**|YZ z#TufJ&j;f1$)J5)0BA>xoBN9c%4n(}79$&Qu}+10coHM!g86O(>Lv4(Oc}l#NYl_C zuIGnh$Ex`non;(SSe$e9AoF<E&ZT&ak~oezLM6dz#vvfNBtxdi#u%e>vlX6&m>mf? zzc97Z7_NA3!g+$|!A`N3;>*{VoDYv>L{Jb7QN&O*L?>Pg;^}J@ede0WM*MJ6UCu_V zTSd`uRw%BNRojoLE*ThNz~<@;<~UDOSjw?%z|qmm+i!(FlDp~u!&^^Xw^GS`=EK!g zZ$s#1OBPUTIT^}j?Icc~aZAFeb328n99`yNraCMJC*?^XBy)wDW@n|07$*ysWgPB) z=Nu$e0}VqH_q-g|5*h-mn$p9*16;Ed&>_Lv@<gHOutrj?(o(o>yJoJUk;;zrO8P|^ zrTj9z&f6Thg+V~NR9tt<VZF$efSK#K^<ve4GB$f)!CC0DB5HgP6K1(G5Z;;r86a_L zER{%&gIpTHs2eL{%EP*t;j|#EOinjOLD)y=VT6&2Oq*1fPYKAJ@wzYpAH&BHL|RJ4 zP*~mAp#wdoOT9R%8}{?mR2xy>2<WHulC#LuFgy<^d5xEZ5$*e5qo)UIv*6LPtrn2+ zX(I?bLpu%Wq6Ou+fzm@QSZX5@13o%~sSnH@1k9YsTCf34)yvY{(SA)eWad7a(U`eO zUCW+LP3D3Q7M1W~4qy}$da7dyYjX+f48LMGs~kX1yjHp|U;&|o%^*I@NXEI7mx;dq z@zC&z<6E96gfCvYe4#q0kJ8MVf&wb(l*|FX`dm_`chb0AwcNiIg$3kJt4=QOcF^i8 zsOubebbof!O4jTT4|XSl;4ES-aB4AChrK74hrP&-16snVPP*;=0B%Wpvteq{81>H{ z_jGWLHmfsG@|Cp&B@a_C?eaZAh5+A7dfaiOVNhYu&1afzb!LA569L*+=r^5cb<eo7 z`PGQg#Wo)`-@DPTtVuUm8JXl+uxHw2+T8oB+oe(y9tg78Ru(gao{RMeH|(_8M0nku z_}XSr>aQL3%&Z2nH;a}B5HZs~gs3(!41#Lw7^I#f{S`)v3J}Q>k9@@}Ofv<UK{TIo z#5I&L#qN?k9scmV<#AXsImi%)4&p}R9WzZ!^+ZD@PfB2?DnhCi6g6N4WGe@toIoZD zthOZB>;-oPMn+^_0(wOxU|$QU$wk$d@ZJ{ZDke@faK1JlKR$=i#1<ZPfzzeTHr`~# z%qw0rs}gl~Da3P*HWX|O5?H06MZGPv)K&#q<Oi0bXWGP`!2(g0in{LsXig)ot}lji zWlaH((nUcV2I5JP6oq=4YSe{Et1`>O=1)}<-SO}+2gGbgxwZJr(e6S+JFpr0C>971 z%D00tmDiwnGGUMZsJ@kIqnX^!Ou)Z*4mH#a%)>yXEtT=~+DWJA;sNeO*Ax%a24}HT zffmr)v=rr16=SL)vw%%HOg*J=5lRW@*_W|D3*=<v9ct$m$YgUR5OMh*5SkAPOC@Gn zjpE5`Ex<FOP5@biu8}1>0{APR%GCil`xSj1Gtg!8C8~aIv@EJd2&Kmg+Gj2hAm@^A z9f0x)%$Ve}m=cR)i7;$?(*kEbhtt*%C{yd3u_)#we^eRcEKo;8p`WQ}mJk|QS@bv1 z=)Ll$cfiQl)xUYa_V(w2!#01)J&~gV7h%=dRk?x;8V(e>q|B#4wwlLAMh)sF*7SIb z+H7_skc=%5s)dLoIoKs^;~>>SIjJoR_&ax%wis|=gVeb$BlJv}%e6wMm}q3a0(h-( z`PV%v-Lx$`c%!EXwT=$A^@D%5c2tk3W0QeHOvJ#CjQ;|NW`X{j1%pmK$EVN(QfZ-( zc2tAPL5^Z${MRpiSbqx{Rr0NiV5yF9s%Xs;s+4yc2V{W51XIT(f%CZtytV5co_ZZ+ zhI@-P*jxo6+5KK`nRu+(bO^9FDz#e`jEzk#5la@#iYOX?^Hzi!JM{Zz{{LVmBo<1i zT+eJ8`s+XnW>Q-wN!U4*#slHIVwd8XWKtuJQkIDkx|`^)LFl5FAo4NQ$YBAYRCg$; zu0}N7T!&SAHq5B9Ay2hcK1V0;^?GTwx;LZsCZ30k9^qaxt&JgO^m{IsFwmG3D8Dz@ z08C?T>T%r6r6{~dHrC&g4lC=rKtvO;LkE3tzMR5>hnI(o2c{iu?BBz^7EyhVgpL`E z5W~gBS;0t4s@fBxW9!$cC)87P^X9LQ%oPju^jAk_LBeW!&DvMw>6pAEpFdG-nd@KQ zTy4`Kg#oIh^+VO5Tu=>zJW_sZOK?!cR0q3<L654z(-@dZ2=Kuo*crU>@KdJHf|(Fd zIheI;5`m@@3hD5-LO&a)+=RX{(E%5G9ZWRBESZi7wQInGw$B|8d3o0vCD&>{$qLC~ z6hT#CC)#Y*@oadl!aADaV6=xHFTJo(!|@`TMsoLoJ4R2X?k>}wXo<Tm-l$^^k}U3K zAbDLN>g>yWM>)agFYV_k3BnU0qxg!bx`SMF&`|?Cd4E;aaJ3J!%)(aWA=P98lyFa^ z)KDc6nrT+yWXt<ZXv~A|mP!*@<yA5f@8U$BAsPKC9w!;sWyrb^<v_24Odxi0E$_l? zBqNYzGAR*?E3XSg^G_vXSG4*jYe;K&g5xB6ib&jUgv>I?I8m%N7;LeT<f59o@1coS z)R(Hmtczd&9Skb2iyv=2S%_L`I9cKCCIDd%4=;hM#WcwQWn9<((suY0kr-BjGWwzD zigm~YJ!_I*>;g#!K_=Jc*NeP?-I_5}_D2oWp3<qbE8$EdmjV<6x5H*LO6fhm?bJv& zr7I38UX)a;2@N|ErYN%OsI*Nzt&O;)QbbHLs;OBmF(PUDEMl9xWzY)Iy}6F$4}c|r zPtX<tnq5GMONcCJt-gtnI52~oitffazlzFR_!EcmDrEA*m3#oQQtd(|#~zIm>uZp_ z%)&RtjkqY_)5;EI*k3y8(ndou#$z;$LGH$mIrxq$N3|x7PXM;!lnVR#7$){gkmbbY z!Z&Fyu%SlF@7PpIMvise*O<=%<GUtrHv+}c;6M)7IJ9a*au+mmI@@J{t`u<=6&KC6 zH4P<Mf4VjjO8?h?ZTR<%=W1&rIj06ex{w>u@3<|MZBzVIQfm%g$)1r0QBfoWMQ>dH z+UvmC*2yKRW0U^+Oqmz#A-NORjEA|R3auInYrw=yy^=l6x+a>t--aJY+Q2t&pToV( zMuO;+0qmp$P5`^H-BW#2Pv~d0t{oPy6cBkp3-7ZrOPhz}d}*u^M!`$}fJ*>ID^Gfd z1=1+7NfsSpx>D$=9dw#?bO>%KSVv3OuKwNjNd4Z{N=}0)&uQ|gFLOv6l6>W^`(d7L zNK!8}wbnVBA3}%)j;G5Own=YwV<Qrgw|XOvQb9FVsSv2eWqq_2bgDqWI<P%DXeeh~ zw%+H6MrK)XXZ-*f5S*2RB}3{V;|xRt$3>aZNB>A(s5Jwk4$bvc7u50aRv>9lZJ5DZ zskLx&U%2Ha(;~s}XToz?n*$e<K(i9CoC^tA-E?yAoC&ZOki-Tp@v-;m)C=|gy~Bfu zxDSmy!qNV92A!Qf>TveN>zyaEg|3m+cjy_9t>JL|ihk_(?_`YwNVweg1r;vq0%(ga zRDVU>ugf^7nV`6vPGnu)AjP$-x459#h8{}-!+oa?tP_uIu8vz|=nm_ATNu<2+l%4A z_57t_5x`OJ#eMO?gdo^nq=L8RYMQp8z*#YYYYkO4x^F<B50qkvlEWoB`+Gaal+#_^ zqi(nL&9vhHE?ZW{8|8%FRd|wKQ5ls&Q=#a=_<&$??4S>?o;3>a_Bo|iq}7yL_qUW> znVAQhUj-QXTL~ixyD^MMk<SiyTp6U^k6A>3PGn(lvdqE2yu-BJP=wH|-HjUiN{BAg zaCOxt!&i(?UPODSq+c)?UyvCP<_~ieBg!$KldvhVo@v^p8$HVVlu=E1qN%&e7I6lO z;&M3hKe(8<qprLLr*T}dB8cg<oXsIO4XK&{l;pPuMxddF%g|7vbACC;hU9{%hTGcm zjT?HBbPyAe7W-j@k`~jqVX$De^Ek6qYOQM1gw04QF$>yS3jjDuM#yc`E|2^G{yNeI zqb&d$;7T-gKH3~(>u9wW{Y=&~+%RvhaxqKp8oTPc%v?H1b|lIzGx8~3iVlh#>Om!N zN(|*NOX)N+QtDWoCL5&=zxd9XY8~~Iex3V1C!7zvm8T%K5+kkP_xthfd*RC97**5t z))(4FEZ0+bl_b?fr3hDr60|cj{cu5?%c*)PxRdq8LTqqK6P4h5s7HZZhB5@Xx)9)) z7G4EL1gDxD;RO7$n-UIYF`U2{JXnDsi?BMkm+bG7S!(i80zskR(oy-O=(hxH?OSvB z$fXB<tx3HEZ6hUFV3+B&+{Gupn+peON6n5jC7eAGS(*b?WEMM9JBpZ>k>N?T0>H<I zH(6OBCJWr!P-YwSSDJF2mQh%tHk}51s1E8KTog++1KJ)d&~zJHCH^X#%U}v!2V%h6 zWYJm_i8q3!&(jr-yA-j3nLoIFuwRt}-+lLSGJ%yROPI1f#GkE*&r;(n4NF6S7ekrf zQZ5IS935zsjf(tBTxeH(!ZzJqYhh+HvYRdAWU&|gLLpjFN^@JimkkY$QRQuRt2AS2 zvHa)?-P#oKQE%KTsmEk#1=#cvxPgvKqiWXaQnM*>B1_PMsNN27w@6~(VqBF2pWvZ_ z-Zrbk%!)`T#F%md<Dm4E;+c|j5>Pv$xYI&FkVlh(f5jVUagsJc7>Lu+tp#)*nxa$J zqts5^9lOdE!N0>?Rd4E%RL>TD{oE{>cEtIp#C**@b;Fe&yn>;!R83Ch0z<PZ#s_Dr z1`H|<URSsdIHQXh%XRo&Y)?lgGY7hHfHFfjXX(B(67QF0E$vXx{+fe&?)6TMSb7dB zLnp=-eOp${)8nhjqNh`qVj?r^vs~T0zepq$H#Azn>?I;IB5@FGy#wU6oBtCab&({L z-^~oLEK7sBdfmU`t>T!1sQ_^!Q6wlU?3O8){lN0%2wvq|kXLz~)o}wicxXlk?&_V? zh$aCfrYMWX_)G97g1br5u8*S(U2bR15xll5;djjOG7m_%{<Br~z(RSmQ@v`5d-FTS zkugz2!NJj=HSmb6)XR>{3b2`j(E+NYKj+O4Q7H#k1%tVdS<QNYb}SjYW#rR`?wR}) zCvq%(IVh|>nqjUrV6N%GM<V$a%0&+rgi<Ew^x(0fBN5Yo7q9#v*kC~=8&r|PJ8my& z70IQnh5;6#^;vSe${Tqzp6vPqgh$kQuuwKCzp*Qs(QFdTW?P<jU)E4gr}SbFiHvS> zdnI6ORdM3BxSzmeR;bc=urX4`GRFh77ZBNPBzIdI2?qQ&@N5;AvQw#6)0BpPMuY{> zW^E?GbO2L5J?*kkxk_k!x(^T*wM~HJ`~Z+2sL2H;GZHYoTGlJQ1W)&6<D9ng_|hS7 zX%cS)*HyNNp1G=;Jc-BJQ$dJGG2M-!t?VfWbyaR4?#kMto<@*&oZrACZ)tG@v7kQD zU4qYE@bAOctE6fWXK4sXxxkQM6dEXsW}_w`&=0nw%$CMWZQ-k<ohYHHmD+D4Iw#8N zIiVJ$Y4=mCQJb~Etn+Cq2-kJdXypX3Q=$ofE$~AG1?@GsF9uplidH!v)x|C8bL&|x z+-tJ1Lczl37~P;Q=Ok(fq)KLH<V1v6i^}EZE+N1Yk%r4K3jCS6fa?My)y!#`kwjaj zGQHlrLP@LeFFQZ!$%dz>*JPH!9iZB_P5^s_=~8{p8snx4+&l~;6$Mmts>r3bS6FkY z;Tc;3CwNG-ROC2_!fZ$?{M2E{1VK`1K;Sc}(g@VkS*ilHlgkb!X!vek3y&EOo~y5$ zqB$I1PR+YefRJ-xg1#$dR}2-pEjgOfS^d+2*9wI3kKw?c{|vaM8D65Z&gJdYh`?on zYKWvq)5dBBEH!m^rpL<`(^9vuIf}-!5{WD@zMZ7n{=`^oUq3-3vIxT~&~bwUTfPb% zodT!S89ue$rE%}D8B9OXyAu*DN7XUjKr(-wwGFfh_NE}8mQ2zL_QiW)rlSn0&^&&R z%gzc>@mSqdiBw_Ot%g}T-E>M9UEMC!Boj4!*+qQ)xY57(Vy^;9N*jGq8CLFA38fTU zkvM^msP8Ed-k!a9rY_JnJa)P?9$^2HS+B5k2e<-NEMv!2Bi8<1MU2R#T*<&kQ(IIY zE-8E3YwvNj+>(v2TFH+vQq2oCUZOZ~%km7Fc8aZHOoC)FK&;W*Q&v`I5nmVbv7s2l zT1vv*2#naTlZ$6}A2=-3T#yd*n+U2$aM=)L!5|+M1<M9{Gc7+eu<J5Jv!80H=>%bc zA~<))y{7FpdC&DtQm6R3d*zohDT80S8Tx7%En;go1(nNy$>$kk0b=hWjimgpFnIVF zc<q$p6DI<f?%GiaK~0$x+w{QPGcaPQ!X>Mhfw3ttmUl_dJ<}$Ph1niwCE+7eWhGhD zAH+5k3`%#cEVjQQHzVMhMm*TxcglBN$NKsY{-4{ItNy1LSvUY-dPybj3yi$<<6;J6 zK*w3kR2r}V)7=GZDxtJsstQ;Q+qg_uLi?UfD-IfFhtj}rLCM@bBzAvS^6%)+s4Hr0 ze(!}mbn6v)<(+9%?3$##y64ciG1W6|2fXm^k;pAG(y+~e0<3O(2BNW8Ex-zX68y!A zjo1pOkp{<V9}5IN(Ev=_doxdvNZU^^=}FH_&8O!lhiGs4rX23nP$|Qdl6V83M%0*K zuIt|&cw=3s53<gb&1!l*0CY+~_Bw>Fn70~K^FdsMHrosKvWw5UUm4*XRNc?GGPlUj z7E+oP`erkOlGggZmU(I@H~{fvIqdi{0=PV831GBdo=AFF)@(GFvOLp@gX2<+6}w%g z&@MxrWRh51o9s;v5LeQ;XE0!KCxc|9<z*+8W1{S}KarIVGl|+*C6I1?$-=nSN-iqf z(MapK?F#H6mn2%Ja!}Syw4Q`%5;0mkKSt8X#a~rfr{J#cUvk@Xi|WBs<9z6z4_l+% zB12nYpLXeyR~nc2ni<#Rr8eORUW2_R8;kFvAzO7Fs7{*Ke$^A`(IO3FUG#`M93KIB zrRxIhfiCo4;EePx2lIzVtdLxzGUA-RcWc)L5Y1)@z{7WY+Ak~>0AnZzvPy@nD;whY zV3|x^bXQHN@J9Hbbis1fz`%)2T;$!9z)-p`=$iEAK_hd7e`13h8Dq`(y@FAF1vXqV zM^mc^&k5dOyU&_!M<NjZ3<n$}tmRc5@aecx&}v<FUJ!uZD-qa@wK{G~@=ajrhCq?( z@sdgZPF236IF{U2gGLjxX@JnaDJ}1%)D^kcGi&+x^a!^umS(yVq&PDzq$`rTR-X>r z(qArRdZr{wJ7lh@yhZ<7Svt$HgdjT_>im2)+REQt`swGj?2${f%6#bSH0a&35XGcn zMXm$j@v@R^!LXR_NHU*|QPH5WPVqv*N~CgK*w>XVAoP~Gxle<!+f!gLq2SlRz$zO& zrCXsw@n5k>f$AB8#|Cp6V08f{?1073Y3Zbyrfph$WkR*IVm;Lo#(<?t&~>a|NM07u z-%6P|wAV9oRf@3vU(kb%<I>jvc#22UB*f|sR~%$VHgnffO2Da2l7hN)@9_aGYXrjD zUJfS$yEIhC#WTL#>;;{wyhR>Teg)I{?>ax$r@A<{8Bji}1yr-eVwcyQxpRwEmS>W^ zHu<Amu&)N6hGIs|N2OoL4;(%2dJj6SbKy7pu)*+vd{!i8OX>P^EY6a(?2?m+2_$(E zv7YLWyx2&L*`!#q%Y2~pZ!*23K<|@ZmU=xlyP=@kg_kxdyyWGWnlM^{NuR7fYfkHq z$m;ymf%-NRpTTILH~a|i*IU$8<nDeW^OS=dW^N}B+?D#XjiD=N;_r2)k2gJ5Se$Ed zV5Hh^R@mnWKgk&t@2fHunR~HjYt$fH(_9l!z6pq=L};$WU8Aeygu~q+WH2o9s-Hx1 zX+t<>wkxu4U%w%!W?GlW=8#Y-e)Bs8z`N6vfl`Y_ee-@Md+ZovWQFtY=?cSnySh6F zT5K-`e`Cr$6*bmGS1gG+k+}OY!&NGv9Jgf=*k6m&4zm5r05ykuGO4Hds}Vy|2gbbU zgP<FZS(C`#1VU=qCjUwA2F51~5;yP7Ns{TojGc$#t9+9(NTQ}zRdfR1(i@MV9>JQ7 z;HnMAXPxHE@eUzoZ|KN}4Yn7#a&`MFSFJ=$cp~JZ*{b)*JY2AKutT&LC?;S9-?aoW zZ`vwTmYJ0HTyOal*bAr<4Gy(4CCZ|Zt)!be><6Q>)A=;#VZo|jhzZaJ7aV4TyDIvI z0$a_z9l&HQudR)&ctO!73lj_NF?=KTr&7XnB`BLT!Un5^mM_j#{E65uek;%{ARA~$ z2V_uj9F<be=XIh(r3_#G0En^Og{kN|MUDc(N*BltcbfogwD7C)XDK!prm_Qf>?-i1 zxl8crMl%(#*;WsAn`N}}I>gx;X|{v!1bBDGH+F(Id8)BHoTfcU!z?mh0UgP@F=D(W zOR{&usV2(z!s{{-VpCYReFe}|X{}ud0MD>qTuCuwcVa$gXG%mQT=+uc_(ULSh-P@I zgU%Oh$8UQMT1>~S=pF}!m!*|XLJPL}7oxS=TEc-!NDo8GtqsWtrWPWi-x4C8150%Z zu9?gOD>X4B0b5M<R3o!9ny}S+D?JYk6AUYs1$289Ip?ZYd+2>w-BA`GSiH;L&MhOh zdRc0iRB<F4zd!35|4g=@ikfuo1mQg7_3{}koYiy+95;w`s7__DdVD#3Qo%{IYV(*m z9d9aE@XML#^?dJAtBFCW&(_$k0N&OY>$F`Z(l4?4%m3(F`!D~pi^-hD)W0AfH`YeJ zy109)Hc}1(x4U~Gyo1Jif!<P<_$2drTB5ve%fgqrf>|-oGit4dz0<~42`Hf{3z6Y` zR5K{tL~())(UlmxEdVS*<&?x{Auz}cXx6)4z%AMI99>Q1A=Dag1t%-RA5Tghmbn_E zKk%xTl5%>lu-gT;q#M8fg%@yYg8zBaGT7>cg1vl{Nb`;wP2D6VcUvyXK$`GV*l?RY zkVTK$N!gpx&qrN@skS;%?sL&7cb`CcA;Bt@9qDMQ&4uF@`L9Uv8AM{iVkyF+rW4Rv zhn6yPU6%s$HpPQ=QkHLEuCCm{_4{R{V{g649k{169Q8Mco<K+{6#URq$CrY@)<@(k zza}_)8t)C&MVx*HDre2yNF;XUM37Sxlx4z#;pod!oLxM4Ho`g|_ma$8C4t@4jg(=? zY+CgUCK!wQE(B#Anf0Lgk*T{q9a+KR<i$&uqJXan$wrCY?O4%G(UuF<oj7<~7Amo% zB-9fDOjy{hMrszWU)T7JKUtAijPVN1q`zTLWP9<eBeB%_t^e!>Z5A%=-V<4DEEljw zBd)F4`p==<k^r1`A+UK&$DIaBjhp_sc!2e;EAkAtSMw^0RvE?VovME9m?_5v+n03> z{L5hPPwuDrkIC4D4{MwUpjA&`m>-RmHotX6{1wRjJJXOes2bEgPdd$bHnmj@sb-{M zz#>x~I74<pU_!nT3C~GFzqCE@6QQQdrY;{fHx~W5X{WqfP_Slj9Y~gwG+CMVA7|)B zC4njjbllg-u5BnGEM;S^@qnUF%1#+0{v=4FpSq2xi<m0TI_~;tafBJANpgPb!)0cs zC3FvPiF(^o1;nZUp;dD@qb3~#n7Jg0$0@Sq-tuZz4!_L@&|%pfOcO5J^@w#nXfTHz zAlf*R%%4Yo7>oBavQqputJVT!0CpW?u&Wq;J%ma;5TpIClV58xU4!ZH9_CVAs!8j< zI1zqeSMgF3Hs!S&h4OBSR9KtZ#f!XFzT$AVxu5R-+jj5PK+W34rV@L`Dc~o26ecQO zc#vPkh_=u?uyhGBC>0I~$3-RlN^6E5qEr@|&I>RZU}!Q$Gpal+<lsTPT?KDV`o)QL zGc=%+D^1|(54$OyEGA|7!E{w)w1vtv9Tpz#QfkTDg<|W90raNqdWgGOwGbcIHmgBc zoq(ojWp<k7svVRRDS_M^U%<+l;*nBA$ABnLQ#Q#d&&Fs8F4bMc^fX~xFI6NskmLeF zz3y(Rm!>7L+`+R5yCzEWo?yLVWdR{H8<MHMT|19pm_k_MzKr80q^w5(@tTNNi!|z3 zs6OG6#J6ay)kqJ5bgM1}vfB#++Dv8xKU@u*Qkctzb*$zc2iTLD4d=z;rC>XVS9=7m zFW-UYU_0hdMIfKt(gl+j4C87gOXEr<{3)-OgP#SX`LtZDfVWuDx>(Sgo^1ii`IbyC zcZ}Wu9}%F3i-6mg#F}0x`HK_JUHM=kt(1$q(#IR?w*0pKql5yZGW+);d*r!$Jso<m zv-t`Be*z_jL+?+#gT^yg{P^uO#q&C}3XO~(!*1i6hP_2An^&SSqcu~2M5&TbZY2^c zzkDPWa=g_6=)X}%L5G9{W+j!ZUH5Q?FlT|Rw*%;A<AR=QqIbO5&qpaGOdC8UgdH9q zuHx0UPq}WcN}vACs4fM#R*|HE99kg!=6Me3jlXgn#%Mj_dcT1Dv<Ic0A`K0#-^YDy zGy%9v_i_4y+zlf&DV008Sd;;`H@TzGlv%W<6*B;<23{O$kXx$p2Jqgn7fS3TYattV z8i;>_6MFW`<2-tt)nC3S>|wLST^!!Bg%E!0D|D6b3PAk^c6(z0%DNqVuU1=7>{Sjp zGYKj$3ndZwf-`8>`<imY)In|<-YPd`DslJ|rJG7kC3dqrn+2xr*GyAxip^;_p)AzI z;Dd&@X4Wo(p!*@JdkmfbBxNvsDY0WQvh&1ip=Axgv25On!!?V_?qhEDWV+{&WtiT( zS=|!b$wt9aPxTcom=e)-=Boj59GMv^DiPTIO=Jq|6{O|=1tmNG))SOH*xj9KkFWmm zvR<gMwCKx@`UZutiFJ*Ux$tDtQUx<F18%>0|KY0Yc$nvF3Kr?vwt?ljy)VlzNSuy> z$c@v-LW8fYSkoT3w`p&ft)5>?{7z^rB{g|mg}Y7TwO@nD=J=sxl;`Z2V#=Q4jFk)K zwh>QOi(m{IY~Cycc>qfmF*-G_77D;!Jea|ugPV6N{>0xM##F7cJ{P=xpG7X9vV++t zHA@S?LYFsmP{9!RG<tPkmJ&>=rUx*expPAotqdBH-TexLclfh(R*drap`AQGVKc3U zyxQ)C1}&$UhC-W<Ax71&%&=Iv__8I4X>UlVnRgsaCLWa!W-3z!2&a{fy0Y8qmC&?V zfGMdts!Y`~tB%N3R;q_E72s=s^5bXA?@$+^6RU;K)6C3L6v2y%(@O`4M&+yXp@NYe z61(J;02>ewyd+L6bPc4w)$Y+)njA`bKw({0O+L4XQC2~sXm3n<^2j29*LQOx-TD=6 zLE<8Q!GnXz!@T@CC66UW;~XMtx`2{i%Rw<sL0h0fSPmFgHbbvrkZW&Am-473fYEj> zB?KME;1t9X7zVdwyW&84M-q`Mc9;QVLQO+bKhKK3YaT~HT_mK9Mv-fk`!ZAwY3quh zNl=L@iyJJ3x+Mg(!H##gk4XHk;A1bz@NJ2~V$k5Zt!oaRGB)fyZk?6ZvM4&$?P#=C zaB^MIAtu_vC}tZ2v+VV>c0cI>K&+JFal~(hq<W^fkl?8_;ev=cd_AOsgC4@ux5rj! z!R`dilq2PgT_vV$&5o&UG6w|nd~l?Piij<8nXFg*iY{L|r<HHwQp@IigyI%>rt`@y znpP4@n_7hW5)-sVjpT8z^yb_6;@nW}Si<sA?g108Rm13bZqB(B92i*|hg=_8e>${A z7%;>(;ab5fN~ErF$T?Sj6^j4Ye+~Zoe}d=MSiGuX1-Q#OQ6p9<4jdoW9RY}NM1Rmy zeTvP#(Qm_|U&i9~?ukv?>u`@l<@S`=l#%8`!1h*vR(0|}uaZWagZiwwT;ssB^ICm` z8jgTlr(2u7N-GrQNf#tF!;Vu0ZX%XRT+wJ|iz2$?4|#?N@9ilTDbE0`RB6pISpmM* zw#em0aDM#@m~Y;z#(WiA-qrrma9gK_eIUXeQ}ihrep-XYCvJ$>@>z!p*1EOP8Gz=B zQgJMJtp&4usMa8Evo>rRK<iNnznS?S^%!pOSgDmad0Wc-kkuToW&*pFR(o`3JJ3wk zy&rutDx5jetdx}Z)LG81$C?LbQDH}FsiY7UHc~4P7Zo-T_ns>D+Tr`Q>Xewxij5%a z0HVUgoPk)4#safSG|TR_0Uig!7NdFuj~BbQ$dXaQ<5vM+Y0&O&A9yqT*9Tr`G0$Es ztbGsMeH8rNTVFkVCVrv%aQ)YJlmOdDHpVtw*b#Ys^Q8o+-m*L$&d27hbV74M9(ksM z?Itn%2Jh(45{{LUzoNvRv{Y03CD0O<T+eerZezR-q|+u&JD6Q@EMkT&q_}tbSW+*E z4}#+jN+s`PbT>W#@$Cx3eED0Qi*J4>kRi@A9_F#}%<e^uZiHw*ykI&JZERi>V@<fy z$_`9XnG65A;nS$i);{Zx(0;zI)1j#^Kv(D?W6{QUvoLi{iq0A`{TjVjg}~CHg~4xC zY9KaJ`WO|$K_#rfcsa&OU<u-D-l)u7t4SLxK?H=sTyf?*2{;RcnYx`HyV6-JFh)Fv zT<dQcx>eC&PXDkl+Damrq|L77(Ohg-)a5+pc7m9{<C;EFp;NL^?Dl0^9TcRZe9%^% zMapteqLq}g0w*!r4kmNNwX<tC@{<+yPUjo+G6j@qSp`&6XTi)6wNPrM7y!;;#R-Jz z(VCleEYO@&(H82NPN&3rW@NAQ_uvSd;M|vAQO)n_?%q*Jvu>Jay1f8#_MlIHNdUoi zA9Os{TwH#&ntaQz(XNYN4ZPXez)*}TX~OLlK2m$&^;&ouL-u>OOkk^e^Ea-&mo<{| zlPhX!Hk|`ejT)QLTPR^yR`32>-Z{gmxXBu$$h(#>p2IoA>WpqD-NistjiIIjUqWS0 z$>psa5L2kjsp_48XJfdUc>#NqAT8N3Qq69bMnI@lYn&NS=q0NGd=QUA2CgsBn2%jY z2p{<hT)PtCTYyV`tTI}r?@DdnCEJ#vR8Gpu2Z;*<;Oa#bQNF$;AT5{=Y<9BVTJE?K zz=#4jB!me>a}9uzsqd*ur!q%SOki0~Gv}imR}N8ZYqBR|RT60H^x{>6N4PK$F0;U` zA~M(V##|r8%v<N1RPR$z6&4H=a|^Xz-<HsmgF)+^;A~>MxUWLd%3Vu&)<pu2QdR)| zYpJiCscMpB2E3y8Ymq8~gJ<bZOs#aD^f({FVL7L4;cQEG&Ebm*&dUvOPPZ3MbDjG? zvKoJU{wsqfRVRWO6s}Fw0k!;BZG?Fopys)`+sg@v>N%J>0%(Sf47Ej*Ez&h!>MPtK z;t@PW0KF)X9BBf`lZj}qR1WyJW|0hI|DC3cxCG~)Yk<d0T*A-<t7(ZM>-18WiZ2|Y zMh}*}{qBeMkZZiyQ$OJldUQD7ALfl|GFR~E!qo6`$FBbYCECiZtfCmKrpv;B(*x7m zltyWl|1!gwvvHENjSf4bnR%M4a+BZn{9mv9@H;|jk37${Ei>0IeaCpW3o}E2y=sct z+Vo63%OJjC$Ng5Z=;yC)93|TMB}>?fFErmX$2v89pBVaE3BW?He?5uiCVw;1HGwFN z-e&OFNcD}OEC=0QXgL$*@&|V905{~9Z+4?XhhWt=yPQ=WIjeQU$3RlZFM~kt?l5<2 zg2-^ZlRy=8`GY44xjWs|K)~wc<$L0X!QWR=uobkr3(I&Nk3BT<=<?amIm&Yenqr}o zsdD#x-M)NJUun~(;n499VjJtM+c&TH=D3nif$$VLsAJf+MI@_g1llB)i(eR+s(SM~ zHislbSmEcLe+y>QyAKjqVGK{8W-}%PgsXj6oVbX|+^dJ)1%u5amKQw%eRh!C^?xhf zoWe&g;79{1AwIU=`0!P>!r7HVDZX>8=<g2}S?Kx4rFR?MJ>7Nyh;EA9zxj*@$gj73 zZp8N!=Mm>JW7Pj&0{7-OfZDp{1n&76BU!9?FNvzy#Ff4BSR)$rbs4RR){dr*0j7rJ zD081V$w86m9le?i`sA*9;!>3ZO{XEia*A^fsP7+erthB^GYD^kyUz6G#~hpP%`(Ca z)6RJXD%};h1`m$+Ca;x8X_6u+&B)KFrhs9+E&P=u1seXUHmPU}2)l9L%_z&2U^s>{ z^qkG2V5@ZQ5l!@F+2j!6=gPsCe(18$xWXW^f?UM8av4QR<~#Ko&so#B5}?JHc_)?a z)6du?s!XLKQR<hO>y5HL#^~|ZhWce7Gt6vdSo$!L;Bf|pKvl8Rd{}S=Jy6v#O`7H% zZ|%eJ%^)vWX+Rg82%|1P*QP*~==CT7uUDhv>c#w=E|rQcO#T>ht2-nZ!w^l}-q@a= zWGeTdVK1Fb%)ctW3`h#|LwL+upvF--8R2bPA5NzpM*ih@DX{X~cB7t<Y|dedZe!K! zOClBmQeWlpQM^zXmQ?Br?rIrnSn)7D^gPifUyX{#xD3g~0EV#-bJisQ(YAWAXCPSz z;rY;i*dXvL?-A2gsV@$U&|4JMSTLt$l-tZ@e%Q+h&t-9URV`j$LQ34+U#$a2Qsq+# zj76~d67YL<B_Vy+Qcf%aH=V+YtV-sbN=t~AVC@w#@6VEr%vWNlZiB~=SuPjougbjZ zptcQIZaZM7nG_@oSgrkoV3iiax+0QoxABDmoKA-3RI;Qwk0~(*M^^U-$AQ`c{h%|S z1?Aj4Y#qhzZ*__|j|7^DPz!{m$V+Wtwn;L&Vc?uF$JI$_t%DZV@y~#K;3_-VDM$Qk zPYrX-x1B)g{)39ao~b{&R`tuj)LY;5R6ISD&W;2ca$w3|otH;SBb4x2^YxgA%44yn z6S^A(d|ttL;9As=f<d<jKxIR8q^BOhIXwi0Ryupj!oHUSLhJs-s`~D!+HZ(#x0i$E zqeByG*r8)CvN}ApmOI;+=uSVQRXB{b3@tWk*_iXFkHUq+ZT==4tA-L&_G4QP*o}g} zHi1TL$?CK1A93(!!)^2?dOA1j#nHKeXcL-ka~xXsj>j|pu{>p6H*f`@@<rxcuX{$d zrhOIf%7mb=O8v%DejJTjQ@Y;ButtmA<dLNA-=J2bMrVeQJfk@yVY>j90$e`(^(K$Z zh;Cq^z&YvGzyA1_3mXSqY?~tDk|t4N+n(x1h-_!718$2*`xqWxzu_$OdsYCt%FQe7 zQAxkk!1bWliGhGlJ`1F+067KiW*PgG+4UY@lk{!43<DSb>h7~B+jlveco7GH4|ims zJ9HxZ<mGbUHx@FUT-uY~m(1wdg&AJ`7QFgsJ*-}s9)5WFA6RGc2D+edhl`1Ffyc#g zSb+GwfFrm@oB7eH%*Qmn3wF<cqU655(cy6M@WmHOcGjhfseLq3Y=C?Z|5c~oY?s|! z{a6YFHVh9LSKldC-c+-7I>fuek&Ad#KdKA4VCQ?ufS^2l$Z}ynCdUPzUi{<I7}7N? zwr!&Ix%?-G6VEPQ`43F~b|6eQ2yjiZKKffAwvk~d^f4iJ_kRiG9P<DhTI}LoWUMr^ zbY-s%>*jYqA;!$@BDZvBaj8nIM6$_y-G@vKkOR5gs39Ru1L8oe?SRO3ZW)|f!$!N9 zC5D~z5{0q?z~46|b@Mk$cr4K%n|NI|6Tt+#cB4$MBJgFLmb8{WLtN%A((`_`J4F@C z(t0`Wh7+sqk>4=_-4dRn_!W?C)yaS^OH|hxi(YQg>PWgYq`F4p(mI|@W1bpOklJ4O z6ij=o?<<RAgUqOTBIC)o$!K91BV028T)weg7-P^3CSwf?nl&VJkl)da9i{h5iOz$< z?rP5)27XbYfg7OuWC%iKxa+yc0%R{m4f6H?t%XR=b@;}mFj+x)8Eo4Ikc@7hhN2*U zdpPRnyErEAaS2xF3*^w(?Y_4D9Ls5V2*-C;0!(krr;vVbimupeMg5@BU<JEcxNPVF zGlio#wg9@qV<ONS0a;Va%_r6w>gZ5fHxFwvyh+eXmRSr~GrmqUFji%61=qLybrn)K zpC_@4_jhBl0(fKDK;?D5lmwNN0X00A;TSL@Y$(-wwU3~flZtt3E>3W$>!!Q}v*wq? z-{d~)MGiz~sxJIg7F`}-K0U^Vl@fF4JOblI{*F?@;l;sXZGIlhL~BO0J*QjsntUA{ zik~N0OTf7r*QdF|t}cMY9K-i<*uGU~FdmGsZfd^H#v5xgbGU8}ja%9>U^SJ5!8xX? zH$nQ?RSq2Vh`8uEBDua2$FubebaQj9Jx?1tUZ;x<s5KuXOFBUgZhffdm(!>hKlxS9 zpWpf95Z4g5T+t=Z+avTTU+w%DHa~dIAbc$q1A#1&<dxFE0bg^go#aigjFD-+l&F#E z%T6U<74kW@*!c0M1l!|Z`S1y%jw|xGN6fsa1>kQz$e@BAeyWBP_~<~<dQd!58~H^v z<ajYgwxi%*2!|zN-(OV0;`5>{nAcWHb%T2?|JYIOrm8{OA{B~8hz6KZyep{E@G7+& zPo6ArcY(a&vk?77t#uCD%%|3&3~r<Lw9{+U1SwrwYgxVf$a2-%K&^&*y-{P!Zrepb zp7iSstU8kHH+@*>tHd4ATi=t3T{~1Q^)q9cl8wq)96Ym0KtZe{e(1|8wZyy;t8G(& zoBSnV?E=!75)P}=kT`voaF*q=1-gP_t9&#&+-cec>oW2-H?3m>rQ6-qVf|hWO&@6- z*ns!~^GOTbZk{@a&(P`8eMYBEqn4x%ojwuB;PV`x9((w_MzS}zt8^hy-uHWk+fecP z!kR_A&cpeI=-v;m&Plyg|HxGGz&*!;R84+x&&HLrGGO1lp9D1_Xw2r4lKVhlnaw!F zDy4!UYx#kIIeehnq;ODHMl<p>`LUwUyw?sl=-!F)=i3X)ir;Lfl7qIbopm66J=oqV z-+Sw{_%lIlJt|PIODo&`=6Br2^AyhtD%FkqoQOX8<}MGf@tgxq<6*4k`<59>pWR$B zNG1$LTJE#Ova^NY;IDYK!*X>_W@z{ny13?+6de=l@|f54p{XbZw>&~EVmx%_5!c&M z_d&3HQ-Isjy+xtNYc=<j(_ur$SwrJlYVp8d&PnEP<bgob8}$npK-2RZQNVM{q?`lN z9jeZ<L^RU2a%-Mfo!`RL@m3)_C_Nd95cTrri4P40=;9~?R}-2MCM8xbqnVi~EjB*{ z$|8a93B;zSC1Oi7hm~{5ZvuCVbyz)BTd7LsR`OqE+I}aU8^+)sLjY8_$J?)ksnPOb zIt)DalJFWkC|O#t442LTb#b`s{bq=w1JCaX@D>5;x4d&AZ<rTwW1kQ^DdH`q+dO3{ zu%-I}{yc}~#>qE2tCs_DDWEzJ0Y9-X_nv^SZ8B)$9%iK4G@vZzJZh>gfAd7`svB|n zEjiM5<#37PVMyADlgP0;dhKQ4q;MM75ZZoF88o#wLK&ql8#x81#Yu&$N}3I(*oH3H zx55tF2%wF1yxt$6h39hFfX7^+&m!{dP|9iC(I`F0e5o7b^!<aFsxBr^#`D_x`Z&^6 zQe)bshaaog#@s$U%|>k#33lnOIg-}7u3(N<k89?}I4)3mZeu)MYQw{AuxAO+h}5K> z6*`N16<BuBVtRnswGvo5n9dt%9pa0(og#b%0J?EC)lq}aR)z@(3hvy{wF7ZWl>vn3 zjWlZ{nE^4o7T{_t3sEDXiDZVAX|6siA6))2e!0@y?80@x%9RMPFYREI<JsIYUyX;z zi14!_+$=z}HA496+w|dBZN&AJ3x})0i>c^Lj9cT)ar_ePVqnM6PopeKc<jGd|KTlf zkHi|Qzx~xP>xZ@rv?uQ19$Mb^i?oC2wW*t)9O9&P@APdNzw&f+g}uKObc`D8)qJzq zb@Z9i(8ntkEK|tLByqg$Mefl$k@b&Z-$zY(M^Dd(zn`wb-_~^iOk4@_mhzgaHD5&% z_j*Ct$H3^7M0AvKx1tvAt#K(QpA!bNUG1)>!^G=F8~9J^W9uC;4t&)m#*Aejaj%oM zu2zo;_R_+wkEXtBu<qEidPZEXOUAd?fO%w5tKl#~G(V7yB+j+L*-PIcn%%{wp_u}Y znRM7Hg{U(u8fv|$HN%oE!|kQJykPgG5zmeuQu~%~EL+Cfi(|XT!C6oK&QRxB9`p^G zHzax1Q`gIF_A=Pct_ES12iHKc@o9gym=y@(!Xn&u^MdtfB`+b0-;D~M0p|OQFp@2= z4Rkl`0c=siA4MF`$7@#J>yr4iON#xT;kA>$UxAQ23;Mmm89Vwsb~LiMb#Fboe3K}- z@V$QNdy7IRHebqzmml1C&xUJ;*9XAso&)!#djHtSc<9c&;`4nPmRhzUEcjK=hrDCy z)>zSD%~DC-Hjs{9)k@n}+P^=+g7*^P@n9FP>K+{~FDTaJR9k~RJAA?Bq}r@!3zSx! z*4B%`^)-=_r+@TnL7)g7d|gbOns9ayDSb_hf=bl#(lBdk4Z)$>DUiH1Ax3@jp){;n zvrvT>P2GOLacm7F!=r=86KK*y#<8in$~9ys2FBC>x&ehc1JFF_%(DZ5PlD3I2SH%z z)Wpho%^gVH#K(+HyNN5NpA;V(kOhqlKG*?`Rtl|E2{K+$ib7uNn01yG@_iE8`aWVZ zM0oSZS~8T+<-lL<U^_uSFm5Tb{072Z*|n8JCnSEOrN4}LzVIj{mjNb-{<uW)L&sZD z$IE0X$F87m;~2jTY?tZKF?rIh98bKtY^m1nu@qL7T&?}4odfGbPrHey>3r=9y1?tF zJDGpNxAqBkrxq3ExVZQ9m7eLMsss$WG=92f9;gVWB3P%V7u6e6mO|ZqaP^kE#;%GQ zUIkP?a<cO{My>>5ADYdT<~bJEb}p&LjMSC|O%?SvehgkY?1aGTA>-5+cWM$?$Ln)% z0M-Mq2&3xzkbdr7tkkm1O!3c$?OvA{<H%By1A233DZ^M-#fK02R|UoyK~`@h>o7x2 zF8g+9oL}-%g86veyTzP&mH=DV2yV^^0BrxztYd3t)<-7SRqAyx$BH-+143rBOj5SK z>7AS>mjq>n4B5E68Co`C@J5ww!nkw5D4YObsEv2!kr8U7g=h+cThN+s$%;9^XxYzv zI4iq!LG)OxahsFLh5z0nBl*m0+`9!~-+O>K^M$2)>-xsx@g`em&P6e=i7at@fUeNE zH*XNy>*CxoJcPo*b9Mn?DQitfb$%$+6XE5MlEmE%RJNAzHrZ#a0=)T`?0nJX@L<8N z8d_<zMkNbix-^=hw?MEB)SX1GQZMI6_}3jA9#cZOwlyBPx1p=^Zdw}T=Tw*iE3uNz zMx_#vDr5uX?gn^gMZryszrCojruL7n{r)fiqhNWJ<;ex%1K+-luOa<a2@JQ51Kwie z6}8ph&gWEbleV67W!eOp{n7tp=NAj--dc6+e`{*r(emHEe__*)nA&QklQ)<V+>N29 zkH=a&<aAf90ljMyWY!SH8dflT?UeO#CE6T_JHB4mbi$|b$nToaK6E_RP_L-lq2U$t zQrT%<qLsS$7?x9c?F};%rmQe?d#A6suky@oCb_s40Fcf27WaPV3lV7lE-`eky3(v{ zdk_=($gQ-E^bkx_+1I^A-*rN`dFFFp>Z0rNBZjBclgR-#vR*f3!_}F6xPo_pK7P;} zK6X$1MhXTG6g#Hxa^MtoN?A8|8xEW)67kaACY=*u^K;@v!hK~M_;nF6C!Jg2hjzZt z!v9%M9q>hPFHQFA(z(l^$-Op1+LjeL%i2n&57*z%F!Iw(P?6|XbQ_V|g5DMicY?W| z;R)s-dbVV5>FAyt?YY<HOmkaGw{x!_cJ6h^D7mB9`9QTG`vTA{irogqz7M;*(xmb2 zVEj;11K9pS%%0?U_@m1?QZSrof4}Fz^Ox6e66Njgo^Co(u(L)J%FyN-ON0T}-D~!U zD94?gUXNma@ANlUUifX<&|=lR`r_6z62(QUU*OgCB~RDATCnC7J^nEJBzQPj5S~s& zKRXPP<BIp&xYakqA61*Z-v7Aj!+4L!UuFENWM|C_#Mk1BCrX)j7U^!A7}y*51(5#z z`9Ftie~=1Yc~t=ZEO39~KW||48Ie5E{l~O+b<#5OD!Fh-xCir&bt|%FxwPE%7~(Tb zTohiAkN-_P?3KIzgD;ZTwoO^k4Bfo#^z%S{2UTJp3912hW6uPtRZoI4EvPpOd?@Fo ziCA_NxCXVK*Tuj<Oz?dck-dI`?MPe#$n+LpRy<r$Zi|C=)+V-Y{@5a70&Mz2Mn+y( zxByu16eq`R)+Rya*3{$m6iPZtvnz)Eukjv}$mf$J#rxQtv=zIYG@H?N0z~ogWx{xW z8Lp%7g#iD2)jd~Kf#c9<+M*MuuB~ea${%d)3+NFDbwM#CGHs?be>!Ylr5USIIOlCV z38X+%|0qpIp&0Z|v38@pq71^~>la~px`)?0w;E3Cy&TeP7X*S(q5i!(5u?AQ24~Gm zV`o4bW!E%qJK6|$D?F{2*g<3%{~ASiBUZEDt=VRXNrsDvl0H+C4S9hhk$N@}oGX|l zYbOM?K+g3-Kn7`7_$-&4&$&oF&?fkbKSOt=rV|j$If(mOQTYR1<s`@6IU}OWOQ6`g z%7D6S0@>W_waC&euYd%9JY~~lgNL}sjb`cBv(8F`TqN$zskR3>V=AG!n8EI@Yei+Y zt@C{Pj#Jlsl^`13E}*r+D<0AGwacv81k?n^wbXXb1ks)#UBetsQeHA-^n8HNJ7rf1 zsg(+habbi;z%>bQ$%`z1ZXb}V50z!>G*(IiR}zh@0NOKQgjvtv9w=<*Md>U)#+%}J z^QoZcHj+iiyF`}+T%y2_DZu71c;Q@UiN||Ryb0o=9stvvY~LXFJbmG;v(H7tot|I^ zY*d<ECzs1J=9Y0mU_GC{jn0>I>kFZsHIct~{qH~dfB08!to)}kEqcfuM}&_Fzxz8s zX3Ba1*3N@lTcGmoP<6hj+r}r#*7WZeZ;!y^+w@Em6JYOc+~$iJ63Y+8v+%;f^Va@8 zHw7lLer+ZV_ZuMIroG4E^$d)~hX#-0n44gqB(Gkti-D%MPp)BFGcgvs+7oNt{rJ5I z?5}w=-HGt$6i4@cZj$7h@}8@96q~cgpcar@(p!UC5NqMG$?1~?PLG$5{ktaL&#?19 zw{~tw{Jw0>ZqX|y4c+W>SDGym8~AoHHKc!wsVOM7#xiaa4C+PgGZS0b^IR?Lps&Ou z>NeZuiT1PD_w3m$v3DD-(u+(C&(ut-Mmq!K%vH|<@(j724diuPqj+KRyS?z5F>Z1C zPcDTWQCBh?#NK8C`B|gn7U))lJoS4L*1bfUdj>n2Dm;)@Q0=|JZHC3FBRRO?!k=9e zFzbg|z&!G>Bi|0m$*mbkBeX-rC7gRiJhGSf?W~UuzZDmAk1DKo;$-S>r?dwyz42J# zorTMuS$)UPq49$Fh3it$XV#2f-M3)6>4i0;!-<7`2;@e^Wk*kuJ9{Sllkg;BJ97HU zsp|F9dctQZTlX;97W?g*O~a|r4p%E>c5C!A^RLC#yL+dZ#y%K~wjXb*fBHv==`9Y< zVe4lg`tbjiAFab6Dt_~!x0nXIbouI$rA5&K{n!=$Z202%&cE8~6Z5IBK*Osx<-B^d zd|l@QvbqbW0{4<K1A(~}6pWwUd}fgO=&|1XXBW@^heTHB3PAn(<A29}XBmT*jP7pb z*c=%5J;1GvcYypl@)2C{Y?1MAJrT%~9^T+#J2*acrg<PRfCQgkPt&L3<7dUbvlT_} zI5El?n347sso?Vl-8FAixrf5lV0mN0q;<mS+7QfaHE;8M9P?GWhgFGB;jO>fQfVk% zM2rjz+oR+oK)c>oeVqv5V)!`bnw(ZA37aQ0+{MV)(~N)hs6cEF#hWh&-gL5ggB)~& zb7X(8UeCFDpk{6m%sM<czT6D!RQ=jO?-fA1sP6sd?@8<yNAK<h*e&U8cM0411>Xx{ zUSxSSLHdr9W+6K`6-vXFAAF7<h2$dg5VTnwoidJLW8}Xh%m)W}bx79(QsKc|C*B(! z22Ii6EvqIYTUcKfm?nk|QI$@w*9b4CjfeAEA-TrB@@T?DgLenprFXGvQ2!Y6i*-gA zr3#;)kiI@<I<*<#K%t#*k1i1;^ZKv0Vo`qG3l5bFhlo0Uzu#8(+SD^xtFHs;{US7# zFN}=Vb*^C&yNH}aq7^x3$_f(z#L~z$R|4|AVes<Dbt)X(P|_AnIpn27TNf146Lfvy zrN_Z(O*-4xB<(?`262w^?f^P5GMNyF7zVZWkHJTydQ;)FY%Ucvh~3EGodwdkt|)Qv zjqJ^Jl2@1_yrl>Ys!kg>w-_M<wzmnp$)a)9fwD~s{O*|;xi$q8Dg&WCy<Yh0=B35` zA@(6&BuU_I3);^)q0E9^O<4ABJ691<dnEPQbJxtj`x*9|GM4~|^j>1l$@@7Vtd>IA z)?;WpLWoNX+V#bNzC&z+zP^5jz!h){BpYrzkA(h{U%mL}c@ornw;EIDomxn`p*rM_ zbNSP-_C<ZQFFl8I&UY~m=-&1Y+I)l4<A3@(*G}oLN+aPP|3$7J?6qaZKFW`<c#5Z% z#)r0<jL)(;!F+5gBDi+*XG;fGg44m$cj9n*V7$C0@eE8nj$h_u`l0mreTh{o9J%kl zqGx+KyCTv0w@;P;_oe5+awGsPb96CxXQXRxI|^Pqy6uu`&OvXpq3)|MizZK>N_p$5 zERc>4uRyvO_&0QkKr@Qxb6ew?S?JJsjY_Yz$?#1R8k%0CN-?v>qhoPK&r}#{3omS@ zI(*XAk(g8tyPwsja$WIp0(4Oqj1$)1m??Ln`i;@HjK^K&d)zJREz#T-&iEn!3c$@- z-|Pmpx4Daf6Y*|bYv+tJ*X7?FEHV$A06E1cM9uazC~hWPH+Z&vPN?45uV?G-_XeLa z*<B;o;_YJP0d<Sr<CAG}<TJND@%%<6?u+L>;7dGzss5XW+2)R)ctgs1^1!SI(ml)f z=kM6O`ac##yHCf*s!wq#@ZjX7*A3aXSEXB;nkSaBrx-F_Z`6E6DlX4D{L&A@VTQKS zZ$32G+kIq{evTEXK&3w(ceMJ^;?VHXnym+mip&syC@B-YZ?v?bJJo(Z^;qAdj;sHO zdT$O7XNP^S87;j4jKjwJAGiBg^gnLHV5@()CbqD5`eOal6EEb4uB1jjZ$8sp9JwDX zZs~re>J~KZERpbYdeA56fvE>_UOh8x?J37{*TdBn7ti75*9_5_{4)N|OR>*?`dg8E zjZA+eDL$tYA6!k`;OpSfk@L$sqmH5XR1$row+v)wCQQ#toxcNf93KC*HP!a~0q}ef z$($!1Hsc(uZes3Qb!2BZr(S;^?1!cA+_1-82OLQ)zaub+SWe=NtA`GItb;)<#mkA6 z2R?0jdfMo?2FvnlD>1W8P#1Iy;RV`y+(134>1i452<HmAJq7(X-mVqHC9AlyhtqRt z#=vB#i;ZXbC=S0iGg~btrBH4k#fJ}W8ee`doEs)BI35PR*X=m@;B(;m*IdDuI6KT7 zi2usPngOq|1mFivujr^K(+>WPWNTrC0^;bU9($M3F6d3m5kE`>PK8^buR|sysKb!k zSz<es-+$2+!83_EPz<>3Ql`xXyMRHD#)HuOo?p2{<l6eWmA%so#F;JSR!=FJp5A3e zU4X7Y6ol3%maMDS8b!uk*L0FDBy|0tyfndYJ!<~HdCx*_-A^5=oNoE)b>O5!QKqed zg|i@wQFwFqZ{Xcp<s@(e;ge#f(%ZfD!^rU&c;9pmDO>Z>jvVX#G^`E*=6!&FT^I48 zfnuGRI|?LtjRSw=YRT!|kT%)93f|H(XYhJmUl_L8saoh=Fs+lyD&ryvP}GHkkef>d z7G>}Q#zuOOuL+#CWFFw|`cuF(PFv4b!&{G)!IWgJ4L32kZCXC&w{5DjiwL_0NoI}g z0w<eW!B`;POQ$KDpXp4|>J!uYE&SGqpPz$Ro}-HjJ5QS(2xed68?<S+Sp(uWs%B@q zecNE7BC`9OcfDYtI;?b{8dU!X7}kK<-~YePGoNOo_9_71`RQWmT&B$9vBH6G>oR0= z?Or5{+;R3|RQ}U_oJciya~1I9Yhkf@w2N;q>8EaGJp>+WAHI%kf9jv4KJ@<6s&<rt zY+W62wA-YDi0c=B+!AdGW;4+l7-LNBKG%dwM(#5IM^<W%6*m9Gq+9fv5{;`V3@@*p z+ZsOy+gp!jCe~|eBlkS+1@&GI6R#Vm@O$E(1Os6hIFzYirGJ9{OptC1I~%9yFJs_~ zxpCE-GUWEI6mcjuv2vy0u38`-=C9DZx5n`c)Ojz{HUu~R(09JohbGi_#ihsFluoA~ z)YIK(5qC?cyCAw&KZ^Eyr7Tt%u4PkIuE%9|VlBhW1;*I|<9~d>*XU<q_^$(Z2JS&? z5AHRl{fZx66Y^^;tfj&(0&GI87;65>r8{iqYs9i^<k!}3tfvyCDU(kJ*aL1VY}2e6 zvS*A?f8D70CnU>rZ8E!lNr2n`%~*QRf$iw<--CsVjoSmcyy!i~x}RBnSL#jh`Ju4W z)gQbB0}sK#$Ltz`2Wpl|mEZino_W4{top5PLv!);Jf77zu)ZmD@{yk99Tpb<VjYMI ztv<7U!9_;9e;97KSlxaeUOqW_c|D=>Gm)FyZ*4&^?~A9y(-e6BET#CGusXiJKKxT2 zc(iz!LqvaecwJHZ@uK!OYm&I^Q2XT<)-@T(KMdv95gvCzx0<(lyZiR&XItvA^$ZsY zH?=fXzWLBSy`MfHyngFHZ&>i@139VO`}4u|{M`FvW%q8b7{2*Q(&@TS2ybj#8a(JL z_IzfrTv)psV88Fq1!UEQ=l|F9@50bUv%4pLy1>HexwT&tdaJXn?Q^N>Y^wSXYkDG{ zsm@Kq_Dwm%SErtbk3*d|e|)(-ONR-bc>MhhGwAM<`qhohoDHGN*QZ|Zpm^z(Tz)xk z;DA}Ixq72G(L%ayXlLZNAkDz^iP0T*<d$W{I-^$;#n{@+lE1*S`{B|e-)voUJ34aG zgxlUmHINI>^@ke*XE1DDHAEks|APIk+&bF4T3I0aCcxvw_mGJ*T0R{=-7Zsny1n8- zW!dty*5ULPNS5GR+b=9z_Mp<{UB37&S}u%z%0u7pnL-a{7p*&3qoD1BvfTOY#go#+ zydCJ<lZ@Ac^Ncu=A_KaibcWF|WaIF<3&wABSMRY)Mc}18ga^+_0{+)wrY6hR7lQrb zv^t7;+&+w-fl0$1$pe!J69EUH4Zu;Y9hnEY^-@ez-Vm!m<lZvk0Kb18Az29AeNa`U z98vt$<bg?|=oX|C-<}D_6E}lh?~$g?`Q)ir42VFh*NaJb@fwYhgPL6DtTY$+rtRDg znVMkowi0^|%DHGzDN7t{THldAM9;;z6OtWZ@5Mw<Cg-cgMf2hc!CBxf*?beHEdGgv z&b}`2$*xL3D@M6gWXd&w+wWnLKi4N-r%E{|qo_KgYQUZJ2u9Urpz)A^)wU|@B8bh) zs-EK%t#(|7xe|V$u<L=5Lc(X7BrJ};rHd0gBlE(2c$PLn$Sp-`MiPF6jJ<zx;J3QC ztCnX_4Cc2u`p-+U@&L;WAak(*#M4Q`SX;z;)ii59Xx-w@Jh0*NB}DS}o4%0kDf=<5 zu{bZTC1$jGEfQ(0%;gdU{72s~avz`b(?2DswsFOOkBt8NFV`e?g~}_pDsx`<Z4TP; zwtYG;GY9^ssz7MIBSd)u`m*4S?oW`8Hyxhu-;(l|gQvDW6G+B{?&A2hrr{f{zr?p& z^^}Z{X5oBcdhLG3$#>Rb2H=t)<*N?Wevmd0h-C*+=J$4umm15j+4LHeUcGL+ABXIh zZ@O~o5Eg!eCfSz`uP8vSZ+x0Zo+(+Icn7cULz>^r*MH>0C~;aCzFt+=zlRi_M%)R? zHA<5|UE030agT!V=;iKK{=0`A{@SVyK-r#0$r@wl>KGS#%Rkrt$|}{y@Vumk(#5}l zesOkZnmfeix?!u-d#gPyb)q~(-L2Ws8ZDowGjE>By}OC<N-K!*DY>_y`9@J*(C@*y zEtgaP{RZ~VaCw6P_c`}e@@y7n&t%nYVI))Aj<TaEaC2B)E$0ZyF^6WEIgmQb@@|)r z;)e(9$@NY(_hWFdcK}`GX%>ldEIn*-x8K0n_jxRx(eLuUm3ZaAw*X(b?$h_X^+1Cj zC^}z#em1Tjt3K5|wB9H?3Atq#ie4)C=K3ZIT3-ClvK>#{bu75LYf1#&h`RII+q%0` z!uNxbJcr`(SBHE5#o(KeoHBIFCnvcSz)=5v@cg3u`BKPz0cpG6PZkfS(C~jpG~H-> zx+F|@=}!+$c5@}b6~J4)MNjZVA-zgXe|jWz^Pj{TxM-M2&V8x<wZFXon-!~qPaglv z)jO&lI`hWO4WVmT>w~WzZCJne>ydEN+1DTc`R+jev&zK%_I=y-&JcT$T)6(x#ia=v z#L?Ti0(hRkkmwQS9ZC~^2lqW&z2FGM+^6)d!esRI$2~m1H~)yq^(q=KbHY6XYj&T4 z?quMb-^DK1<;BPEZ$NnGN+LG;#`9`JYq;xM;Iytio~nL-1D6ThMtWUlceQVw+5kv% zNdQIc2(VqF|D}nA3&4DyxZi3|%N34?h#N2G|C0??y{2L{CfuStQaSYWr42~)Pf-G+ z;qL|p&d})5>ZREajhE7Px+l;Ed;{?&vkzZ=!x8jR6WsaJXYa!Qyx{{iw*ZEYz3&ue zyCJhK5ODRDqIFyeV1LiXW&`OiE*Dgz#yf%NrGj9=^+)N6u+(>s$<eLkg=+(zCMXAn zT~nH&t3Nnyv3mbGydGHBwLz7q@4xF^QHZubflBMr?%vgdT~0_aaMujrFXY<b9a)?= z15Qnd=i&scl=|((*QsIgX*Wp4!-7YyVchIEJvPV$TyQuDh3M<qAr8Nixp9zJAvBKt zWn70-`$mFYVvvcGJ3vLLCebUj@FEqZzl%Qw{-e5(k=sxzr$DANm}ZwpAmz+83KF!P zyGK=RbBTO<o?%0CAO{qBrm9>5gk7>2=DSNG9a`3auAzje5P!ZN$@IdSUEsHL0g%tL z!%_LYHIhPTzSViU_9;Xb2moL99hgMGv>$Q>j9i$n%YbN>u1u5);J6AFc;Jh8;7&6Y z%`!ySCBxED?v$-xX47aM_Oh;we-P#QoSBex@&wlrdWq@&IP;S4y#ya(43{>-Y--#< z_9i|(H;Dn@gP8FyNVoPFD|RipTbE{@Me+X;_9kFe)qC5&LuzT512~`!pb%Tb9KcyK z6@)D)dozeTvOq=Hg-0~4sGcL{#1>2x6mSS(Gi*@PgbsA_yr$qx1#BA3dJTt?Ja)1? zozCez@BhBPzqK~dbFSxqbt!AFX|J_Rf1h>V_xJnjL4ZM5b+)gW00K}E|1Ph;iuY!Z z|2`P^->=qOHaPRjQm=&Jh1muISZNrypx*uDO20C*DfLQ<`)zZ=woP?NxFzJ>@c~7| zX#>6T@G*#MnLHWczrgj0E`WD<_D_WmK>X6){=2nOrvX6(VKZ+R7=ei~cifSO(HBmD z;tQjp@3rH2!qfpU0k+N{=Ee}_^y8`S$7z#&rZcZ!?>;cTDgmLrnnRP^RYXq$c@Nl7 zo;nz&fY<<4k;jn1AFzveq_uC4+xvjgjnO@su52g*^62nJy<I$eE}?A=y1wb{W@xvw z;i^8yvou{d?e&6m3I`*h3()PBfnAV706|V|Z`3SyQToM<FTpG%nrbh7W-vNasz)Q4 z98Lb`%fC|Ewdtef-JZ~)IrM675WqqQhaS6je4!7VjPM)g$5eA#auL2g&3H!TUGevm zT%20)N?;e&6J|eBb?cFtYXA)}^4<j);5i<e0HbcwAEr*axx}dW`%$b@`8lmDP4R#| z!^xL^*YKWAb)M~C+Q<C{jQbbxJ}<I8Ue%$_M+ZI|ZruFtPJw_OEz1K(0Rr%HU#gA! zLq{9{5tPn}-r+olH+>R;y*$EM*>n_#9L?E`B;4wT2iyX3+Ausrt(TYnU32DydzE>n ztPXeIh!Ne3TeLAByNE)+eYqDC_JL=|Yg<Nb@^TAk&T@_Zr8PGx%0og}V|XAOJ!H;K zG_wvp91AL(KSd~@neYFjY&#;OB2OL~`a!=N82!;CW<tgNtIE>DyB#Pxz9OpMRm0WD zS!L-FAC-HZ6qTM#u(dGqq~zpR%uS##PX*wkygDZBWN|AN#b+NjbwvMJm}3j$Jqdts z{usF@{$a>^Wau&U&sQ(}9M0cMQ7dy$C|3+&pdAZPg}%zepK?B^p#($v1-0bBxUa_V zBi5oJeA_1h6!ASCV>;GBz1P<HD#;-jFo137UJe%@`_v$kXZ2?Eosqn)XxhetGz%7* zAkuSF4(0nGSOYSnH2cQTd$-KS?=|EC9-GhLocU%!xK}`|eG^7_=<zKhpT#^{vdnsN z8SN{MHVqHQ2+a{4#{9-+i1`)uv8l2oez$%AqvI<(ut30VRI7_C9*xnNobbCBc4!C~ zC*jQVI1X>3ysPmTN<Jn1Y4{!g+G)ByF13;)i9kW`aJ)owoaGuw2kOnYeP_I`tBf3u z;`_Pl4L@H;3X!yl8m_Y_b$~_iQ2oWG$JJ1d#!m3%F$`mzY5yX=n}dE-g<MV!hkOi_ z6cpO1&o4zm8orE!CGYRU_&OaJ*bVe-JcoEh(&fb*t=_cqHaG`TL5?#kM*-1x8XFv= zP_<vEv<4ZQ*?taR8Vq8XB_k~5cb?`p2UcFkZ3qu284&ZDMP_Pj7JGr#Fs~Q)EN|z` zwgWtS(kj7})zZv{wdxr6Q2w0=2cUz6KCK7FY2gpv2xVsJwvH)CWoi?V$Wg||KI;Mr z1>H_D+z`>-fqHLR9#TjzfP^hLx1QLq%E6z8yl5|_>7XKts+dj76R2(hY|;wNfW?4P z1W)|{`^%6{?IgzpKZC-%`g$44IWhKT%zrI5I*asGqK-XhluFMMKq6c>KDFnGBI-tv z+q3l?DkHuYzQ?z#S_bJ_!@>wx$2y!8x`>6f^Le*le-q=SZS=pNs{QTzRH*B1#%|YA zgQmGBtgpEYCh#?Ezb3EMMc<^>6zvb1w*6XC{WSNyqH8r*Oi&N}`efA)DKjnjCN&4D zf?v&@iR|dKv?d1~?)q#_77Cz{0s#n<p3onl1Ay!1i@&V@og$!u1D%9~KHG>sQVY<4 zfIw4oa+2r_iQ*!Jmk4MCCyipLK=5I{Aj6nJ12Hj@neB4wr*81`Q1(AX0^9+_0?l23 z^s)B=TUcayQEO5PgvBAH^XDX$)b~V?5E;S!=Z{`7p-TV0s-Y!4_u33L%)-*M7%IR< zv}UX2R3*|&PF#3bdm5(ycDc67R9{;28WO@fZ8o#wo|yeiOXkUGTsvBP8rbEgkQH== zs%lM}+oV&4oCN!xhZd3ky9zpBg+dV&+o`c01H9gG2DyAy3nvwFi0h%T8@L0#Ul-sg zA%vmO`4s@TD&8siuN-;7I!hDrQwBO<<adu`b`LBtLq*`LmbLP|A5uN_fPJAH|KG1> zYu591N4cS;g42|Y&v2>!D29XTUm<n?3gC)j;onzWP%-<A<p|+bGEN^pBvkEHjdUK# zzyWz+S>Sj@29*7E7;urn106Bpfe{5EIZfs_v(c)i*sF90NA;17f&|8E1qL?>=nZcS zNwx=E3qLYNA;FH%xCXsyyp8|`N@e7a?u~;`P*+pozA@l3r2g#(H7|g)ptg+PahWE- z_F|s5Dz{!J0ogp#LHeg}8mrIyM$Pk|4m@zigtcuLUUZ;p!-49(Q?G9ED=RNer-@(D ze|V1>LEg4i9($)2Vl~Ep2>TzE&y7Yjze`y;R0GlR@rvJR@w@i5-|6apiRKrqr`XUg z9EeK*-9Fv?MOA|6`+$KC62hSbY*U#&9U%5n^e-d^gf~RZ!fQILfZT?txezU8m3T}F zFe%gCw#a1@;H@nKFZ_t<Q7_<<yz7HP@D~lRfYXV-VA%>`LJ%R3ykS|yb0J;dntQ>7 z`8$aOTan%yQXH_&q#?m=%j{ht81~s%Mj=6Rz-{xK<6H+LUw|PQV>4dceTfh#XNPux zu5R+;p9)uCS7<?{%J0eW%8h)t_K07j`|PeDpC<T6Guwxq`DTtba|8gbO73ZSo7M(u zW&&^y^<Is*pB~%SUg+_{F0bM^5hVnK?tD0q3IIHfu^6><zl-g&T?}CX;{v2{+V-qH z)0qRoJC6Gb0J1<D951O=;BJ^^>tH2>aTZY)vdb<wYx|YptZ>@-Ez`vI@2EzI_RnwU z{@eIXd@+VHj~UM}NYT0gf{-i3<!}}AspLH_Lz?X1iF7|M?LzVIIRQxqK8~NX1J)r= z0OmM#8sjg605IgcQeN@nvr>2?PB{X77F>W-ogu~8^$Xku-pYA#dUg*%J{6j)Vh=q& zW^e$ZL+1d0P>r(U`Kqr?fsH$Y%Rq#v1!RCc@GdHp0u_Pfjav1AgauHs$FW~k6l_C5 zpGnVJfO=?+C+3|su?&HJKORrlFI>U|x&b2WhFMhj08qova&}FHV2J`Y;_`7z%4dMm zFVl-Nc|Z$g5CnfYAG+5fKL`jwB|i5?BX+dAVM731wlD&F>;!dZI6*`P9LUT+Uf_G6 zZl3go`~v=90c|w&d#GF@zXLf4JS$ODpnTx*s7vW}&YAO@IpO~_fBE)Di-y_A27Wbh zA|M#9ygV#u>Mr*#mkpm6Lq!lVA?{`FWCu6k9X#0Y;WMpx2{+l|Q)}!12vHf@#(^8; zV?z2B9tCrM@GzV4zYODo&hoHO6!@9u+l)(V%r_Ykq_QK`1GR7waIHnB;X_DSfsgwJ z=mzj2Zc8$QnFRa=Y|kJ966A69N=;6#GCzD4w8(}F+c6zX(3VuRtX-L8*K&x?NPJXH z`&8<XAwpIc_)N`=80}UM-xFR$Cc_7G7bJ;*;^3Y66VW<Xn&8*_fRGCJN_(ICKIbC} znwD{}s<tRI(&ymQs2vCr+d)hO<_wyTixt6IeCbCo^SHE&4!RK0Ar=Vdf?|Nw-HB5X zTJ)ky0HR7zGX`i-r0O05(g&0c7zwb@(LV`C|IH{A>$&*CZJ<~HLIMo#3keKp=ZC~r zLcvCyM5uyQ^Pq~vR*f30o42OYT9}2MHe=}j5D~!9kxtoz@&Gnr9?^`+Py^C|3v+@O zjBG<R@LAaZiVhAOMr5!uCVZ&TXOk6*K#bJg;RB91au`Yc%j0t9_im976cKXfkJ63@ z5%5D);9~FsVtppy!H$+_;K79ud^iYJfQk^fbY#5W?j6o@>${%$Xa>LL{GbTuIr$Jj za!u$U5QMeDb3gjR<3mJq*4)h{505^O^sV)jl+o=>>IcC9Nxtn#TI0Hh=SDP#vK}wG zKfwVx0FSx!4g7@{lyu-RTN4vJHyt#TBK-eNxv~}l>m!gdU=zE*p&^JD@aSMmzb04* zsZmQg`AhN<!@E27-}*k>{hr5#FAnv);c$<PQJm1#>{nV|mcID-yZu2AMLT+@**1Sv zGuO1xM4g}k_y9}6-DbENHF521ZxBUxkSGao^j)HYo)&<<;96|g7bfW-;drqFNF?d{ z!!wgI>H0G<Fj3PN7zHTqujv!d1cE*|*w_2INCBEXgM(roR4DV{BrS&Zn4Jt@03ShY z2S0)Y)C3@jN)mM2<6d<{hJR-Jm7D<iAnHnW|8aB=P-b7A0a>ASy&<l;U%j7uLS~cy zT(r5N*}g4=K>&h+O<#)EmM{bwyy_?x6okX&m((8K(cM*iKY(m-o5gxC13c$s@I{_5 z!AkrI;Ywdn!2%g!+o|Fv%>&HJA_ekL6%<R<Lo`=nLV$<~>Kz?<|4-N`4=>3o_zz=% zMQKV#7s25+c|(g1(uEMgf$L&9U}`(#@b(ZwdwhVI|DkqYXa^hyu`kDTmtmnp241iA zZ&Z!~Mz2gd4x|K84%i`wCWU;Bypk(~vEUSH=mk+Ilbp?HadA1~jSvW!$<s!A{`<RA z;6<)qNgo6doJYOJ%A>>K7=C0#pTulFEq-M4G0tOba)AK`0zLuknU6~o4<Po5sl=ir zmg`?OtjCj60)i24g+u@hASk@=E7TBaAGewZ1&3^aZhS*a8-v!1xdD*^*D6JQ+K{TE z{t!wq?2DhED&bf=fXIAOpC10Ae^B<8eS+3cz_2P21DqGbZ3^q@HHE%PF9+n%eH#x* z8511eWi;ktNUx~ox~HH^Fo}R;Q8=$E@Z@?ic*9*#BuLKCr2r8`&@o?vfdT{CENpn+ zml<rdP(SdX3nT+6WGvdjbSJt6G6c~BGK?lS;QU~%p8j|=`rPGss*-LrK+Th$1rQQo z00>%W@PY3O4f5&o`ko+vkN@8PXv1kr1_}GmOk#g37z<}Gbe0#6nSgb{&=-;o|FG8& z79jyCy||Y#jNYcAP!;JIH>(a31fU|WC-9+-pkXt<;e(xv(0L~kP?0IJLtLUCg8nZH zWB^jOL9__90VBv4&@{#cof&USb?+Z^>RM8XcV^_nb*Pz#q<}cABo!y1b_&&mY!X$E zd#Mtmf}RD5YCE58`jxfrm+==U)d^Rq>8Oe?cCQhbOBG_6Q&S7*;2wBFL2>KIpg2hD zAvi&gHcF8~eS8&qZqI^ofrbLhK8MhNJB$&AI)C&s^ccT^bCT*oRCngjp%}9<0-6M# zAuJnMAMj{aTe=`WX*0?+v5+ISsj|PtW!)p=19Uq>j}^G4m`N{7l;-uyKG5c!NvHOZ zv=?dvj0Bb(Feab`0Zm4*YVgpHiiDC8;7dS}(1`)%{fZdK27(FemFE!ViD)5yVFzGB zpjw=~>&=C35k1Q`Q#!~Cq|m^o^)<U3Sfwcn`?xxAhUH-KqydNlRL?@@5Cwh+4`f>^ z-!zYoNf|nMw|jF-g;EzTm=GB7;D^KLI`6mJqaw%(X3#JJ%y5VRVb5GXfM!EXj3c_z zH`50naxKsoqAQUlnEP&NX-q|Vi)adjhA0XQfQB^}d~&S$ZqaihN5qVuH$6MqEo^he zLB}Vb4wx6v=|f|(+XC5wraTP+ApilN)eS>4By_O72z3FauqINYf)19#Z`kpf8(~3P zg_Hr&Vsnw<{^Y7_;ej7U*s&_LwBVa^i%KGRDg`3>NN=SxT>hr~q9_k3tDG<{pge#> zKoSTnPQ_6dW|spO2H8!q6N(Ck7unrg9D|Opc(Gr_s37+ikH<Xru88x7MbX=8%MMEX z;*0xj;D%X-w$T%zF+>=yGH-DF#kP$>s2=b}<6Jj*6DoUv#j&s{P~*1>i{tb~e^)rc zgE@pE&1P`1!@=Vn*+JL<b^K5s9@7mAi6COor~5!Nfnh{M5XF8#10TYHraa8W7*7@A zrVZ&r*{^Xfn(@GrP!N%-;Y1kzWiWisYyl7gQbL3KY!v!Iytrt35Oslm4L!;?vl3uq zV?q<F@a@f^p!ngC0h(wunCGCjE}$Se5NHV5KOC44uo+9hiO>SOEhLpm10Y66uu$tn zL!b@;Z6diZ#$W7ML7@QOAtnV&3u^WB-Xz`Vm$&cAz5otv#jq&qzLxUei=qEm49owt z<K%rG>H&y>>W1bqfN6juFe^Hw6gs#9lnGddD16Z|V4%DNO_)%n1XTDj24M@v6Lr3u zn7>1YD-r@WaQxQ=16Jfoy8;gAI3k5(p9?mS=rifB@%uNls};B&AOh5V(G)s;mqY}m zC<15PM!$pA1Q_k4kstm=mKj+w1d<SVff9y5E<t56p^iKu^$LUF@{=6KZG)@=<r{Dy zwfQ$Wt(=ep-G>|m{xIePJ?LI2bwc~xi#&r4dPp}SU?798;tjOj$5@~)T4u1LT2FNz zZV10p#S669Ko6{d9HV>;`GM@jQipo~$5Zs9L~sQmJu%vG8Z#;-`SK0$;Olr7MDJPo zK(T`3k+2D(0Esp@D~Jt%LC~}Z=Q)ZQPBm$u3;N|l0gzHbwm}fng0TveHpHR{B8w-0 zGn$2>2MjPG#^NHR3{a&T(H=mw4BmVCHXx4FL{LFNvH*|GY+8U$K==Zx5D)s<OVnHd ziY3GZA!<kyMyYL}6d@%EnB`W56lF4ZN)qyX3Lo0_V=zj3NB?{BQw4Vb4f}1zG1D>- zUT}{agBR{0^di{K(p`xJL8n^riXCjYvNZK+uI(Xwft~V--VTKq0aXHgp;#f*HU<g< z!wygyIG5~FaX0Fxt%sd~^S?aQ)`>>W@|&235F5mqu>aJxarjrI*uAgz^Uk!)qPK0c zA%+v$AZ4-1k8D;wx>K+N(21>|#iLZ}KoqV)lr^Y=={AGs7tqDCTy?GPwPDA+(N z1b33e4o}!6Q^hnv{m2?X#9IG}nV&?Th2VrBg}rF^dSn~gU~V*lsA2#|>-@@Azc>k` zkdTRP!f0HWkniutz_feZUZf@4!Xz(&_DBA1)L|lPCk{gzqW{zWy-}@zzZt4s{$p(P zhyK1S5<p~O;M_u$WQ<|tfQCcQ4y6fN_aEp1O&uc(79Y0-ZVVktBq4{{2#|!XNCbv& z#iB|rigdst1O^z}RRk`o(uCcaS3=VvD0BxnH1-{N!TGlqBo$f+4R0=tK~15s1fe0_ za=;VQ*VOF`3^^R#;%LJ@lXrKIY^msBWews2$_dqrVjwh-AfgmO99~?LZ}iEvf-Ocz z*;>%yht|X4=;(@Q>-oAfrY9<+Dq0p>>@h$Hp8-vvhKgdW$;sYWWC2T5R0M`)#hxEx z^sz%`hzWK?d<sw~vVa((qpbO!M|V!SF`x<3Le!kdgNQ07*HvvU%WRn&IMwr1$jyE8 zldLZVn%ou+J@V>^-KqWuTXUSL1?ZE%J+Zo9b2$3{c+3q5;DTpsxeZbQn&+=_26=53 z7egolQN_RyO@lTUpekWboCiD#$t}DcQALR%<b@3fLy`q2u9jPP%I5G@QL2^!dk+=y z0`O7ne}9tc=`ug)4y{}KfDi6b+hUI&**6bTL%7N8cj(J$$#ts%41qx*MaN&fy)lS_ zL(zdA1c>b-KFk12e0IN0G>IJ|M07#m5voJP7cF26rW3`xm<4%4{D@o1rJ(0g)G^bj z=NzPh!5zHefOXLiRSy{WO>0~%v6A8gSpbO#t%d>J{yxQ?5FZE_A}@d@kaH+U!2)Sw z5xoUi5({8JNC2T|4<(0zI1d<Nkv~`h=kr5xLXi)%iLf|Ow18YfaR6iphzrmJwhbzh z@<5FkKnd^{Mq0LFc&A_hI?!YXU2G6xf$VUnbQhZbD9BKg)C>&65tSYo$p>;cwFgi< zkd%V-212$GVFuml=UaKW?*=I@gqH#JKuQ8sP*Kza#R>E|_zsS@X1qkxWx(jtz9t`o zG%OIN3>7)lLXD1=5ueI})@EQ`pAHEIz<}%ZT=x|)Uah0Xz)A~76n&*k5Q4P&P7eQ| z94G=9wsk*bg3Gt)L<sN&Iv5)rosK3muiuG_1#7gIH>fe+_3aq400De)hM+(0^L26! zd^xYhpbRO1od=Yp!Lg46yhJXz;iNoVmI+`qGz+It62YlpEhr5IO1^eUxD+NTCO{~V zBFSz%Mu`X*3+W(43{t@a(OP)7>`=%VYk&qKI)GKseiy?mo*3T$W1ko*NP=-)4fK(C zZmc%s`@1j;Km?{fb&xRJzs$1RF4;rA$R~K<ju;X|)DC5bf()8n(xoaArH`CxHnJ<u z40A=^dYK9o7eLehF;@WF9wWsGm52khTp|Z%K1IF4k)(lCB3losPJ>W2#J&+Vr=tQP zv&l<8AwdSFA<z{NQjC;YqM4$WYwRlag}g_jHW6VH&ZVQiTc}36Jg`TOv?J~Ym0wOl zUV{|z;e0$09*GHenUBPCeRPxw=EUfK2R@bGt{!Xv1gOx$T9?T%D=uXS#>t3jSxRKM zg9Qxsrd5nbYB~ixh^2@+ET|t+IA$V-+HuqnM9u&ja0EqA;)*%pZ5y<Sq0k)spk!ns z5+O>4i!`8BNIF7bhN?s!sKR6$GcB{&UFj8yDrkR%MgEAkg#S^>u$Q%BRKK#^y%i40 zsa8`#98!&Uz+M_^bgyYMbS+}j1^$mEWtCe}lh>eok;+zb)g(42B8-Sx!r#%<ssxk* z=J1F90cE5rF?*4eWJ;R`#4C2%EOQ2AV&a1s&*X6niqcnS+3TMIV<^(VefVx}@?7Uv zKi<O2KNd9Dr*5SIj}Yj=N96gkeEz&>+s;o=R2hn%$!M*ByrT#gaZETc4Oz4Erp6mu zfg?kgT9$!XhdNcBc-8vioD9`^NV@w2M$qjSdPLumCvmDdk?7vPWq`6ckc`Bl^KU3( zU}xZru~v8>_~q7*zC|F+iop4EbwPryfiot9E4o-;u{J<?Se5)uMHlBi>*mZW^Lv9i z;sRk@WbDd_2MSbNXz{M5qk$;H;pkil4h_YR4>$z{f*}Wd7>o~K2yW3B!Ul#Yi8*v7 z3^D{a5iib|U}PArQPzqqb7hP<!$lOv!?7292V|spLY3IsB0>cC!n)tHVno!rmW@Sg zKJux8!%>k1SprH#>odWQ#)_iA1zEA7!;fdAxGfwO9nuh+Rap>ngM_hmiide(W&eV2 z3#RyH(3|i&GBw)^3n+J}v3l<~E#Ah4B7<815|pJiqr5+9hH?=e_$^RFvJXq%Fzc&Y z{N=#rC2!1Tcrx7UovDr_MHoM|A?3hTM|x*gLBl{g@>}Qf$9`C73bW(}tq$GWJZHDv zBsj6R6HeSI>wiJS32)o^<L~YZ0&tX;JGuZmy!uB)t&g1LaF0pZziMlR4iv%}P$$xC zG(5T(u1fLaM|sdMP`#ihClQzY+o)$)Cn=IddApr)@c1ho><q0GvV=MXDS=^#V9lk7 zdhdlHY+?YWpgOT$)DIPe1beU;0)7UOp@xoyP)^s#HPNVo#EFo1lmw*66V+U|$2~E- zs3S-uTRY-ILAW`{Z#&fn>ILSltrRBgz7B6mIm({;$_D8_1VMs^gfuJwEuaCBh!o*C zL_kBl32Y5(UK0YRBLu^pxEh^|3&4SHTrdg9_$2HNJ$6Xhg5`=zYlz+g6p*?}yPQ?2 z4jp0!JcI0xbxOzx_vMQ+zgb3c9Wc}-kRs?B0B2;lmG8wUs_m>6pf89TAP_*gK)*JO zN0``7*Fyk29BqYsIKe$i9&lr7aBs%&$H1akAsp?sz$Jd-?O8EayGL?X<O?;j0zR0e z;Etjz0DQy;kqLV7l~DSjsVIMhsfH%N2D=<;K8CVK;7lu-0$8N{2C4)@1WweX0HFma zq;P2^Xj25g0t!KQo*I|XHQt#6jUHpLBor~==g=lWdVs~0xTd9`1I&hpi_{zjuns^% z^*f@;p&<cL17U;Tp#w4wp#`E{NKFLqxsQkm^gJ|?0R4<qHKI_Ik_U3m@DB!W{~W|A zFQ_^OW*qT{qzV^s?H~^XA#ewp5J6MnCiZWaAf$eSn>SF@U=%`?Kga^yk8XGm7F;-q zCm{8sfHhZ92Za($7s!H-Fgh4w%>ag!W};mhiz+cR_CR6-)KDCtX(}`?B$&zmO04&g z#{-IjPQjdq)`tPQ3%fGW&N2FRzp)RBfzKaHAOFecOr!7t>JWen@u|@GF&OHK1AqZp zL+TLYn3?F4p}_#&%B9+3rC1lRKYTExLba%3NydU}HJ6aDRA<=*Mj({n_#r6TkbDJj zMBD?&8KOtr8K-E3?h5u7w%{4t6${Zepj?1*?DaEYwBQ7JW!Rb6<7@Z_EQm4VX{V56 zD3J^SFR6=|w&_d)w;<n1(?+|z1>Tv0N>EU?e}n&ffD%<zmnX2xBk*uEOcdZS3ONc4 zRaILkc5vIYfGSkmNV^D%9;6M}Eltfy4c<ql1&E+_g=oDeAok_qZm>_9kn1eP+y~f+ zY8HZ;)H(12T_FU#!Xj&@7pJO6K5*-0ZW$jJjQhH63Ob((JqPL!S7b(JVMd2N{i|wA zkmsCigWB+xI|UDoB}x+FLctMAv4{%=M-WR&isC}?qsWaq#&B7Sog%R>xkHByCkiU? z%i^UNMI#J2A39;s?&yjGQoSHeOb?ueP4k0SBI&Tox*nesTM?u<EVc;tnUMNKPuLkX z*0gG*F0oUZk}OvGE`UnW>4PR&?9Iq2S{#F8-lYXnlXn68L8Yjqnvs#IsT9@5ti?v( z@fpdWkcx_yQPoTR@{B$u)?82QSl*IZgnUFx#WHI-nPPm#$9}sT^-lvb8Yb`QU-6Q) zG%K<=hM%zQC97jt)ORf#voB8GGs1dcVnu4T0LS%x^Ro+%4dus7v_U*Sd5`;bv*(K` z3j;5jAD;k(r0cONYO975A4ZFEQIP!3)C$9cf*&9Jv%HFuM|1eAE%P-sV{epel~G?6 zy&DCa#^llu+71ymV3?3USlIE{_0Qfm?G_m$D#|uGUvvy;8vNk<QCliJ5mHF`p}o@_ zb<rN)wjjhT_O4hvS%i!tJM0e#9AbaaAt7uKAWk0oa_TqzQP{!0N{J9PHrQTqhckl6 zX1^{vcWgZ=^2Og!(K!N%2uV@85QHJjv6_-${^En@VR=X$hN2CE$E1k}R}dFYMqP19 z8KK8Dp1}4%5i1~4Xyq2S*>5SjKWsw~iWZv4>5V!0;BS0nc%XE5(HYx_jMClY1c$eC z-azp(pi-EqL!5GMs@UnzBm{F3<{*$lvT`hpI0%P;3tXFl53H+DzK4o51jZQVu1l_! zMoMm87!1KJ)<bkpAP2y{fTO{_h6D(5$xV#g(nv|A8FYXcb^16R6C^j`n23R)g#20v z6H-56Z&xpPDy;9IXE2BPNI1<AUnP2IBW@F<l(2v4<e`Tc)R_ud(xHLEf8Z51{}*1l z57Gt(IOT<iRKOGlh7l!l;D)iVO=1riG9`;iR|Ay|;)3X0uvF`!)Gp;n&QjZvm$I2F z$QK+=IjyjZ4DjzLMp8|%pliXq7wv^VRb~NS84vMTq!{Y=)cC<ZFga+{U}R?|6puxW z8u}CXqNylKR5pzO1#tueHHtn|5CMq>Nsvg*L?XI_;ih$_f)$`uJMhO|*e+YlS~7sG zjMd|zHG>OL=?mi%-OKT)ln9}^8Y7Cxxf66@#MPDp<s5vc<(XB-hnyT4&6NrveVD1> zD4Kyh0R&_TDzT?qJ5Hc3GBgP0(IzFUXd}G17Mzw4MvW?<;P(q@;E|hPAW?B(gi^XG z`iWL!hVLQC2tg5ybbLy{i1jRLL~(|sAK1DvpTwte2rRIZQ_)HiH62>R2-Wuy$AZ!d zy9eMK_*FtPB9E{aay;e<M)jz=0L?-{kqBfDG<-yQrRe1ACpb7m-*~e2x6_I>N+BB< zoH=o0eCU6~iKoHgTm>%j;(!<uxs;#67;2c8w{?u_Y6ot>B!%=g5I)F^?AnPaI(Z;| z<OY@S1Ug*d7l8^8+Jvql5=n>%1f?JgDlEVR4AqJo)R?W-yseJmzMVKFh;b2MlZ&HB zKneRraZ!+jOQQfGFtkvS3Pl*W8zdB2Kqf@H%AhfR_1$ao5wgfREBQ~2Kc0|Q6iKT8 zlp+)sp3Y}$v}=wvFuh6=2qj3EB3gv{m1N{a3*s6Rj*Lkr!ylTqy@Y5ITPgo{j2Xgi zlTXLv+Gg&|+eZZX&D?*%^%|fZZfM)iRtQK?eV~TK^Lfotn|MRoK9RL!ywNzy*AIO1 zR?i$y8@o^GNP$TjGW<XmecMoDs)0tp)fWE&t%zB89&|IJhGX)s&47&Vk#9x?%*mJx zxY!stnNG{&J@<JQ(vE>h@{I$kM)HRh7Gj3B_v9U|u`y+vE83uP^z~iovmUC)5%36% zk(%8euu<XwDU?2zTMj5+WiP-)IVO=Um6HYzom+L-JUTiW9?J35@sKp2jv!~@QTcfL zrd-RrsYq%XK_1aD4pZgOxo1rN#UKxpr8M|Z$-o2rbgm`b6Q6wWX$+N)aL+P+D(L(v zb<CNTse$IKic^7WE<FB3Yg}+;|7v`!ONsj_1HiG=dVE;)kjsb8v|OCLZ%xL!iIu%q zkJ^_Kvow&Ow_X#qWAh;<FIfxnHacyWN-ASNU<A#b3gX|HSOF~r@<{WN<xvP>fLTgE zxLm^B8o~o_M(YyD@)*~~LydC4=_M&KC=4yP2i)`cwxQrd>kRlM1>lX?_g*${y$9B? z+H!*uzW6S3>kaup!1!vxh@2>!!Cm3WDi7_D#S_;>Ze?i0W@sBVY?@bBphqF%o(;#3 z^y}gNH$RO+x=2}wxGY%YTC{(B{xL3M)+H>0GD@(B29Q{bat(STALxq_Du=<fk?>ZM z^c|Sapuhp6<czA`0FkuJmF*?<r~#4APm#x1+<{;h4U(jyA;pvJ{$c(>S?=?8g<~Py zKPuZg;$r0d$Uc#w6(QCAZ#eAD^CQ<pWgACqiv)A19nO<9l=R^b5U57}QukQqN5`VV zgLJ?OkF5-4Hh6(Lz#2FL<Ctt6OX`@WvxZVbHe#f=9lfhj2WBc{PY6!B@F=B~<~87m z-<Y^mu}Tc_KpkX4DRbbo2m&DMDdGk<MTdf}oO63PHocHLMMVD!|%K6|TUGJQp+t zq_H3oL#c=xTH^?L_t!j^j-rB+C2%3JVqN5O_=jGgz(f{^Dhhh=4LA)u7g56C#6|K` zmoT)u;b{K5vmq6tVjY}M$u*ekvIO-O43|`CTmZ9@m#;fKf)&3b8zPTlA37><76>Xr zFhw9SDiJyxsgY5z1*pKJMK3(MBr#S193paD5p-ZV1QU?D$P%2qNiq-M0RbG&ljuSe z6l~&hMLJ;A&Q+ZP82}}n5F?<eU=MH=AF(#WAUZ4^Z9^^;a)(Ykcz?zJ2Vf+;`tv~A zFZB)R3?bO$CvzS73`H#k^?*}oE5)&!brYI3<Lc=w-y!v*sPe!BiBL08^C+SXZVKTO z30XF<GDA9I&@|Cl1Db{pr+`p_Pu^o!no!_Ysv6Qw6MrCG2o=0=Eem4r@F00bu#p(# z)DS{s6q(t95)G+_n__!NkVT0dsKC@_pyE}^El~ynnIX@C%ct@pLJBTO6^GzF@Um#d zbU*f!2S@lt|FryZ3^786+B^<~-B>v4#6YiU2&#}&R0a_?ItD)TaEeGqDB6r;x+TDA zfHl$y9fBZ1;0<01NlXjs?;}63{**!q7ihc4Fw4RcUJ%ZPOelw4C5V_o2BZ|y&T?TA z#SY%kKR{0)Djy}-lxqeKMsH0RQQ=f5B=9nD6CpvM734vn^6UbF$o;8`6~GUN_lGH# zY~_u15KEXwReVH}krWBehp$Z7<>4#0amgI{qi8RnAJ*5R3FQ!b{aDGE&VjL0ThcIS z6qFKlLWgC;UYYBX&`3iIndaJ%Kjo`P`jvHXe2RAby2X4GGf_1r)NV<{lvI`{7L9GQ zBm!crbIK_hzKoe_z_B$-3yLciV%rD;88HqQ&>zytkRV^fbzJQERC402al{pIy!M|< z9Xh|jZ1D4`i*Q~|&a<C)kEP90=$z&NSAbYR9SD1RQZY$~qyi{$q;_8YX5{IpuGl*+ zB=vE(g>KQO@p*E74fthq1qo%itdCL4VJ`p0a<HzU?x-gqL_1(Nvz~{r0;n>1cQii$ zL}HXwlC2~Vsv`($cvMtS9hnSuq#B$8(W63FM@$t(aAcs4h~pAmkwnMEZ{OW?_%H3B zGExB}+&1Y%yx+cNd^{A~5{h+4UY&~^$FXXdE`FEGvMLXlrmPt7b4ttzYw@t?yvw!U z4%|s%Nt{?Qu6l7+<?htU6?0Dvi!Q%h9^7K}J+ip&nq$CKY9uQHeu|6sUVZxv83cmJ zA>$k{MMJ=6dtF>IrUK}3dLg*v*=3d?ic8+F7knvr;o_mB%?0sjZuQQX<BCvDFL^eR zp$`MJkx}QWy6-ZVmwys<Vf5y(TP6L!8x`$d?=i}DChX_rxvN1XfkDQicVGP3pyfRH z;fJ!WQBf5JK#0dK=p(%WG9mZ{GHG6480o|`6A(haxW9|XV-P}25s*q0f*>N&wy|r_ zlpsG$3^8o#(k|c+KbSFC><WFvC>5<+PtKxoGabz-uDRB#Mb@68&g4Eh42ywS)Krnn z5KtKKNZ6Gq&dV4|B^sC%KSsl)Yw#@S9U^?3FCC;q#x|jl`O!#f+{O4mKQgouKvM50 z;eQZ8=Dr%x<UEz!CwioESg-?$<vOJiVv2FZd8#M~QMx1l(XNtUeqLrUagcK(y_$-8 z7&to$;-QpKmr(H#3L9#I2b)Qs&#CX}Kbb)@fQ?GNoGY89H3^f$(KksA7#Jqo9+GWZ zo<rA7Fj~9P8=^b>q&KG)*+Lu1adL4^G|CaVg<~PBO_2#vS&v#au-<}!OO4KI0j3Hq zBW3P@GnlOO72Z%s>z;`V8ajA9R9Y0ifLf%dghn3vkgfz0sv5jemDbRQcc?44Oi?_v ziVg)UV4)ASG7wyf)GN~6Kz}D)W6_#J=7Sy($!CI5XiYy#Z;PRWlDI;UKvcsDi9I4` zN(Rt$61>mrCI}#h&|*Rq73Xx<k%tNei&o1UCTdAg%tW;TJcdROyc!WM<RVeRvWAT< z0Uk=b04mv@V63zXHK%x)%+Y=z_lY)LIGkxu0SwH!+-5K!A<9zMlj>|F6t=yf?<4w( zs#6gsNO?rHCE7fTlu}eagkjBm&c)31#X4aMI4l#$SG<kbUZ`0`wI`4Uc)@O-L4ul0 zdLmg0I-vm~*BaRsCr#fL8pO&|*gE_Qnj*}gCV?Q3)`;z8=A_Qdh!PY)GPrsd+kjnE zUIRf!x;*V*VG?XBF!r2^Zks0=fptwkDFTxK7=kfi4>r*VTCY!AHAq2<a1XSd*FVOf zUi5#O_P%{_62^Cob*TmhHy_mTK*7r3u24+cq;bVs)RoYjDaW9zF@>ZsFsA=cmPt~w z2J8mfB1%Bf>P`S7pq0iB1+pCZ@il}46%G-+fjdLVMcW|Mpw49&w@`{}ai#r*2#6;` zuxp;AMRXm6XamydXv^rkXaz91knPuW3Q|ylyeg1~{?Oo|wy>x?VVZHl5_;7xLHR!m zu^R~{&jHXO(~wi{hvJgR%Y!#m`-mSjnEngCSv{T$kY`p;B`@H+Q9wHmCBLTu-0o=T z!Pl0X+dNX&7~urPzJ3Z#!h(|@%3GJrM%#l%=dFcoi5WF!su!G_8$c|0GiVs?79!JX zbuFr2^H5JVP#f)TpNUR2Xcy|9V6$|8+66CAidgM)y(SX@9^Bjft(VOG@et|vAO(y+ z)Y`ryaF?Isc6YS;CeJaOY!9S9Lfz!%KF?evO(~8*4RMG;gJcNlrEbfBRS-nFKu6g# zV0b8qBbuN4j-<?@VG7WM7*m7D$d&=awU~&~N}dly7zCUH7*Se@_%VA$MPYyh8cRdn z1(QEr8k3d`>DB~9K{7-_BN5nCp*EEad|=jl@MWR{Vb>hX3G?aJiqL5k4Vp8iDL3$G zK~_|D+cN7Z)0DDqZSn~Q&9^xVl23v(wvsdwCW2FL?CaAA2C3KxF~oXv--0Q1*qm2D z5Sgez<hSscBJ0N)70&Ru;~A&Tz8k|M?|B$~D^vH`t~my7ww_|llxz~JvB@5b&%w=k z$u|pLxNvBjtQ-4T?qW}`Qmo5+;rt;8B%2Q;XDta|I#)~`w^sx6Rb0gL?h6y<dX*li zD$P#&Y)?#Z_MA_m&Kb6jit@PV3$5g5kMX?|dgu3u_f3l`oB}i{*id3x9C{$juXj<2 zP)O{1X}|<zQoR8$%b=ok0h-K~OvrotdLTn$SHV@UE~bUuHi^Zv?6Ka4HeERBrrS5A z{rVx3Do#$3vS*k%{VuZ$GpFpbLDL474EtrcgcB67KtsXi5;V|E0?J@Bqo@_#Q02PE zeFZWig<VWL44{kh>IV0DgFp}XRbdJ+Jz~kje+8DqbE$}wI5sxVkM`SLG#$c6yfrz{ z>Qnv}q!a!}`6Ppq3KomZTkkrX_@9-ug4{@xl&Wm~4Tu6VSy1nX!@dgl4}D)}5GyR0 z5`{2Ge{8wHepTR_vV_`syFx7abZEGFjc6*KbAAekYr_obqxc=K#NYy`B8eD#>oHla zvTs}}3oVL)3PXq}F82k)oU&n1+oFVwL>8p93nLv=m&AOjONF#?$&~}q7oeF?JW=&5 zGUNhKo)9|-1E!{;5MqQ>fHf2zIvX{e<rLRd(BR-Oubl?}{wUc3n4~2@c<<N+eK*7; z!arf`BZ*NF8+ZvgWCw#Ms#pYVv~?SZ|8hw!3Q~8xMC>S*4O>{!NkWPr@lSryEae5s z7c%vMrd$(v5JqX)e3p15FYQ=Bbt{HwO<n?IY~i)w@+r2!Hqrzg6qSgp1L5EcHn$XY zh4X94b!e?WW!5YJ7A{Mq2S@~}QI)?~6Gogv#32^Sn%UqACXUuhlOI4_(ku)A9*_H6 zk`lx)DNz+kgGC*mPf+TGuCDMCv?oFvn4(-sI|!qKEQX?EnA`)M7Y^$xqH$7}B6_+L zl)3>~$Ot*A0~Yn02`J}zScEVE1O!cZLR_=L1kecMu)r3aK*S0>aS@J`hQWR(pqVy2 z2(;Y5!&DbTz$qkJ#llvi&jZGh87+rYp+TpHH!7J@3a&xiMk-$rvMuaocBvwA5%&o% z>5rIMSozhBhEZ&f0JFLI=%azH9Kc8a+qd?&!+NR7CZ<-MOr@f;R+#3k%!*qsBb(AH z7|j5p#1SakbrK39QiuWzMhA{~Eu~5sM9Y&jqCcjVLNRFKh>#10$0CIkKeEpkWdIE^ zeni<!yB>210?ZKT9>}A(>UJ4RMJ@$kpac<>Tmf?6P+p>_Clpv*>_Ma<O^_XkLH~hm z)V|X)c{Fn?lB?B}9Udg{l;7(rN|g~zF(>Rwp~A957iwq`K`|n^AcTrbe#<?<PD*%r zM7@_whDop!eXvRcp5<eb!56(&H4LSJbV;lrV|`p4d!6Dh@1<!0wfG-;j``sN3;s@k zXDGnXJIdLDiNX-Ha&Ae?@l^Qol>F5;)*Bw;--V|a4Mw|y##u>T?i(Sn%&HB}ZU-5; z>9{=urbh(fX3JI&4^GewrO8?KU7%EhcP6g~o5Z`X3Hm+3Ob=WHqA|D5$#@=G%pxc( z5uKJ3TVs{#@+MW6-E&YObCd`(aMFOL>KUkmiEKIX{iK19BdMzKNJHKElbt-CJ~VQo zG>>Q2dxy=H(Lrh1OWw^1Ti&hpgz>GYmbPVSXG~*r`fR;7eug>Nk^TM9x!>mWDgST% z;{#Al`kcErJtfN2_EH+iWkt8&{t$Vl<>^Nb1>gJFZ{P9s|C&@e?!*cxCzHq~``qsT z8kWx616%S6YRd+0x4R7~I6Svy|G?;)g4)LiZkEq=^4U^TG54poxqo&h79?d}Hy2zz zJaA9q*yix*&2Fzo7g0Akki7W=+m8Wr+{RL0$$l2TPdt4e&)OpJ3f-Qx+l_A4__DyU zpS|^L0pcaeXYyV+_s$4F%#O&{oLfg<-23N=rAN;96J%ND@v(2(OV7{fVcbx#q4eq4 z&;$GZ`XXRbTIh(18NZ^$*j@QM6{CGW4%X46{LnMg94BG=_$f@mG8Gj`pKKb}#o>_z zY&rho_Zzz?IH9DXhy*c`TN{-&BKcOAc=8b?6>tc9dcV@Xm~@i14c5cq!CF{7!Lu;? z=JN_qHUUqfdJ#^5CzYM>q>-3m1(R4y1~}(IQ&GG4&rP+?cAj#cYBBnh?{tBUK#4Uz z0Fe@dwnvjSXTE79=q1cQ#NzPInKv*5<g=rCn!C`>%C=-{B^Ci9n;fW!!FIHJV7so@ zi+{qB6)+N4eBLga2%u$m=}i>82F5(RWmib}1i;MEUtu&MbkYtj?*l%5MT1DJI(qvl z5`jcpcZJf8QO&rpJ5wQ4T7W8mB7G-tfR-x}AW;J+-bVBc2n`zD1G=qyNAevQqSq0c zpsL(f(up=Gcc3BhLNc2tC<SIhXK_ZMN{23<9f^k&;fkH8v<X=VU&OOO(BW7APLh#` zil(Xv0)S-{)o4tD8vtQwR+ElI+y&4@rAHS^G|z|sxM7IK<PE%j3~_wRm!X@ZIz<nx zIV&%5AOz4Ju|dcK5(VK;%>u3vN?kdvG|fvu$uLGx1Xh{_0{~0J3ItU2APnzB4_H8# z=}rPbJu+#DT{LCL?M5q1Gm{Vog$>glRAG4w%{vi?C?05X0zD|jP(l#O;(;guzDVCL z5Y<Bf3GG3VwPB*guPe0?blh&2H97#$&=OE18*zbolz+plste>EBr++s)C?T0ovQvr z*J{}7BcTybtDQQYmnex|0i%j&STHInRnbwjIvapk0=R|^!0`(q8cHzJbo)oMt(5G7 zYn3c58=H||&?yum5RD=dknjy1CWtW|b(k){o*_;A(Z1)Y9Q6F8<gp%F2tlEHssvKI zP(m?`n{@|i27lD#Hln<iHMdhGG&*iR!=#fCnHOP0X&~LM;T7Gf88u)O7&_CNh#-x+ z!2{#Ql{+D6pfE>}MI#%5DKHHI#igu}TzsX6h=x+Mj3kZ1WNxVK4NX~T(?YlHB|L;0 zWg@9Cib4%_txCuN&M;Ohf(Q^s1zFDO)jd#Hu*G+VLjtu}0-Oo&P%D{kl47BU&;1DT zg^kZ>w_t(i!-J&m<61KUsDyi~i36{=2u56}>&wg<!BEZFNNef(D|T<Y5@-zLfI#kd zW+qHGC!iOTaE|XNHY7Wnx)1*o!ZjP!iuV8%<cRokS;rZ?vVdOX@6u?GOEc9!22QSc z8nGAij^D&Ih8*)0*e7v)(lO(lTQX~!yWRi32)ChyX%Emc@*C{e1kETrBxu^s*0ES~ z4mUa{{SjW*4%?VH8ABzj6CJmuYhm^Rw~!!TKd-tS0G2uDO5BWftlWJwdX@94WKwqE zXB@X>^hNUI6)}Axkejujnm0N^f-4Jplpr1(<F=4hHdg>B-qlfV=Fy+7^c|m`vc$fq z!q(z_BC&P3-(a{#Y31)=(*oZC>8VRf=2ckljXHrq?1diAwERcPE1ehaWfraBr~QwV z7dy}K(?>n7>z_XM8-6_f;INjhUmw4gc5K*Z(+gLB)N|t>Vn(EWoYi*e52$H6Ywnr( zhnR%4kFwgF3!$Xc<MYCp*0hF<wkr$c)<9Y5nd866%X(>3+w~{o)_T9%@_h2CmMOQQ z4zA2yJt6l<?_<;dnSH#UE#BcauJXb=UA-rS2mHO%^T*1%s<F*()0;g%uzc6@Ae<m; z{5u2tC290B7)vyO;@=tY=fFAPW1F+aezt8%@Yd+>BOinB^WEr=c1`oE%kB}jArF)i zcX!3%;O^91%115p*qGnexc)lqpt&BSdczWOM0!AT$&M*OawRRmu>lf`_hDrTg?U(m zEZ~-EL}sTZpjbGf5(UD0r+I}1A&N4K1;3y5PJo<})B6=m!|_u0I@mavbeugyN>u^{ zLQ13OQtYZbK>{c;XUSMk?(4pc6O?r6abGK>l7<DJ1xAeY4@)dZlqA}(p!^~51pkXE zN-82ybP!W2#ygu@pr8Ot1ZXNu8kXn~1HYz&^s-5LKRc=es>kA2;DDUaK9QlsoQfNU zxoWjnV5r~<wg*&C^SJO7z+;kmP({cQ({;!x{O_m}f(nQPlX+5FaV?Qy5KWnB`js{j zhU(Xg&ld*{<!s=qxBCJHl*qD6^p8jVBw?cVvis%>ro2izVYv%M7K|fGRTxOTpr1qF z&?FhkE+8L)8Z9lt_8)jjmYBvsS)inXztFB>-lb>YD>R<KnT2V9935~+Vkj_MG-n4x zI?ksq$G2UI(8-F}BcndC0bdEyu%FX>q4qVR!vIJ4-8#bDmSn6#3SkYMF*<7=eD~5s z5be4-wu4QmimW3TQ5_k>%&MMy5emY9$3B|WAT$V3&CMV!Xo(t~d)lc+`vP}rSTgAA zMo11IP5yO6N=AnhHN0zDhXa4UoD~%%4XFNAS9OXogy}MAs5D^a4p=RIN7*nG<1U_) ztI4<E4{;@lJ<fnDy+o$~Rp2fs(D6a8MJjRRg9|vwgAWHyL=+K+mZCUHgbXMg>iKm1 z0Y+1OK-(t?L&H!_*TA^%a)eNS3{|8nQYVa<3`LlP6Tw0eLH#Y}4-ZaWkM^U<$d$+h zWca_-6)}Na1c!%zC`uq9V2CiqAKbqi1ty3!_!CotjOsw52|=gCO+!tym`{pJjL?EG z6N)xxIp!@xm`2ngv6?6o!Kl*{FwDEiEa?yJKgK}mJ3nv!_U>BMBjg$@eVLnO2d*A< zl5U_<LQw{zrOJhLRUumi6ts$%Fa@3{uL0^t5wou+=_>&Tddk7<cZ!p+-3X>5!)8<s zmuYHEN95@ws|ZH5$7EEHRZF@^B~XI8E{$VwPVmw{T)j<j#Y~*Q?fBg>jI?MaJ`_<D zW@x+WfmvSRI90zaHqej1(`|N;R#*olaTUl*dByH`AwlTE4FfUy#o#i@FJtD}?iXyi zGfz29TH1x@5$gGU{zZhBJJYhWLv5JKg$@%y0f?nm?ZN|2y|N94R4T5`bJ;6)ia3!q zzivHe_b#dTa*unxZmvnBp42PbZLcyO{L=#k6Xw6S%iZIW|IpH(f(AW0R*}mf1FR(~ zwz)R5%-)XwbxXW{Ex|vXwM7tTFcbU)G-cslrEkhMX97C97gip`Gg|B4t(w;_*_c&i zGXl<zt7C1mM}<X(K&k1uv}t_^|8KaHc-0T6veh=leeuwmfpm>NbbNTCZFtBk|DFn4 z?)CLm*b?owa1m;MR{2+=D@nzP8A}kP#fK={J=2l{@32KlkNULSC5}p`?H-DH3gZ?z zqT6<!Fut?c*mHdP+DA&~Rro<!S?V|ZZu+bE^h?G4+Q-u8<~bVMHp~cn>xWoluYjvb zXYNh^!{YDoTio6Bi&GPGz%73ysMP%-?s)py$)2VemW=NwK3+L)#_ErHc^DJz1ec2d zmnY-aq<?7cX@7E2eA<OgZMUC{i+&8?Vm)<l-JnC|OWv7v@57kK^DRBDg#}!nVwtn# z*;j^d&2ntETjM=i6TFkQHjH&<nF{{)<NYlUS~Ia&{mPJCv6<GTk(Z0De@lG=Yq6Nu z@=d}>0L>pFjY&^8yt4L&qbmA~Clbn@Hk}z&mr%3pWAnydg^o`m`$c_M{ju+B?uNIX zj(n`N$a$`MWB&K1(kVTR+d{TQj{0;!_N}JU-lL)|9@c0JBQB9WEZH%eEV(i7uAX+Q zxqpm3x+L1+@xsK9+Fq(NE#!x8pQh~JQ5qO?pvRP$1A`#9Y#Mhk`J3bqlRvZ$n|d&8 zR@GI5S{@NbT=_5=v#z`poVT79(1ux#+N$LB?zP?WJ`PJP&8~WWMnPVKX?N*_=<<T{ z0fR~>L@ftuIK!#5>;}j5i7ww=*v>AEv#7LW0x&EY){&$Va*WZ}*1qiH=aO1(kZESO z48<>_4_u!ROEL8ov6CJszi3`bc)=dfXqueA8eurW#%V)+4Z^tQL8XYeLV$T{Z4Z3O zCI>B`rh#Gp=!ovdgOWEk4RT@3UI&onqDh%RtKaga9W*JDvP(!fQnwgu9tj^>IuJbZ zs2_|S_&Ezs-@rhJ?2672qQBhSHS=e9JinJzbg&_!^gRusho;eo#2D2XO`{(ru3+5j zX!2<K4N-?@=I|P(GOYZ|O=UxzCYjkpTC1uMt-f!2bcGp9at#C`4UaVOgS)6K3%4MD z+9_6xWC@L--w7rZ89Is<z#CXDniIro9Hl~hA@w#)&%)UG4=N0AM}|$oA5474U@k8U zBXJ5*M}4<6Se?M<GKNh<Q5}T)5az<wx*&%rq!~rx)+mo>qS{?97(NBw1erADJSw+g zjzDH&P0u=I%P4n-UC=?H;0=-?vLo$62Ua62D^;Gip^=kWATX%{9{q==80BN=CyS6+ z264ty6(*%IV=wIvdkB-ou;r-k2Z6Sf$|KX5K&LRfs*k8tu!EeOs*~t~Y18mW(~ZOi z0;`w6D-P9iKE^JrGPPkd%ZBi%aobw8H1pKj2ZVspDUBWyI+*zjIpRBHGM4u0WOeaC zN(5ZkHeKsa(i<@zm{L+5g!=~r(P5G}3`t6l%y2<Z(lAZqgQsA2ag4seN@NxtfBQaW zFZpBfFHh~fGm$VLA_{6rIOJnQu3_qwaZ<GVQj{Rs6im=UzepugjA1;klWhbaY0O~G zmV%L6#bhyaD$}_99lgV-kYM0brVhD=qq|fOQ_Q)9I%rKp`OQQ!VBkU!MEOM6PUQq* ziwHw{*^pcr6S@>vp!?)0z+!wu6dP(Ggp>|tLjoy^G9*WXOVKNm|92P?<3~XY&aY`V zly^D`Dzt=fHzKGA<*DckzDYC_jc_Q{jPNGmV4ry+{QyhUd4edufJ($;qR7GPbHNXo zL1{0SaF_@)M4k7PRx`-&%Z^%&m*wS$&%M`_Q1WF+%>J{Nf@5}hjKLr4wVU2p0V(J5 z%a4xhZ<#&HY?#;#0=hM7cGceGD<xjQ?2_b(pUjMhPLpT9xd9^19{INsnoSe(z!PXa zq3AlFGEP1x!DaHsl8?WL69Nh$`kajj3h<0;8g*+kgquWLxAU3a%062icmFwieMpcO z6`Y~&8zDCJUvP6}_paXiJU1BZk>gkSJhX68#cxfU9fX+CpcHZo6q>8gEOL0X6`TkG z#0;H0*rP2dt(4NsN?;45mqiuEd)_COU0phA`Hi$(N-q`nath=91|!arR`^!rh)>6- zZ*&w8W>(m9r-l+?ZWZ)D|3l1(oyUvQ_K!UB>Z}|4Cm5&9fbg<7`+UsOowa4%x4+ad z*<NXyvHYx$#b&&|ukWawhFE*$suRnDe4g2Cyyob>;qU~@;L4*Xmd){bc7w6i(fy;! zu+P)metxLw*wz2aJ=h&pLA~}^@{e_oIvjQQ|9*YMapAMQ7SBhX4fz7V5|wGlS~AGD zOa8z}w~&@$i#~2GvTg;$WIM8+n`R4c9AV9J{MA(b`W-_--O@<U11-Zmf4vfxl@QQ; z&Hcmkj#kUx+AiGwzIfQXvGuW8*2(w{v&Q}XZ$F<sGwPK8_`u5hs~db@3o!Hza%3m> zw=T1sGS5g0*c9Y2B?UQhUw9zop26G$AOn~gbS&qs;9M^<4n>*s=YA*)@knl~x?xE> zyzKhRk#_IHGh+5tF6^_o_Tg1_pv|CtgANQr!Ls|AO=Vpd^kMOGX@D#X!Zdn5-{ZdY zuodNBd}pftAbIC;=Zp7-%?SS30?}o_ap&^3@jsusXZ5YPFVlJI-q5u8w8puOvvN+1 zJrN8I<}j9boCv56hQ8w9G9(o)Bj(a=HfUz3l3+snm<N?_GY_hSGDCqy?OrlqHfoV) zeEoBi(@D#SNF$+_3@?pz;z|_hd=+9T$S{J7CIPAXM6b>Qw1hhwKr(l805ww7?6}Ld z<e#scw-*__WCvlH^Y*X88oaFQM(6w&KnCyU0GGSY#QgVnt)2Ez&Z{$j&M#dF7<niM zuLxoy0d+#(&kG-lsOo<qVWEb1z=Blg;Dth45IYFA67~^K<_XOgf^g$2wi2|MpHy!* zeJ6~fvNuny+$g2j;IF49Ik*^#5fHe?f>)g-7?u9Ti7}We%+S3k4VQS3A|DKh#EP*0 zRaQ|s7yL`2R1`H-LuimjD|kt7C#(+kk0u6n$l|cNxZ?#;`;c>eAp^5q2OT5rMmrIW z{%tB93!q7H*Nh&p2{jVw)5`PFyUD@hQk_uXyP#zW1sA4Aab}oKenL#zk1#b&o)U?0 zs74}6lE6f;hD}>cAfGP6P|_%!E)v?WD31kC5s<Z;Ruo|XLJYZs$rg5#6@>Z(PE_O? zaFMzY&DCS$b%7;nJ@SVHvQPwa3jYG*d&!mv&H(O=ZX)o2I%xL{8nhF}nlfhqcf=hu z!c|#Y6!IiUwpL^rZFf|vCU1HZG)K5`SyY_FMT)J7B2aDwQXu;5v~m7f7C;+SvlP)} zR9=RVqIp5gA}d`85#Ncs0V69h3tOMi(D?}9s-5tC5OOs5k+vyPPP9$}Fce|Buwgv< zySb7uNW>u9j9g8@^SD!U_mgOCzUZG**8J+-YQ}tQ+RQOT5EZsnjuKF&6X_5=z&&l+ zRCE~SYud|?=pO07A~qG2kWMO(4p71;3UM?vg583Mu&aUy+|WzQ>Z0cghIp67MAN06 zZ4~1O9jU@+Rh^_qU$g+Q#!W7-2`UG<NEts$n)wfkjQ+)NzBH&39p*Qc=B3vJ(ds|i zQL>A&k!WhE2(PZ)zzxC^Rl9r%ykgcSyET*H;K6+prbAPC#K~G~9Ht^QB$@E4jjXYf zRk(JX+c6GU_<CJzu?H-_Y1^;I+Uw^NsYJ&4tNlv^Z%8@))n42fUIoqO75kSEc~Yjm zmA5U$%d#g0fH5;+M%7+x9DS-wbAx;@?{Np*yj~ZSJkj}Oa_{EaxVmXrtWQQ9`KNw= zwU3TW!P#%D>36lUVg7qN4o}Mpc?;_EdpK!P&YQ4@-Pb&AoRf};cku6^Em9YJs>g?+ zt1VzCwq*P)kkFe@eEh@S7$RZh=f*z>zG)a9F(@ovgPrR&{aXuyj3l7MTiFRvc&Pj2 zPfgfTR_UB;UhVhp_?Ipkf4-MiI>eU!+}8(BUWgbo8ZZ+C=jqUu2TQu$Why4RE$EMF z=TDxBy7=9_Q8OYIk6O0#Sk8k!VSm{fb<1bP$lURvu@`zxcN7?WVz)0$YX}|n($3l& z-3x#-*MF((e|~YQ0M55z*Y}Sw19_b0*FKFhN9SS2`{v0N=D^mShfn(~3wr#7Ku*}z z%8<`DFHAde-~Q2_Lr2{n@Y-i?#ua;Gva9dQJ@^Nogr^@rk@U>@C2v?(<XZA;SKcdL z`RkBF(~_sIv8-!)>76lE4?S{X{7=2JDrT*&Ee(7nuVRI#w>7IG#$(u`hJ@CX0lwu0 zCDyFUo8yu$j|?|ehqMe_bg}h|4}t@OoqsRC{FkMJCnOzQI+SVF1k0ZWeD>DFv^>kQ zZ2!d|p52FotItn)<i8);@sCf-vXYM-1_A9h&$!?o6y#_G^1NjEHs`H`tbRbAWRo?@ za>hKv81*zHn=)^wt$JJbcg;oKheIkCP{4V7#QXcbDysfgb<YB~>D*s8c^w1*U9I|C z_1^5yde52Ne5!fFCm|k#r^bhLDcoVmyf<)0Z*;6LHGXV5?hFInBo(H3E<1#UxgUqE zIPC70^T6U;+-ux{s)&FHpB1Hp%eVcjxzDGzo)!0%+}flekWDQsvkCf+XgaU8`0Xw< z0(pvrT`cJaP1G@GSnn%=sN)UB$uYvq3b7P{V;pl8_KbIaMImSB9iGNKsO*9{!?%sW zoA8#nlGSfv&tm*~+h82I*U=~HH3vnOk+L@Q{r$EZI9>R>_p_Y0XPW-y=o8roO;b06 zgoag2Z(0c@Cv=h-e1p&ppav;kj=D3=7z<%AF+g*tuzH>#!oM8En_tSFzd<u*l1Yow zz)(``BBXQ7S0G477DyM^TZ9+U9uhI?i^U|OM5k;Fd1RduX_S6(N!NpJDg#L1N|X(3 zS%>Vg;-((5@Vk8pF%X!<EDFQOsH7fMvQqp1&qRnh^PvBs`6%T`S64ddHW-=PfkvD$ zr6B(Y6G|r>MFQvrM-+n6V`82Kr-t%_Sn&ojQwOS|Xrz4yqO4MV!=x-OK><@YCT!3n zoT`Wxk0H*81Eoj{XQeR1+=kY`7WfFv=%@=J_)@DrtA1_p^tAvC(yqAh&M3kzGLrax z0$79pZK%80Vg5*4dg;)j)(QWJx^f#sc}^FmbMrL7(IgfekDReOjkKOcutn|!l);p9 z4)BClRd>RTP9BN2bzPJG%HAiCNw$eSW<H9i1DZLB8CgU|!D@*q>#7YagS30YnLNN| zFwUgy+lJlj7+V0t2&K(F?Db|4{Rr9&{%2h;LKN64OdP8TM45cfgr~_|unX3+e=5`> z?RV%$Kptvfj1SXmWN9@u9^R%nTRMNH_$#PGAvq=zNL~-EEi{DiHdd}RhWD5ENFQ>A z&mW6>-Sw$M)ApkEM4hTgAreX}HBzh8&LxeY5cH*G5EyKr1$Mcz=&II|<)ko7UTHVD z5kQ!p+G-`asBFzz=2Ae*at>So6%Gw>RB?4j@usu)q~a>LW(~q{4)|dm942LbwF^H4 z9DG}Qsz#H9+Mz`?#?>xBKu3ZzcU%_^$^fBAX_9J(t3_%~T^pM$vWloi(pp9f*{Jq) zKdRpU>I&}Yg-x1{<dTAdPUpq5<_RPFTX{k^Ks8nBq@{LtrQmsWJRa&0HLGku45goM zE(O^pI`QWQw$WG!Xv3iKup~$|BI*QRez|YL6Xq0HS?_^yg5JxFs<Dp_;?k~^aDoeI z2;h@4jNn7s`P}~H!aOpNJ?hKkiOn~u|Abdhyc}NjtL>)Om!a>KLK%8{?5|smO(~A| zno`Ox%}nT4waNO%2TdMjm(1B+Ewig<UQV{WUT^4^8;}<`4oAnGHhUwC;AKg+yc}f6 zD2Pbz-SoVzPvpZ0`AyLjqL-syMVsD1rJPmhvE-*6$BN457fdcio0>uX;p0N=qm6E3 zl6z*xyElzm!uqhu{XI%sOGiVtx>OSO*2u`*??#7@UKpHkYu6LGqs~YD`mo``^(b_x z%YSv5BgR<xZqzoP6@Ei5<QMLYIuHIiaBqC*53v{WKOU863;iL|e&AjKHavbJe$<NT zw>&c*KM}j#cp>zSwz}1yO?T`&ZnvKGx7eObJGcG0wBzp84O3Tm7=!D~|7xizIh0iL zOXaGIKg6vmUF9rFIsN2`XE!{TR=4@Nv_IeXmwTtp**9B?R(|;8iKH(tHXVIz&(~Ec zH*PIi3ldtA@yRoxO;vwgb}Q~))rrwDpDx+=8HAwLR>Q+R{(L>b9v_u5^46k%mIt=B zCV%%z%ZQ8KgUT<LS~Dtd96Nfn^_*u>T7H}FJK1MP$9<PE(7Dh&WA42l|M7+8=8q$+ z33r``l0P}}!u1~`ooyw<-hE~F;kxPvM=$cS+-(c_=Ww3^A>g8_b2|?Q=boMNXwc@O zCtir@pOiJ~l+Wr5^ZvZ0@c!!YKBIgVWW?RgzHKTD98elm<{ed$yV0JOQ|=b+h)%wc z>wS2+;gPJVBck7^2(qjOA}yZsaMgF2@V1&a{PUC8-ka~No4vJ1$rC;1HbsT|fP==_ z!|q~fcGGLl6rZHRmxA*rgqo^y`|!7l^s3}t6QBU~c?t@TweSVcWtV<FleXzV-p4V8 zR>!WvAfx%s^8rSLp^~-%KR4a8c34I@c;Fz?6GA&MyNpYARL`{(EP+kc%?xhpFYXn* zF}uGBzfj+lPN}Cqw3=Uy5k4qof_=sq&a9kjFY8wPdcF7tR{NXo*!>sg95IVvq-38^ z$T#zVI5SOmcdkUe)K{VJzwP&{C{4eZSC(B^Wbkd9-SSA%R||7qFaE{!eld1H^f$C1 z9IBM~SvNDC8dssR`VvOghjMlW>~%mQnAQsiqaF%<UPKi_%7@;Pru-=S@ojrzxE=dq zTUq?wx8Pr_#4sr#=ENjlL}7jkPR3@S(akI;&aSP|R2JG+8p1G{4CRT;rNSjDAjH_P z4Cb;$DM<nq$e+j-B|C}bhVmi!a!P-KE}_dsTa;z=b{e%8rBQXr4GYa^Un$?@$~g;^ z(5OPvrCkK-;6RDDMS)5scUY(0QRC4|qjgvzw`sZvm6S31Gy$4mqz-K_oq`udoyVU( zTDxDPiAg|84Bc8BnRJ2&-_ZqAv+&?rrSmK%@MDU114iwFFvM|Kk<FA6`_!!08t&<O zj}$s{Ag4V=Dri#E_UYInzLh5W@CWE9l4!y|49FcmgSt9d#s$oCfaPGHK`O#^uy2d> zh%-H}zJU`YQtM%+2A2<pn?EZS_v8n8Nsr1f!=!zZ&Mj;LjPKz&5dczr*+nR`tCYUG z)F(BC5WqxIzEGIt3F$xBQy70z?YN>~P&nocen(@wT5fjDAdF`Nno?HQe_F`=q^tN{ zaLe4KTuQaZlb$nxxBu<X_OnXEJTK*@!Fzk?0jcTze_ev^{PD3X!YN%+#Ob=PXb;-& zD^y`STv|o#HWOE1`?l?^s-X;nI4pb$mB=tep>ohg$439?sE<9-Vc%t?L6PaiHoE=- z#R=p4ZF8$?<nlRjMEiP7Nu*syJEwGx<g`0)m&6zoYp%0H)<FPr$w~jo2U8f-`TJb) z;Z7&{he`>xS6^wBTFMwZCD|REjpC7lIouxvA*xj_^NW>LOD}KRbnfqs?@0<-d1XL9 zau#~wsG4vI<!Hi?lwTn+ba`Uqs+%Lelw6OvWuoqE+cNHv%gPBuM46{ZDT2cVC23;g zd;3oVno?v*VbT2evM3il0~V?&CLnD|8R7t0{`64Z#>2js_X3xuyotqO))aVQKY3i5 zqp{S?_@DaaLL`C&MS>cZ+}rstMNnj-DVEt)zi#<xR?LpW3-D`ZLhaVxO&*R5q^7{} zwb)}RWT_JGoC`OSOROIn!*iUr$k93W%R#ZD!wu1w%=x_n5=#x?h6Uf1jLR?i>S<$m z>48lZZ>E>HnXcN#C&xBM`Fv&cENbwx#`s71HVpUN8i>V!=w4UN9)*Ep+Jas?6b}H~ z>y5b3{L=gf+<V5Gb4zn8YBL?(&YSJIT`ddd8DqjuMQwBVgzfxv)#|Cvj3-a57?n7{ zZXNlTdsFBCusHO|6AOp`<=#fe@aCcy=J_uM44owq4R2|fI&b)Qd&kZHA*N{W*T)j} zetkG-(uvg{W!Ib2YaeV$d*H<PJ%^rXyFTHy&peFt_Q#}u@@2yhmO($gbhGyJ$8R+x zeYx-lAkpKwOVXR332!cFsoql-c<IZ9SgLxvEbzu6`zv_`y&_jUx!{E*U;Hv=bl&m3 zWr2TMI%&ZRb#+ZMU-JmA|GP&Y+y2_29s_N^hP^R5?wf6+Pt3kI&H2!C59L+H-AeD{ z>}y?7{>Wbjj@y4^?X0ZY$(8;5XTAC4qQV8acRjvcm-fokxJw5-Dvy=~b&LKyvdrVA zGyh)R^vVC&d3bJ4wvQ!av~A7Iy?r*{-*hNA=U7SX+#`!G{c`jlspYxjeP#?Oo%{DA zuZI2I@0&AVq@16Px#nXz9~*ZMPbdj-ER3o*EVrD$@a-E@yA0ZJGHT(ICuZMmj(G9* zrU5VS`TF3iqk8QwN`B+}*ygEAL-yN$DK9Xl<M+$P%K;77utI$<4alu1P4S%jSD)af zsGi29p%y>Sie)z-9d-R<TKvw#vsxk_e=_XJh&`o)f2oWJh&q3<xsTHanB?pe;rnDb zH|(j5@Sl};BH+aACBULt)!h=DP4^y1oBj1Yg-(0Q=Qj-&06GBx!mrm${01;S1ow=q z_pJ48+lF6OAFQ^2MT!F7*h`=hJ>!@Zd1G`=PPN*D<OJj)_9!k|SuR{O6A(41{7)uX zJIU-?`>b<s#SG`(@*9tWeW*B*kwPbgzOVUYyVm+9?{&ae0zv_e04aUV;ZB8159RDo z>z;th)cAfe;f9oC!pJOaRQ?mjY_L&q@<ymS!&&J?*$4rm#sW&Wik8Sm)S(pK5Q%_R z?QGO84v~Ps01_Z3peQ*CgYB=XEL$?r`SjHEjIqKGo#I?Rl}pyi=fNFHz;vX*RRV-C zOv*LEzyUxg%dVEKVjcp0;LTnUSNmCA2&Sc{|Hl@t5HZA+dIrZKM6(9BB~aCon6`j4 za5Iu^#%wO4JMc0TpkYtN1B1HaXn;pocvNsIK|mUg9Cx{2m>EdaC=!Wu++_e-YhA-s zQf!QHqQBk)Pz9I?V`_E-_+F5ITrfg4N8-qU28dnAGxtTU_f3?YBaO_b!ip{N`6T+J zZdot;mQUd&BqUrP6dGt@DYz~{N<TKmLAk9qWg+X&d7bJ9WF$sw1XOebsvDZcBe0`2 z!4vn1(Vxx>omqyan65pEK;(WBURAeKO#m5jvY1t-Qp8?1qF8Asl+ZJosOTiLFB2kE z(g;U2qQPxzdX}o>=Na&Ly0jV5LJ(a85T|A=+NS1I(!XEro7oIih>H}?x&c{57NbEY z9f2`xPnTELy0?w~_rTiU-oSLpm{S?kBZ5Wr-{Ua5u@QkGB$(L)msQ{B65h^8J(M^0 zyCe>9rmy%}V1{;Bxgzr;3g&>Kr0ATQ6L^6YSn#ia3+ySQ)k5V+Ef|74ny%EDW0dpc zI)DOHyVs_2P5KJS72}dznv~u#hhN@FPSUNuj+S002-DKan$YDEf>=_e($BkC@GjA0 zexG(Ps4~|gL0a(^zK1DjK2OahW3@c#NFB|P&$caN<tP;D-xO;Mk!9UV1Cm~U1tu9} zwbOYB4nY`7zA|Mi^eIG~W&dGToB{y!RtlEzlx8OQSEaySyF6xi-7`tF%T!TUiep`) z4eP{d6HRE)<?!k;pe=|${;<#zNJ0;Rl!jTKtx74*o3eFX<9j7v248;tw5Az7ZNcJW zUp{RSe%d0?v=HC~Xxaf+E%L9$T=e*RlSkz+LeuDdZvuzjPVq9ne)`+dx9x_Q-c2u- z+CfUj*}2aj_Psz-syFnG-kGz>;BYUEHiVcDyO-uvL>j^>%mrAs8=^|h`4J^v#wzoU zlECq~vya?wzj-L{R_W9u%Pi%yJ#zx5mjskdD-MccBje@a!?!zQ8>2Cs<hj6}x6PYN zE?6sef}KjyRj|Yn*SOT!Z2V_bp>3?&w4Jxgj`d4)|9OvliD8ppW8O#UiBsNad*$XY zhi;F(wP5l6-$&dkUHwt|vEg6eOEmoZ`vFt_-B!2eU!P6?ZeOn7uunezVNv{n+JBTm zHM;WJXAc`6?-4hp@x!O!kbT@-aP#>Z@X#~Z(8JPe&od9Mo%pARryPD^{`P&J`J}8N z5Y^slcs2UFN5(w<;JS&CKi~Y*ivXz9b&F<9IsEUL*UAFFX-#@GF!S`oxyQF`&#hl^ z>-e|BKi!p?2`)ObIrG<w9oKVh@AiJj$Fd`O@e4m?UY`D^iKUBn7VdC1c^-N7`O!Z; z@oCACb<K->{uK9V*84BDR$e{}g{t`0b0aJ(oXbCd;q%@1xBWb>`T1>^-<dPG`qk=D zkEU!m^<w{dF~!^WyRWrQ{@%9sp|Vro^qlu_Y{;!2&qmtUUNju|>w^Z*d67@7^)7rk zd2vfxOy5PH-%E~9kLddJ+9kR7?fO^C%X_~rcyq<Ug%2e(H~bJWy*m2lFXc=AkoI-J z_L>O)>3_M`=i(31mgmwkN`5(99C9mbK=XW4K=tAhfYNhmUqnvI^1g@_xzDN<Es=p( z5gL{}qwUzPuk)5wMm0oxpWm6+6uri0?0KTo@;9*%G1NdnA}q~sS^e{-wj8zW>;Z79 z)s_iSXa@MW22mB){b%h1M9uljjuSIY<pT%X!B+PF3x#NQ%GW<{su%#4sWo2rg<p0M zy>Y-l4}hP_Uk3CT;x_&nF(QGbM-5}z!dnKlftv_Doz_0m7VcdARt|aVE&Kvajr=MY z=rzo7cZ=G$+<zYQrb(uP4%@jX48)bmpHB&$5Zv}wz)Cn~Bfkn2(s?rnAk~IsHo$1- z%Hp-~;o$5&`hFIrs-QQSL8999At;OZBo*zn?HZrgY`AtI%0(<X|496qp0|!u8vg*1 zP)nwf3RNtfM<DR9@=NkUIOcbeA}xNzv#Bi|%EU#lYR9(D(i2YKVOJ$9=@OC4VEY|2 zsa`bzoer*;7NP##p2BRMPpau#f*Obe`DrZGNp*ruBsren%SHb~Kav%y0RVz7LS5h~ z<=*)Tx2Z`cl}g3rGogxeB6LL`v=r2IffMv@GK|3pc7QhEIDrH}atIYcpCS1mWdj)y z`DTbi=o2Vv4Lv9|sQ`^Gp-a82U5>`Kp(;;JwFqaCiZ`V<Q8ZF=m~<UPtVyIaQHoGN zPZCiKm#(F`wK6v7Q2bi?zE7b3z!8h*d71E5O_6bbkeV<n1O+D;h`euAN3Yq4+!Oo- zDE<GKd+)d?&h?Gk5;b;3us2kc1wo})2p9xGSU_Qc1y?jS5LVF$VvR<lSO5`}uA%}< zS(*impm^-DV4@TYQ4<>mY*7?7#&h25ex8|S@#OdWz3+eT=R}!(X6BihCFe8WT-SBq z4?^D>KTP!KV2klsId{bb?~LOo|FU?Vx<wH+EEGB-<KKD|g`tdXeFx2-4A2m-b3fQd z*8?j`#1*wbph$si(N2m?V*|gnQ=l^{`V&gd7)^0ck&eNwkSMp@dK#0EzWHOr-yyV? z6PzkqGI@+`XVm!2-KE<J?_w%xZ%-o0aKn~>i(47zTYv-zu3GYh^jB!#!<Jia%W_A} zgVxIpg|HF<2Q9Jytx1reP#@1sv@}}n8d{Z@p+@SOpF`Nv)Px5(Mse(Be5N%ZhL@5w z=lXQqE_5Jl)-VWj@KQCh<#-1loWj)~hI889o`_sxq1hNIZ^6SW!=kjkJ%S{0z$Tme z18R*h=%H#ZF*YsgPtdHAAo&0!Sym}Am?0L=S~JHE*&&b;rH}Ar<*eEbU*)4UfFh)= zG!qJ3g%$yzui-|1jG;!7!UQrKLuF;pp>|E!dK5H-Ff|Zp2%rdVTi~(K?u0$~GX-86 z?T59tZ!|{JgGqr3<ut`4rgmcpx5$FSDA{$pVb?XZ8`Fi2G6>Uw0~cJx%(%`#ILsG4 z`^jKTnZ+PXd(#;Dlzc2R?m|x1*u^jKAAWhlmY;n9P<e|oZa<%vR1k6qkQE4WDp;Bm zFI^+k&2^A;@O&ciG6GdSmp96Kf68gt?j=d8>lC&qt5`oe$5rK?IWIHmle#WCWuDs8 z#7oi}oK-rnF=Na}Pwx)iXtNm<T}Wfa?!{hd?iF*wXO3Cp={l=g8hG8?Xz|ee@iwk= z8#66tRr_5^xo~Vl-RTY4<@1+i7@dh6zOe73V{KDp$;Tqx-%L+2icR?4Jvy#!n8lyJ zUw@r4>dw?S|AT)#`N>nBcI=(np=F(0&6R6a#~i0vx=M;W|5EnN4^Qru#3d)@D}H!- zuS7lP#j3a8ZkZ7r_EM3MICDb5*n2PU6+K^K6*?<;k>t_b(F;QTS5&6_R{7$u&{^O6 zuc=JAS6Nun|K^s6GlRxOo%%2^R&{q-ZRx_GFJg9h%nDV_ii%!%`1<0rvwNH_+*Llh zp#1%wD_`EvQ5mXtR@ZIOb6oxRzO9lFzlI>QjLh^6E1X@%<c{s$Bii_t-@PACUVrv` zcIhsslAvBwjpa3_@p^j(7|*Kds{9~*JFOxludJx(Oa0tyXP-~|p{w$Er-{{%tJG_6 zbR4x@(cPg}u_AhuGJZ&l`LCoEX<dwWdM=q)H~M|Q4u>|}*c{t!skeXWJN3>xAFubF zIwSS`NQ20VJ8P<gM!Zv-`K_s5aqL||lKWTpH;;1uy3DrWWA%uA(4sy)O|zJqJ?Bc{ zxU$KWYpRFuyO$PJ_H^ZStD&}~m20XHkq#=WH@C!UTo<+ltKMZ=6uVz}>1y`zMntSS zZH8H8r_{F?a5Jk`2SmgMUc%OzYEJ`;OY)qAoSv?6l?HM%PuF;9vNCr5B{wtBn8hWp z{ff-#fGh96e_3t!R@%nM{|7jGEmsGv{w|!h!|O{{yS??>_-G`d){=}-(_(;HZ+61~ z46n=HZo6;o@V_>$?N|3Y{-WE-U19bocddml*8_ZGfBfFAu>R>_G3U|)AgJ%s9~t1s z76wxKrhqPk?7IX~fU`6~tNMJ?v3`O*u&JNgq-t?G)Gh)z(x)DGk#W_Ejqc9A>wyb0 z?@myjb_VRS90(fe!c?id5LYH38MPQ{6j7R6RREMKLM>Q{&7q5gFOEr!o5<>7suzhZ zLMWTl7qhrTc}U~pv4MJmE)?*i<tYmQvo|@Xum3?(VlVzC9D{#IB)~m3&L4Px3j?kw z)fcWOdV~BjqH?tu&&{sO2Pk>1B^j}l4{n}!3((9eU=A*WEcJiqxBpAdX{uLa)Cuv2 zi(!K7BbtI-fLc!7`}n1JV46sayND%RMPquA(48kJoczbn7=zh}=x@kwuDNCe41tiu zOfu+F{1a~vNQ*$QOgCMdysqI|V2F#*SMv{FGmaci-y!*U^n*<<gsrIk5kV3qvzvY_ z*BmRH0?Ob~aZ~{UNLpzEQ@9~ci4v@Q>5G22NQZ|ZM@1?c9t$fLq86Wu@!)?V(#}&^ z0=J+_j{uY8E6^SiNaTT1e}X2zP3yB5{T2$#=s>1VkuAv`y3dY4m<iGok9AY|-3F$i zc{m1QRR~%cLMmBb<l&$nuIrI98&z_Hscn(nb!Qh^B!hOPNWfzbl(jN<f`XR7R?uu0 zC98N4@t+p<i@)zDEW$0um(FFNP9C6vFcX6#NIxWKfo*tG<=!gR_UC+Ww&)exE3lfN z7{v%bHKA-SW}&_xYM1OmB8v_k(<I7?4TRb^T<`zDDt9J$X{DWri2fIg@Nb%2qlsxz z6?IT<hFL7+M0ZZT{?JR2CC}r<T)9S!`s|$ln&iI*NLmY^S&wm>juPj*z#qU@AOMt@ z|6aibE&9e;iJB07LaK=>+eFEVO(%+2n2zgOoUEvd4QG+phr%|dYc*b{Es8#|E!-he zPTQGE^)17$T^zfBKe7j~_&Ajj9-Y?2q53xgT5XrP12{>6%DO?GqPP_H>*EaYS0LNJ zTe-GqcOWuSK(Y9VHPEfPgmf-il+!3%l%Dk6qke|BJ)fof_dor!&u!<!d5hBhp>f4y zXYN;$v7S%5gq*zW7QbLYaX-T+gC@-IAGe@bar?RB<?kLghR=)(H@ca~x8344TmAUB zV%4(H9W{EL)>Un`DtTPdyYAy8b-4Kei=TX4mu<FExvRV~KwxF+cZp7Ov!1tA$GOg` zs_a$#&6qW^-eu}|S^PZf^RA;m$`j+CqhF7=i+5CI*Wxh;8uQJ&7F(QsE>|byCI`1G zcD%MmUb3+!X?A0-_x7HHF9tf*xf(twzWT4?G5Md=)$@EGxSqg&(M?V*UYlR09$SpV zhFpCZY4q5wO*?m`ym)A)(!5h-MUL~bfGgeGFCJ2~b*-|zSGZHVi2RSIt3#cpPrK(Q zTPnMgEK_*~EKz*(aFAv2Ev5C2lw)BR9}mnsy=vr?+N(=%oW8Ko{_45Md#>15FWc)h z|GVm6|L7ZIuul2s-EqDh92LiHTKl<QX}EbcV8V<e*WRDFIeb^-wRe%zCpVtnaA|<D z_?JF;)7sV7jqje=drrjNll?-!+4?H8^EH*kV%-w?rfm7Q0ZaQm?l>bQ_^9oJBSpEP z7LO0zJ3hel)bHOF|6P{ypfYFp+LxXD&CgkW)h52Mb;OOMN9)e}9xd|nJKEx1&al!S zx`&^(Y|t~FaD4KotdSS*$Vvz4wsf4@BFp;vh4GJWc>k>0^LO>$i3j#QP<66+Qu6lw zqQZDAOuFW!SLTU#c|lA5Rimz$^`vaM=jmH->t>r=yOr?rUaoW4%ju(5ymT+SSr#^> z)AF<J=6SzZTi^58yS$?%kh&h;`!TxzAJMuM3wNyEp7k!T_Sn13KA)a?+uj>LZ&DU; z?B3hd1@AJG%j&CpIBXe}TvoSv$?CKKjHs)JI@q4@&rDuhADehD#s8hU(LrrcIjYR! zidT6Nf@&&P)#Ri8?=sB1?MIdA@4C0|h(u<RY*UvxZFO#~Y*p&pS>@|47T3!97!@W@ zNuCx{7%;s-(kXsMc}9ceb=TVoD=L<#Kh}-=Sox?gaL)N;?#p)>zfBqZDS6)7e)T8+ za(nZk-9_KuoKNom&GE1AHa;35Y))t$vk#)wmbIjF(I_Le3HC9&!CV8FC#XLbr1n)d z!c-HSe*{6{50Tif*>~Mvq=)rCaM=Y47E{tVlZm9pnT+kHxYqWn5K%p2Q!&y5-c136 zK>@2D=P{e<Y&*jGWgiS-`dBHm5bruFt*@8vCG`v$_v@vRNN5FKor0a3Om~wR$4$k^ zHrveUEQnt^c*B>|+q%gp<o&0+czj4_gxFChAgXE=0fNYRB3)_RKP{omu|9y1ph;8X z%?4Pos0q<Tn9>-9SUHerj!OEpwL2bc7XwoNBa!_BqWm)&ir3|+g$x>rM4XKTTMcR= zkI(yI12=q!zMKDr_x|~aIYR17&M=b&*Fkj1Qd56_taSlREXA-}30tKovJ;X?u)gq% zNT&N@No&?Ji2O4`DDu0^9oEBd17vgNVumLBL@{f!9wS*<8zw;Ln&uG(K|X|VyaKT$ z)&hYRM=OE^9_)g%;+por5mk(A1w6;E4@Wfp&F=Le3*HlHBPZrD8|@g1s8fKHY6;2i zV}c!UizTQ~@rFLtt*PRU7;!KQ#|sf~{07cYPMmUKoU*h^<&Yes!)Vd3mK@*UGqU|0 z=g!bB2`O@r(YRWb!UALX+>{;T>%y}b837}o0!zOWZ=%07zzsks^FYrj-8kw>z)2Ko zc=T_=b%fovzO)7@^McnO#DAc$MbZJ6Y*e=hH$ckUp@+xP5<qWuFTU?{2b!2d;`aqI z-{{;3WsI6jZ$ED;3Ea;b5v0W<RfQw&@K2FU9fM=YdR+6QRT2H5l0D+Exd{Y+5q`1< z?5E%^BCN%QEb2%AHlkyh^~ee7eTGKnTG7m!Y$7$OU>i>5#e#mgW;yS`$P(alBcP9w z%9qHEzp0S)gqS+OiS)2~lI##Sq9m1gsL-E4m~6RZDcOksaEM?qYJ%&c<0uaF7ds@t zon<9~%vU4~gXopTkoBK=j1)l4vH!0Q;mLHSq2V_N?~t&LL7YtyoJb9wu_1CDmx2>X z{nCTR*`J6E=!Ttxpnb6*7VwV_TTaTBMnwaJk^Knei+PS8WzU5Jno*jlhcyj`Ftq#V z!BsNHntfm}n{0x&IKZ37VG_@7J6_)B-_Iteq1}YGglYc6e^E|2yQlE*_V{`JrkAmq zkIe=C1aCz~z&x<ql*B3H*Vq+;+ln7wfBezo=YiL9@Z<4E?|+%@Fpd7UF?^couFJWp zGY8Hbc+Dnf+U1Pb>X-2@kJorMZg?)8=u@l@W9`GNs#KrifmQ2nr9YOfnpl0{@fwdu zA3dJi|JvumAmy|XHAN@(DXsS@Z4RypwKxr!TO-ekeeUuIlbrqQ^v>W<Ii3GiyztY$ zn#5=Ks@8n_*QJQyvYgDDH9t<g`h3dmwK<>We?Q~U`e5^#q(u!irC%RjBl{HjDFtIL z0~TkQ-k9+3zT4jX{ht<{!+x9di_#-&!Fy$b)m`cI_|iQtbz2Tv_6TYib$9sj)2b)$ zgC08G{oB&T+$GfMiS^!TRttlw9{uz_+GxhYE4lJ7dOkd)_s6#TpZ?S0^k3dvPv}4C zziRp~#gc$G!9klE{{Bj?-eqR3|Ij07Y45!ep;f8I_bjf;IxldDcyYV>(wY7P-`2_p zb)0u{_N>7hk1spFy4~5rFJ`=7{UIOC!5;_2w{PX@+~L^Ata)8$P26<z(L|%#={D9o zi>IzrB)s!k{#}CAW}iLt46mL2WoJf4g1T<_vtJh;{Wx&j{j0qvDR<t9?fY=TVq<x* z;>`8s=e)PRSa{)tTfzIAZpT*^n?HFz{_dbbsyRFQlwaKzIdt_ny}ttwcX+?=o>c1G z_;v34@6Q^o>}2gdK~h(0Q_yg3(zdhzE>4_SeEj`?S}0z>c{M8eKP^nYR>X&u{r1z0 zpN2NB?V7u#^GB1BD=O+se!1%Xo9vfYKD{md{?kIwu<FR)-iNOQU%TsXUDoALVZ*)j zg}<$?UH2QP@#Eq()p>f`dw#Qc%j6|Cb(>$_JLvGFY>@I@*4r7KXXh>Mw{LY&$-BHI z#cQrN?pyu6&!B3z(4{Y(7QD+VELwB@$;ZmZHfw#W8a~x^`uE%9Cm%6#{h57zZQ|aS z&QI3d_<rxpDSKZ|yWRCxukw3uR-JrnfAw8D{<+=m(5O`>-=qf18rJ@Se;VgJb2+)B zY@okqLtukV-N!K>hx`Tr^tQfiec2{y4L&&6dVgbnZwLMf7+79h>v2;3A#O=}j7{<a zkl)e2#$CTSu>8o$?QdtS?f2=AM_mJ^1O0MermyY4vC)6~n<d%fK3+c=Jt?FIhI|MP z(;tmok{&kc<n}iqTR8ib{Q;RSgh_g(O{1jUiG##;0w!W`C%Djo10Sh;GuV;;p9U?# zlOC7*XOtl4_5v^a3C^MLP&pZb*4AW`UkWG?L_8ih13zBv1A#9P_{fkhtS7u(pd#QR zd@eu(akI!S=aT;$`<P}3mz5v;!#RMHIg`w46FDL_;htcj{{Le@6cdBQei3BY3ff_l zR++|q;Xk<0213SKvr<N(=zoqV8A+Bdq-XK=F~A;$z_<p;oB@4q0|HqU!x0x()m3Bo zd^>mJTZWGq%KDl&ZJ<t1atoj<^S}jQiDD5-p~VEHy|9L*209rzqUAQ#8lZmz5iT(q z=SiGg1zZHZ0drYfDk_qsQPv-mmPn%maXL<*o2#J456;fK8li@c#68C)!(b&{(Zra* z?M?-BQ-!EwqWV#RM@F=a_cJFO_8A&7NVrajh7y3a-7fSPkS<lss%6rfQ00fjTV7A7 znnj*Wm}Ei!&olR80w0iuyOD7hl&{Mxd=a8ss&yxoXtqESt<c3nFi)Mi2#iD;`!9{6 zB2oFHnTc{W55jLU*aTz>6<5XV*0Id~*5yy!bO9W}(H4)PJs};(P?i1I?ZUqy;fvxw zFbRJgb{UQ4N*XI#Mld}RoQs>%sFfKR_&1=6^Do`(`qxI1r7nb)rr-BM*8dnW5Eivp z5p$(sjcH1_ahnr9DG`~t4jXUq{SP~3LTw|!kWR7Xm5!4TmpcSAQ8OL$Mg<1suB<36 ziUo_@!qj3$BGiA>_JFrd<|k=y%==745{@GzTV{p3!~dLn<13=z;YmL<re#l9Rf0CK zHXq<!8#INFM4>fJy(OaX9R$?OEP6(2Btmnnu|vo0IO&$^r{Z3k5=aPzzmhO1n!3I8 zF3jCt#5GJ<pG{&WvGES1@5g`*{dNSZ#7E?*xGr;c2Vx|c3|bhXAA^=Yr=S~-AA9|1 z{Q2@JsCL{P_-oS`S+a)bS-xK|cj??IAWbS9C?`f`-m9M<OTRr&Us5cP=-8UE6-@9u zF6P^gl4I*aEUKZ(UQhw4al~>=_2{cWn7ir0rn8^W{(Zsy3~PIVBWK2sy*#rhl#p_) z*GI{68AiVWP444FDZ-`SgU0aSxZ_3_F3*e$-BM({DE$f~!|zIIe95Sq9j5uKmVNoh zlU_x}tCp==R~<OT<#9#h4~^m9nC=)=lmB5^+Skfi*Jf4aJg)dKt9sFtsomGeuv?|y zt9Vqr&v%7N4{Rt$Es|k;>ss}nTWa>`H>#dHH=b|VwRqI7=ZaQ?l;3Wt$@*32Y4U@v zN{@EML0{VBoaw4e^xd-6+~MRJ&+va0D^31Y>~!?s)m=(<pG&s;wI=oG$?CkL_o|H) zALUDQ{6|iYKAKu>bbF1wLb1ks>$8TMLkWgwe1Gj7G%vN<diA>RH~;wHaAWR4-v#d% zrmXz6f0%i{unB)GD+hSa`mw@%M?$H~%&*3OSg5!;ZSv_k5e-iR{BlFD6z;aHda`KQ z;B(*YQ!SZZH}=Nw=Gh}EirQYpa<J+KmzUp2QkJ$m9C^e#;#g_*-opKfJ-%?uZnfc- z=ZUdDeVlUj-T4J~F72uQ)FOEH!VkY~Z%9e{5aRsDnmu2+B=%|FxWMB<{=m-ibABIY zpB#P1CuU{jnLna$MXmFGQR<Qx^I_V>IT5E`nZ~GgKQ8?F^@+=wJ=gvG*Pz>f4?X8S z)NxG6#Fb^&GdAo<n7%IFdHbDq?P83p!?q7@wNCN)ZRe5r@o~@C`RY+CKP_y(`@&(r znmuVs(-RY?+{inh{p7uRVcEDo9~O>XsFM{H@ut_|?A5W2dTzci8~*k-oAvRgl|1kl zzl!`Th4(HVxIeeC-NwjUbqNjkGG_d1b?w9B?{X@h-aC|_d&c*x0WC`2Wkv2=ea2<q z>iETLpN`lvIzhLl*T6UTzb>1X|5KUuw3pLM+b-#}aNDQ4$^U*EH{xB^wzB$}J;rUZ zICt;O{c&Xh?aS)UELpv8zRUg~kYJkPXPu9gn@+x+cyY(vZyMIteOHrapwg*moZIN| za%^I`ddN4czcI_Yz3W-zNq=CXj%=GD?fb?2-Ub7&2Fc{Ok~Yt-tXohva6y^3&YFr3 zsc&dt#-~4id+EL6W5r93il%?%o=jY8I%$pB&wq`pUi)TAdYoVQ-Zu~x|M<-%ZbHX? zfBfeC4hP5iZTeWZ0tXzg10GHU-t{BAD{24Eqx8UUWY<Da?5FNrbv*lV7rWr9#T30u zG%Ruc5&Q4Dlt#OwHi4z-uwTaZ%U+~IS`_s_2T@NX{yR=0qUtVg0OsurDqW!SuTn6N zsf4vmdGwgWkdsM*q#-J8sunYEmvlvQkrYkq1re}c4oQ9H0Lw6D4>K;*D2B$61F6Pg zWKYnf2AMt+{r)!!tR+1P^u-GTIgaIhE<gU49;q2PBQ~ng(io}wG?c&j@xE`a1{P^s zyR1rqlgwu(aPvl@U_8HObq$~}f&Q3IYRYX=YLU$Gk5s~5SO5Yh?;KIC#5t^NLF^p{ zMgl?My2c&E7GcD1_#QO15c;2;%P)h9240zohXYjo&*n2ia18l?equb2n6asx0?s3c z73gy!!Zb0SNHBO7VNeUR7(r@PD4;5nkd@jz@PY|OTy$9z;yhL@$qN8D2=TS-Sb7h` z8uDS;Hd0~PLSd}W7k)pq6dms++7g%ymSpF-x6WZ|pUGI14k&_6TIj;<rNRMStO{J@ zu74ZQYS^2V6L4r=&bm|RlbYF@y1;+IAR5)7Qgr%4RIi-}SU<2EHBm)73z*+6t62Xp zU}Wo__}#gre1Te!t7v74kygwc4kY^-E-ouiz?qst3hEn%qgv3@!$(HDRIYGpjsUPz zXL&)|Z29PoXLjKm-G7f1S8kzIVX!s~t0B<d1|2cQPldH((9x79>@?*IpVes=kZwq& zo;-R-bi)19$Oy47msp-D8mgLl&Cdpylt(5pAscRj!=EIG!JyD_wOKzhQs8*7POyS; zb<tMkVj!3C$Z!UR3HQb3K1B3{f#%t`fd66Ovq$+{z=X9e7`-BF${yhHNsZ(;@VVwl zbq7%ULab#ENS-_|Wd3}J1_iJa4q<yR+m<oC`N#v<yAUcROQoPRYGukC-}Agyq5rux zLCabD3%_#|%L8mdBDCQWVLY#Ca4QN<qe*z=4gg2H$5uR7m78)gvEn)DhK%JLYbJz4 zbxdRgSh5j0J1X#muE=1Jvm99OxeFR#uw(6UtQ-EA&IyePR^9e&(+D6;ns9NfY!muo zJj02P`bm}p^6UumIPcl5kv-uUI9@t4uH^jBwmOOa(+<ZOn1-x9(DrgG@0ir81Cr3l z8oj?uJqGx;pW40R$%q=g6aP|r3@V=9y>e5S^`p}8IRgx%^S}I*bLMO1zCahXH&I-f z`d0LwA&ohWo2*omdKFtcJeQyIdey7gCEGsFv-=v)O%tob<~C;GxB;Hyd^7YLb9xR^ zmLB}*71^~opg!5^vEG)N3||}d>$A^2hYhTb%kAUR%^jb;er(LGYgasNz`u&;89lK+ zWbnn&#+-*o8}q+>{z+XWzgPW>^`tA-9((l)i)U=EtSOpv6ilc1=wsmOeA=h?g3}A0 zD|$BCM@5wMH`<u8YSFU7u_w*r8tUiz+iXr7HgAK|OSgdRnYp!xZpSCo8kv;YO?jt2 zVl&ZEUGbydhuYBOv8h=z$9KEDVzl0ojHtPX=6z7<m1HfA_<M)By58+beTbnVYs`&0 z**v}6RUPj9x}eWsd6(2%=a==AwK`_g`MYTS@mG=umHqj`<n*wmDHl@B0ArRWU+;Q- zGrRuA`bQi53RD4RD+_0|j#@tDX`jWjpA}o*Ydl+c#rK`uI@S2($s<qC&%Jy5?SqrM zyGBj?spF1@@w+2ODGyj?6^FeWyLV;Y)5vd>Z|mmnSiX7e6BC1iuF_2zk=Jh8TNW03 zCHz`*{J_?dI?wYXN_HBA)f-Jd_AXav#z*f}CZBTWKO7on=#;$Jrrvwsy(8s|%i3pj zd0OROH{zg`^D|}MzuykI`f|FlrS!;}8;iHaW%o^6vU+9Wy~8(_td8~1+dH(EZ3U?8 zTye_b%5x{*c8T4c7PxI~-5JF%Y_v=A?u>5$Vm9?#ckUUMv+Uxs$TLz81DVd6%1!YD z%eOd{4pZr@sU9<;?5lFs#c4-O0A(lry>w(-avqJiodC{KANW)UID6FVh{+PwZ{GG5 zTX3BIg0-f9<ugnR>A3<2ovvGfL-glixR8cDLV9db-36z;P+c~)TU&J;90s!%$d<E$ zIL(D^+I#iOSs~M=FF&}soypC`47<Qvg0btyja`q+rVP|TUx`fIgE}{}DkKsW5-gVo z)FKNQ7Oo7+8`J(0!+Q2&r4pi2R|0lR8EGnmumKe=zL|LESG5KTqkw65AuQz)ol&!5 zRExSar!x`C=4g4ef=0)<4GTCBdudlf`1(=tX)<vW=B1Xd+79eL4WLb+Ttgurgog8< z`NtYw<3d_<7nK&52#D<PnHHxJ=bF>t|KY%X&@4CH1Zd4NcE+F8O0@XDtYP9d3cfMa z!dD^?6Zz?IQ^}u9VDg?{1*>o1ZYnZrH4xo|rEa)OiVO<5q|7m;ZD>eoyP1+GCgZSx zyF)lEM_#NT{NM!;;-HYUOJU|O?{&fSFEWN1!qI&J4B0Ob@WH0KO}*!xNNpNU&F5h> zbBPNcbaSE1FoR>@9Oi;M3}#B4P@*6ZVv|k<%}q}T)Zv26az&i5mG(I>YyY91L1U>> z4~{nBD$4Ys6&wB*zcm=IpfuD@L<CbwEfi0l_aka+#a2mfAsosn3KWeqWcV!s{aCUQ zxk6SA+O&EPhMSi;pdy#K=e(JjP|-o&I-we`CFN)T*XJE0g~l7UJ09%jMFV2~P3*RT z@=_`&wJjK%0A$(#GuS1<&)ryCX=}wKI-Cf#3H{9Ou)2koTAj?SB3eC!=BH5L2im~P zj#0G*SE~LwS@!_T_lbl?qMG0ZH+jAP!vN3RK~=*kK6*rVB7q4_UNPYEPnw=~#P4s^ zb}|$LRuweKe|**^1Qbg}L0~T0g&G_In-L#qu_=w%T(lG5P=j$3HqS*@RxO_6)Fyin zk9eL&g(G#1`NE01e`DAA5Ni+CWS%6o#Ne-kO>0a|L0oe)ppy}h=~8K_;jxmfjTO&H zqGN42;1jFP1EIPjVdsqgaun%vtl5Q={m#JVmG-2wqp?3&1;%59h1O==<`qV9CQT3w z{*pbXBdBfb@~Yz`#F>VWX?(OIoRF_u(Q)PMqBhvX=y9W&MaP3eJMP&MY<hWju%W{5 z45T`#PF6>k!--?8MRxOQz!Cn2)0BG*45faL8e+aswU@U7;yp1aUyq@KI(u|f<y+hf zboLC*Z7Dfz<aa5o!vm{tqw@&RtP;%z*d5zZgMCB3R<4XbP^DjO{AJw(tHVRH^1`|t z*sYd>&2EfR79H}6>{V=^J-<F)ZWKE=*QHmn^pJe&fv8+Pa9aGF+#o$^%ng}(j?sCq zEj5`=HtHJt=bk@xEuLePW&JdM=*F77Dea19L=RFP=|8ag7ptF!y=voxyxyI$|E^XV zj`3Wdd(CHnv~j%JXUSZ{{T**){QhlQLo9PwXm--{Lf<P(r>n;*9hKX+uN<E@XX)0j zyrx#=DSKJIUio)G)V(o%hI+5+>{Poy=H}^uq}`celXMhOM;9(WH%~7%&`N%OpYnZ_ zOUc`0>)?5dFCB`wb7WoohQQVGvh-zz9lQ72r+)Ny)uM$L(|p&SpItxp?#lct3$hFE zcWU42SdLp|{Emu{XY#H0U*@lV<(rsLwz8n&uipywwyj!nGveK!w>CcgGbw#XY4OwZ z0e5DEJt)1ByY7U1=GA}AGOkJAI&n+ahzYBnm%j4K{IRiM=bG=8>6ZU0UhVZX^?ZNl zpRX)=?wzr*=Euy9HENf3#VhPe{-`|HJ7m&xck7AO#lt36&vIIutJaIY<ufLAkTUAR z6lwL!wd!7xHKjwn>bI{+{@|ZAvUtve#_ZHl%InVN-iC+d-vGbV7tE|Y*Ugz?H0NUS zN|$NV*VeC(i7tA(Q&p*7F>0ISfpq_{ti1T$ne*#<ZAyJ}pJCUzcraO}pN{9bcqiv+ zI$p=R)g_#Z`~9t}jrG@M_8Yn+2ilCc@$M=ebWe3E(Y0vco`LEu?^In~V(3Ghjhyym z#iZI@T<!kW&&F`IU&ia6tz|C}xwEf&y$i`Ym(twLBvko@uYYq~ee$oFRV5A=r<Ep# zO~M~j*{b&MpkIxnl4gP_0y79?y<nQoto~9tP9|)20a%sT1FQ^{Tf$81CpcV|_Du}4 zrzt#uRzzm(BBC%Rnyo4BB9D!%sErRt1*u=vbnct79GtwD#59meX(DF1l(NIP^9keB z6ve6mLbMJ`N1P!qm8oA^t|%uVWA1&za>J`i04+{w03KL=q{w_`kHRtp&XwbhE}V>4 zI($ejYKd^hu?>dX2d(R{q5?X!*{pw34XTzj1q3o>>s)Y|O;E2OD>XIBXcC^pz@Bhj zIl!(NPkk;x@r)a5ZNU~q)@W7$yd%`Vf?tG+I#DD^-CF5QPJeT<a|~+90%G{K(2<Kr z;xy8kz?n_bnXpH^2ygi@ob{jQB@SJvG!w2K^d#iGAh>b!l$B=^78xGQBLD<&@K5yM zV%Y?*M?py|$(sY9JM~e4`IxH5ics-y3`s`#u3J(n4w*du5Ll;&{UTTuDGniM<Z(R# zKoH4e#RdNbAVRZ?R;>NnhG;6l*l&;75@?kl-kx44&g8x0QNKZ-wMrXGxOGZtI@;v9 zIKd%h1}4+ggf6o}X+%{V9hX2~LJ(W>2R+&dr{G2^IHvC0xgNwStR%=PIT$*zwjS>K z)QW>Ca`YSH;X_`IE9hP#it%=|_$JVkgtf(Gc}77eYg*ce)vCI;OS+B%%fdIUp1d-F z48|Cys0cJ6tVvkVOD94BpYs7>6M|^igL>2g-fYZPkdx3Qmi4q}-C}V>8&sfb>Kn9* zLOqtE!V{=924OhEe>{K{Ku`w}x_}^0Stb16G8!g?(uApnSRNP82(N@&CF2ul2o<TB z^ab#WKTi*ZUTS2T{u9n==~x9U^e0C1no*P}q=~G=4sBLt0Uy;=vkWvOFWhqy99FIA z$v-^?tF=i<!)!t#FABvB?^WlG#rcI}QLo?w513RgW3>F>6{eA3D$J9pTfoGy%2)Va zh`7L6ATBaM$=RGqr4EfBA-{pjjOiTOAK}vrP0?mD=W{9Oi_uj_Vy78Fc2&EBmXqH( z8dEJNjf_T@^U)D-SX;scJpgusNM?vm`Xa0Ks!?^6_DmdI0z!M1V@J?6ZA>?XdusJ) zg?qg9xrUhM(8<0~;WAU_Pm<W7!K__XLyw;)>%<wjf}?iDn$Fk9@O}Jgh^e*1P-gq* zQ`^gGU6Q|?ru<gA$6&mHeR7urEv6|~vJWoFyR&VFW^JwiHtucof%2<WgS%JWu-ZE> zr{~wotMt+LQ_j-?zP|MiJ8F)Eby9g19P-NTRXp`jRqlZK^}R3W%$(bpBR4u2>vc)b z-)OUr+Q+F(z4AeB`(DMav2q=C=+r~4prj3j7aDD}cWCSU(4TXzSe+Y#atXawm8Huv zclm`G-+B@fqMH(grFz>JnjIacqnk3XZ~N?9H@9y+mtwfF@AmD+`19Srjdd344(%I$ zb;9<^wI_Z0ZM}2Pa9+yR*SE4tG9As{zDoM*N2{C*&yFv$lB)`pKmRzuSo&-6cW>uC z4Y^fwL6uXdNVr;YICzJ&;zt|f%XvGlncc3rP<CWl?lGMy5#>KFj$hZd&@^M(@l*2R zsE@a-Uitp`EqEz6`)sG^w>wsJon@TW)$6Z22B8V18w>RkL)&4XbPH`^*X?xQzdB7E zT>D~hqq@iG=QH)rO|0H$Jz!-aYDR9S`<+VZs>~WWu)54*VztzFZSKjv^Qu&S=Mn}f z^MO&tBPUkNfl^2Hrv4RHzDmDQ{Zen?rC!B8JB{kXJrC<eWkuE;SXq|q0hF3$^v8Bj zwO-VZku~Xoxy}!=XN^+USa#W3ZJzSAa(nul{I=2QflvM2?^#N}8LjH#;2T&!Hag$g z++o-SLaVJmMJ(>^d3fGq*P>xrThw#5W*Jw3r4n0LZmhO_^ZVN_Us(Ac#7}n{Ya9Cw zyE7GCr*`$W|5&-P>X^>&imuXux$Uyr<t)`db(m4r)UL7zE*s{LD>GbOfPra}E^P>( zTD&=s6A~G7uy34=PiGL2#I((NFw-&Rx5`ujrCQ5K<C3i<gON6;X`>X`l3$U=#Q}>^ z75R#UQgN2X9pk9F!Gsf-X}vit#;X`iv<OH82LZZVpg#$=BeNxOCLBy`rjtBH8kc3y zpisbG21+~~Qv9yNfTYA3n+ETBtTchcc3d@OH3-~MBxMTkP13bUk#eC{X)2aEGiRJ4 zM9uV2xges9AI;cPPt$`;EHV`j;V?y|1<fQcb`H1m<jqNpnTT54qY=YEDgx$cRaNi{ zlb)jy!)|kBOU#UEox`0!+${41fiLW4wHQrn5~?X6nZ_l>--LUG_!@bVtGSLw2lC4^ znM!mO+X>fTphNl<+d)%w1ffabl(L0(gcz7O#b=NQ)r#=Y1Dz(&T#TtCdAu}%S16D^ z!`h!Q#fEEYY#kp1f+nB{h)1JKL5MOST`?4l=Fn3Ql*f@vQbcAS_!0&mi9Yl<vnWw! zNl|<OGl*W$@Ztw{8z`N`ze2pzT2KdmXTAzQa_hKMMYqfE8UZU>ibu>@{ev>44N^>& zqTXsE8{(J6geZKSLa{BaWkk{%ldmdjiGE1XYsJ1ERt6iyWTi^6`)wCw@bG;wF5=?g zdWE7HK$2odiy<ZpJw{lQG=`6wb)2cnRWK8qmWR};MWxH5V1oIMY`p*#icuvPX|}#l zM2iMLG%nNo^fC1PW<ZnzL;^R_M7IUr{X#JTAVg>)i_%gI14oFUgk=vMP|83NG8|kW z_EjT7GN2`+n^}{fH&&a<^d2pJNfHF~Auwv5QPU*OIF<Nlt4vLzmX?{RAt%mMeuOEK zrJwibfM!M(Bqu~6Zw78@N~CF9qwnbv*r9ATjrGVm%$P(!9yCL%TM!eJH|l`G${e(1 zE!5P4g8WE6WBwtX1lDBJp+bX9NF?}>CKC-+zz@=75aB?4*bs7bhHM%%kTaDCQ8qsh zFwg^tR)_#LZ9$9b=z<osASl0cD^=&MO>hF-#-QbujTIXl&Leil79;YTuo+zD)W)=i zL6x5;1TLE9x$3+#n5+L8HV>7l^0TWp1ld*85=fbfN*9dIqZv@U2%eZc#^I^Af(Y$f zMJn{IHbAs+VyD!(gNuGI9<0FdT)&GyRD|c)dHzrlVo<&ndQ_4Lh-?UkJ%8{zKyuW! zQ2mZzD9<mlzQ_sDFW+P^enc_B7DOwv!EwLGkCuKb-D1}NqMhd%uhWwIMt<dY?YhOi zl_twlbEcOhmu}LRJRRVgBO4jkC1C1-4q3%chdz3t{rgYYDLv5PC)vn#)mH59UCB}E zn7nn>MpHcV!i=W)UOuo%9h0%H+RVXoSeVt6=f2VdSFJK6z^_=Z4Ys;H{2FrSwRbz% zqDx#4CpU|f2RVMbJK(2XP{z%@@)G9`SoODk=B`=Zs~>0RTU@ZnsO$}-DhP~;QjWFA zQ;xN4c(1O#Ztq*QD5#u1jlX>1x_$48Qxh^R-C7hTp8NUPv$GdooBkSc?ML<K4rOgt zc~8qbW$b(H$NY|=6-V~xUK<$y#Cyu^+5QXrerq`^JlCwX&jDqFdg!xny-ns#S{HWS z<9KADo^p8B)ZK}eS9@I<TK{cv^y+%k6LSCZS=HC>oWF6zbV%XU?Vi7#y)ohA*43}P zMgXYFmi8)kPc?c|=WUZ>86`Q;sP?pfK4X`|bFa+Enz9aI)4)_ceaqB&ht|l?9rB(& zx3S=sw@u%$sBJ^k6%Nl8_~ZQuBGi5N=UKj&SC*;UMb;D#i^x6UUD<cbe52$Y117(^ zvFj&y>#!5b0i)Fmtk+fdn4%ap!0y$JSJ}%Pb0(!{r&yi5UKKoGVc*TKvfTsgwhx#E zjFMKn)>w8J8FwZ=Y*$UvC50qK9d6y-@qy84=^SaXaY9DYsW-p>`%Oh$MTW=xpXOgW z3#M8WD;>CN>z<C2>Q2{ZuU@%2QKx@L{hZVF2UmZ)dJDE&V*DVmXzH+IJ?&+i)%SDk zy<W%sJ{{DQi>7%wOASu#K@Z~f_ycn4*b=+@<=D#}8=T|AruBYlk4JQNDc#?B>RnF_ zMUi@S*$up82l=U)^pq-FRPh4HRV!q=((b-=q&bGOP?tusa$p*g0SL&XYJbJS5@&Ol zlt?IAumIUgTzynPCSVt``BLh_kx1Rp9Jp|`3MnA*u(Z<@+z$x6%M~f~v3-%ow5e=J zO>)$5vMG4HpJ_yJ0U3vJ^KE}$A;z^HmL6XWOhglU`EyZ9t_?auEJ{GF4yYC&-AbFI z*xIUawLWN!LB?su9E!-kWHd(gl^lw&hiHsmry?D3a)C&M2t6Y8U>|CT(Uh%<XLO_y zy%+>h<9e+bw2`lbID#VzkG_k{(}YcFT&*I%j_F;jjTevtaEG#2hJQ`8)eM!$U*xVE z(G8wYkkXj=#C)pTbfztPCNV3H*mp%`r~@8dq$q*{!9QFNNeUvAEl>krFI(vc<(>S? z>e-DoE=xN_k3;A|aO1Gv55!X;JBW^CaV%YhG!oXNroQ>?;#m7Rn=SF2jgUL=2$_Gv zE8;iCbgVS8jb<bcD*)6>@ziMfO6X%naVGK}ot^MCA|gdVi2h@Q92#AUxDMY$S|nPR zA>{;k+CU3u)1n4MdANP46yK&GHSxA?5b98b$?=XZ@cCzRhr!e>!xojB6bEy_s?e<4 z2EOJNLa#H%JxnYE=;6AWv>CfMO`cxN+2ePFix7{(h`fp<S*x=-+{7d%ZAGM9gvAY* z?Z~#Nh(Ti5`sY_JP>a6#&FAYa1xVpDRf^+LQ~I9VJ7(L_`yLI=mioB@vlLtiYUauH z(A6~8C%$2HLD8XOH7&B{Moc0Fi7f(6KQT(E!O~U0fu*D*f!mslIufVYx{#nCR}T#Y ziB+1naIZc{g=wz{K#~v`rMW1j=}XH4T3Xzs4LAbMd<6{AzA<e&0;&k69}y2%jhcvu zK^L7|&PWPzD}0-bd>HnDUqpZs^ZrdvVI<ZeTFRs>G(5v?LRaE70lbw7f?a?&o;hpU zz!z99+W-~>8J)%LESD_5zBIHGK7S1SRr;W|cN<fJGNwBn5BeP{7%qdDd=hNU{%6Nl zY?#(j+J^5{y1|h1OND@S9Gk%)s7_5*Ady%`M@V}FQ*Z^(!>~Koz;r8s5$RTQASP`H zIvo_+qkJ;f9wwT~5{3^DZy8*S0vpAcj5nD!#&j|rO~XJU8ji!T3*@IsL8q1OpexhK zC9y<Ic9lO=m2|6}th1-5s{PdV?vDa$9d-8fs8O|_23g8JxtlaZCDlpIajy-)L8&^K zURi4S;(*2Tr9h~7S%z2Mo$@^w<0bX+X6OdbkV!}7bf`)lZ}ii2X@FVw<U>_C1Ee{! zjIg-OIYyhD2e`(5L>Kvgx0wSuDrc#BeOT7AjNvgUwR=5n&JRy<`=Zjhz$kumOh%<M z4ga3&TeKe9QxDhSCu*uAo!Vy}+7J2Zb?yz5!Sh__NrN_lnesR@Jpd*B{y>?MVY%J$ z!k!CB7f!CwbH8D@M4mf3I)2vIW%B!azk9D(a3DNdmF+NVbIw^G{er$*s(!DIJXn3p z&0}+cea$hWLEanv-@EyRt2a3oOkTJ-ZDM+Rv%gK`F^^_f_uj79mKz=T*CG>Hzofrz z1fN^GaIyED5_PZcZ}TOt@3Or|zZm-T{DNQf7W++^-tg0nG9&M<bGLi;T&a$`F0Z;? zElDr5+iPE?^7<*kC}*U1A;41R`ziP6Ui<4=UY8QA@`tUf&K()1aC&-JuS<QHYspac z>nVzzQvgiSrE}b$g?o;92#x7$<@J^I?RLP&GcV9{eHVQo@ad$7*{N3dAT(8(*H~>! z&wUZ!!yvfN-tO5R^RttU8VnpSDJ}%OqEEMtp3<kB-A3VKrSlB@Fk<Xr?ptMK=Gnpf zC{XFTYqe{(EJ>Chm#LfUY2j%Uf4+aj9+gGDB33znPLBOGd5SzWYPFer)dBTDhn8DO zCpra2D(JhXuj*W4t5Zt%YCp^ImP~D`I#5>M0$;G{uw%P6t2(>4RdsfWOVpub+Sa>Q zTW7q+@LhN2?WM|QW6A;ev&#ALZ~&8gTl6Is(orisf0P}vMuV~y=r9Yyg5w5nubZ+p zSE1aiyO3g(ine9@tEO|kiHT5*j#kJvXK$3fct=ze5Z9L?QsGdc#(Ay6o82#?1SN|> zp$vgcmE`cDL{Si)V8WGT9{~%A!jZ3h7*#=H1dT1$v)mJrj|fHN)R8K~!AW|C?7b!d ziY|io5VcIe5+hckt%sL+Ed{<s!XbU-10V=sqaAe;8hZWBOglQKx%0=8TU>k5)~J}j zBp`q`kC8VAz2zBER})fkor!ybx|c}-YG4h<@<2D7;68^i0kKFd!^;s5ZOn2y;5bT8 zGx4cLP?8wqupaavQh_hzL};{@4t43GzsYu!Q+j8lxOx%G#baV|F(9HGJZHS{lL3y{ z&Wk1neDNhB8F%5$Oo|jil^biRkDjr3ffGD1KqHY$Jb<VUsVY1Ld(-2ZNRgBBL}Bt2 z3K(fSfJ~AT%k@A-AcG%(J@`E`91}uaO!29Wy4E_Iz8oPzR3ZSHjAR)OV#uZI!U3d( zv+KbXJ-bn43<43=D^d<0?KkKOzSN^1yvD-oyhR0(7EYvxgY3j^Qpk>Tk4>x^1bMM; zX(V&;W@Kpd3Mv|jmSgDiuj`J6|J*Z-X-c5el^L&*WW{|&)|<mXw}U`UjEewcMQt`( z6fq<VW{k+Z*`_WWNW(+nf>GG;H~N-E`MfLp<$f;p(syC4VLgPusrv<@)aQh_dP{%| zaR?V!nCXT{4RK4e&=M0>kb-BDQ<L07oh|TMB~ZeZIN*p&3jw%psRTEWXUMH!T7g}T z38IzOg$Z}YCh8V_PA<R*@y>`w0CZY{62GUWn-N_*=rRI@@i;oG%VcIFyS$JwXSb)( zdvFd{m;|PSd~{w6n=_T{6|o!u$+`n6Obn2O7(TnFg3%q=ngSI20?;6{F0d2NaJ_P@ z;boiD(Un9rCLfV0hYdVCv>;~1^&;ZA#T`5rUUxt+in8x`>=M$6oFiHg+JKNiLvZQL zb&m(#4_ZpB)N_6DaKm4vj~Y4wUiKZ0GXWS8lTm<*)Fwl$JM3OmvJFSZnK<=~>p(Qb zGE&kurgK+qJ%eCWE9gPBy+)q`MA?!_*Q4B#Xb8-dm6SMSG*gafj*y|hPVFdblhp>Q z5Xfje%_or2X`J~d5NJYo+AShb&s5AZt)u%RqMntC7z1kq``9k<@$MVh#t%{1$L>zn zQQ62c+RKc*CiIyQYvdJyVS=7MC9!JHY9nuHtn5hWn7E7aY*Xcxx2N3S%o3v+UOC>j zc`EZhuG?i9EjsvB^ng~hD>%YU-(pimK*<6xcxv$1Dth>Z8O0I$>`w`@JS)p_Zb^e~ z!;cwNn+)b~R5-R+R?#YGQ^hW~;V0D9E>3o|?K*Fk&Fai;U%GMdIbrQ!@3r|*_N~gA zben~z&z0XW+^H{rpr_E6rxgxg^mg<i6FZ|jmNL`o#YPX4-z0g>h$xt>+~ciepX4*Q zR%dUQZLL1Ged*OfQ^I4H53R_%po|O1yRdL);9vbM?dtnS_1%15ay=#X!sCK9w^N^Y z*zEeMy3fPL{B0H4Kc`mzDqT?McwmP`m^AQH?ySI1>OGfczNuXur|zTk)6EDl4*p^2 zv*#DPczaXd`n=eW@{HJz-a$hPF1o(VaxdS>Xeeul_bQ#z1LjBdI^B%kzw)U=#r|al zTg#t@+fR6yJ=1tn#R2+Q7jCyvWmo5O*Ql4Y#@uSCd)g(B!`?Tf+jbs}`gv=W#LR0^ zeAv$P`T1T~)6I4njM<rg7$fTBq5!Y?nP#A#?K_J+Ej^8NK|KCJQSoW9>SQm~Xq7_Z zDv@UdV(A4pV>uQ_sLtstiI1r4P`$ILqFCvW6CY7AyZVQsGsRMeobHb*HfQN&#%Jw+ zk@PzlW@L9qH`Kp<3;1aP+Of_60A;n!ZY|rK!{njymbO@*0g-Lzcc2r9OEjDWZn6bO z!IB$x8e-DmirOqd&Fr8RUizZp=8i;@dysD`a!v=--GWxgApdN1=gVS^h)c5Ulf6Mj zdJd^WgR2hY0C3h<Y<x+L9-#a9L0&ondZGNdU)5|V6O>)L>e#stgdc-n%7|@{UE=*5 zN>p<g0O9RV+@tZ^SR~vSHGMpo)DgWRN@yXXrh|kac?AoblMlwY2XQ72H6);DvPuFY z#Y6KUxycXFC&ArnUaZFi9KMH;h1J6GEL3d-L?(_qEI3XAOY?KF^M8jI1e`#P+Ld(x zEy5YD`!pjJEVIa7vz*p=9trYH2|9E^p<w!t)(x`olqf=7=MzzYX)PqFolv40G*%hc za7e1ch2>4IV3TqLG{F~0FhZDU8pPvKqybSpiY-D!ogE-#p(8^w;8vJLxSb|U!4z0z z2NN*Gisj6yCl|yh-8;;f;->>MXqI+F6e_IDh%6J7A*yL(9Zt!);{8lX#p1DSt`l*6 zglgH)D=Q$XLaR>};E3+SVQiuWv)=$V1P??sP;#iUkAV({EieRbmEBmM%!+F~ZQf+b zu@$2czRqAVd5!EuYb9Z&$pO?X_8-&Q96~tX0DJnVz@A@1KT12>sRDY~CV-5Lfz~s6 zLSu$3>}btGN9_W3(i+@7X&r2UR0{8W&*+GO6}KOoK2!N0ThYmIf0tfVW9RcO=kHOZ z)BtRLV8YMb4J7ywr%)AM^QH_6KXg2xV!ev%%nq_*UACB<(~<Cr+A)xL0}?@PU3S`o zV{z#J<wN^4FM4K$vHHGa`+dYEt{*UiY7$Ehd2lg>%skwPmShA?h20UO3zjJ7Hz?Rx zqP8R;nkWo$9f)`YY7bZ=NyStrk#`UP67U9vasUc}?<i07nLDP<IjmurXo@vckw8G~ zSqNsZ!DCRc$>5}E)T4rN!R$(+fQ1KRN)}v27HWDA%?2BWBq#|`gkAm5;@9+E03KSf zk-=3sgCTbGGud-|<KQiF(hA%zv?MHAUO_aZ`gI!cg|m(BpI}GQe8_Thm-wa5*$}i8 z>QK*2t|HwJvPGT<U~>Stgr%unVonw9_dElErlGw?+A*E$2MP*j6trlIKIuXC@n?e0 zBP|LNhn0R?Lxy(LrXXt*`k#F)=|e<85P}>R&!4k4=RQNCE|Vw3h69OORaPteN8P#b zMb@SqJxP7>?$}+)eTjX%8*}uG#|<6Fs3tW>W+Y$iC`&pI#K8v=hRkrBG$-QQ7Vd8I zB*_!T4lqP2abarM7ZQujyDT={w5acL3e?j#$nug^_%PF;jO!_O3!_zbJ6i>1T!T4w zKgT^|eTrQmU}x1^WkL+#=ZB!o6E(#h0Xi7~o#7`+t2;W`yA6-4?7T{^zV9%y&N7o0 zUO4Akv}t(C1Z8KVE(^~U8XpNXaZcA$8Wr}=9dq-G+t22tO^?Vs@12fM!+!a`lOiJD zQJLo*VD&ipP49piQPoLTy`mZ4y!*4l<btw1Acy`c2|%{U>`p+QzB)GLP@jUJp}!t* zcix%fx_6<|_AA~2(q)h5-Ap$(ny>aWP?pC}onKHNYGdWysYIrh#^)G$JIjvGF~0_$ ziMLS~ZF{be8OURe5BK=0uF8DAG=GRZZkzWbY5k_3Z+V$#NDJzoE6fahmK7v{aDX(n zb<Y{o+%va2V5T7)e40muW9EHxnsVFDAET~51k^ZQ^66tVTzbQNT-4=7@%^~4<2`g` zdFCb8`MER_n6a==d>=_vaq!M`|9su;UYAv1ouCBr%KBmz1aM7S(FH~EPzSR^iaCnI z(0THmuDj;pXCA;NS7zc=AWssuEo8>D5-2UNDU&#@&mY$|3#*fRWhi314U=uo!g$s) z?@C=5V>{YL<6X6FBd45<2P1T5gNeW}jEUNk`a?30%eK)<3TwMpj~x-W8$2-yqjUY7 z?GfzWDBDOtbC;Q1gg$;1o6#tBa}LmFg=`~*iC}I?`!a9JZ5!pSnT|su503<Kdb!rw zxWhT9J-sbNvN<B9p=4ECNHW~R;-Mg9fRxrk)|(g0F``*auT%&?h;D14jR-K1jkui! zg(cDA6toJqQBGK(r4b>3L^!}h+*;F6W*Z2=bs(S>v4o(uOeEA0YwwVU5<DWJ2b!%J z?C1(s81uvcRkzbEt}zLQFAq)kB+MpwK)4KxXrB?7ir)Y_eUd1{ZL=_jN16dnU%Y1m z(F?!IX95qCvcwx@w?Qbud5Ww#AvaAN;45dz-bsQQBtR5GUPJ<je6#zA7^#m(VbO2X zpg0zNq7XGXa$?yW6RDUdW*W%cByy;zcPW=_Qv4V|h+XR;pyZh_3n!b`lCjuSHtT($ z9aZv`_o5}KVe5cXgn~CM1c5B1sXfClf-g3-#e-BNF~rR^9}^~5iIMN7xDBG+8tQ3< zE@3r>ErkimjuM3xzzu{G)^(H&F9s8aY|)|JF1C5NUr0tx{RDXUTa#GAT0bn$&f4G8 zuRzdnpaf|wE=(=*TEuMf=3;opo+{^HCQ@n&{Rdppg%(a8uZ<Hhis2iVg;J!7FLVR= zGD5AlohKRP`&EO^Bnr534&6?D^v<R0qEo4cafkxw<v-kzG#8KyuO?&K4)e0Gw+$7U z5!T$1JxE9pMHCJyASTR7+6iTYc(?l`Tw*Ruaf5n%y4?|QW*hbj{Rj@xJD=6!i49B1 zK*M>2N!S6laxkVg2*f-5GtV9oP^nn{yNRqAYzSp=BpzwCC^&|jzGm2pLO+mOGzbJc zkW?Z8j{aG!(O7Kae8?!Z(#ivg))!Z8I22Kgi99etqv^$hL4YCAN^6Cb_<pAT2+z<; zJ931h<2q0~0=l8+Sr67@roL?;`^0td8Nq}a9A02L2kGg`SIpH4kl1D+v%^k!kP5*D z$IVtCl!QVxpbo4rWQuCo$z)#HRo$6t4*>_~w2HqJ(i_4JL!m?vi!E1n3@*-AxFh_- zBpf;*6@OG0w~(?^^e1<&I)Q1X5!XDj2P5%epbHH*2|ffm<au?mZ&i7Q{#P}j8z6~9 zo~a#4v+3lWr3U9XD7Fk8VP>g_m8a%T^Ue-25A6-E@uVG>E?z39MUJO>pZ`h~@M!*{ z!G5yZjn2N(`Qd#shVMKWZ|me&5fB4{NeSz4u!mD1468?b?eg00vgqLkz}e{3Ssz=& zkJWog24f%6K7N))x*TdcgKv7qY^rotSyU|iIoF-&#Z6*ycGk?G1PrrHZ)|Q(3c8R~ z{qSaTn!Ve^F|IFV7mP1uzxX-AMYi(1Z}k4?yeWRWZ1z}<oFX5pepQ|HG-bh$Tkv6? z`g--&rwI#6w)iJqogP)~d(}7UrbX<FIk%PO@}ZV;`s?bjHD1FMQB{8^^8&K${a#Nw zV&|V>aXT?$vgN3Iiqn7mGApY5!%mQl$_yk^8g%hZj%#_mQC^Nhrt*$AKH9^kL#VmG zG#4C`<DDUWy6NZoP;d;mCTbf#6W6%@5^L06r|@EYYt^zd3;c$=FUuZa^bu$?vwQN* z_Hi>I*_^0zFI^*lm0U?5hf7O=HaA`+U+)u_j8DfP<;V}ko(S+HC+nfXWO!HoF8Dht zwhJmwY*B!>fA($VuO^OHo^z6^@>f=xjLr|tP-c1?yBf=rgTfa&4D}YUCh0S*0m=~G zw85g}Rgu7&%=nzkr1kX7um$>vSkn?Ki|@&|$d|<`C%3`E=jVeuR7=<)4pVVhj+1H# zbQC9S?!8>v0=kPTXhPcQ`O>~|eYcEPbw&>-XF?#Lj3-fz=Z5T1u!qhAS44m&LkV)* zw$z|)qGdNilaQSorJW~ZhjEX~(#|chdNdnEF1pF58VyqDF&92c+FiylqKSpY3`4QJ zA>#_NrP@Nwv28xYxdd}fV)_nMnQ>n#2`Ugz1aYT|)sTsn6(kiAbeKFen;Tusp(5>O zf8PKt;-N?nD;lF<P)m|hgtC0R)yX_c>f8di_%#%T05KEIirGK#`7{9?ZCb&x%@i3N zOG1*sFL)N#F_WYafCBdLSP@FgpiTf8SR_f*YzS;{1EktOS89@zC^RF6c>*XW1oeSf zBb3=mA|f#o0x0nPG%>I1Vk(r@J@H%N6T-}5fJ5<LKmb!&U_fa?N5D@8V)%lnK_y<a zyeE`U=6*1b`VK)ifu;d-jR`Xd^|&Dm-x6$yTy(b*NGQ}?-JI+r=woCh1yD!!!DR5U zf-{uOb7h2?VPF*%TRR5^6r`0R+&M*dLS1;=#h90b8FS-_rN2Q^e0@U1t(*KEz>$C? zXcL-ZZkuO{?658V?;uu{F?WmWIz0A6s3{cb!`;lztf*~b3-Y*-Ez+z3ZJ5#0r758- zc1F@DF?OUuv718W9Ig37#d5?-Vj>7s6GP!3*my#Bb{T}5oe_rAe~D;@m6uWfCECEV zFuRS(KkN%AYJq=6g}Bn8pBPDezhd7RWMI%!ooP16LX%<wk%nb<03_fR2O<b+s|n@i zA%e>ew7j7S&;jNaCkJsUX#q;E^SCod4*pJ`8|5x)LA<z2P=OvK@M13t=|B|{%kO!j zWxKdiG+n33d7?8oel*3OxdkN{WUPLx3C4(kw3Qex)*${&oFfV*1a4eHab)fku0U3i zCJ3$J8zL})D;~g%(l}U}D`++#LhWb0LFrOV(E)z7qP(-H)&M+MIT<Fz!RuuYQrl>V z%#aB<NaT=`vmHv#@8VTc+h}EjM3HC%fs5zSN<5Iy@P}h758)d_#(DHLcv7u6^whWm zX2O}FWe5dlzpTXi?AXd5D%WSV^bGOa+>!{#P~l^6F+g$}@gH_%$EmG|g%U0@!oem* zZ|rSV3|c(PN!TH1IY9bM6XFmAF*Sz|r!w+6a8VR_?l&Es+VjB0tKg)S_}}V$7*m*# z&}fLT{T8FvCIl>F<QYUcr&=8eF%RjRJGHfL(WV=+<d$f~+j)*8e4~X-=3||S)eoe0 zLB^?`eeF{0ot@l5r~3QKf-*NcEll8CV^Q-k$2|yU)U}|@V`?u+ON-4vAjPaF4c|XJ zCCJU<W}E48F`H9@oHJ7zl;uP+7-XCJnSGaL_I>>n;*7=FsTP&9+=BWJo>goyH*J#V z;KH$so~9wL(%xM)HU5{OH}`LQnA^R2S#Ep3*ET6_w$`t#KM^*^IAuz)?V$m__TK3^ z4+~ZeJl}S@z2^b-MddQfUxuyG9j5hZ^_%(lq>p{`EjPv1Ur+krGej*dUKTROU0SsN z+3IDP3#9S#$@zWc>dVD9+Ybz%kX!*l#wOQpvbw?~?97zl3CXVwd}5959MrE(!tD5G z+d7{|&}L?iiDkgjj)29=XY%~8Gyc7#;T45eUZ(LU<}br1#kQRVrCz4R_~ht6jy{=r zxyBdKr?HA{3G9;^EaSz1#lZ0jSjLf9CV?EOVztOJl_p~niezx44nvelfEaV#soE)z z#FzL?GjgHyxC?crSm_wy5CR8kHqaz6BQV1UDhyX;NTK-$tYOR&lkduyrFe)AoUAbl zJGfbrZh8=OKtgI)3`>Y`R6&`t*!BuLqq&j{@8Po8UKR`V^mQwWUU;8F0y-vtxMcID zWL4X=T2}RyXaUy?y^-dOM=5=0kJi%8kYWt38iHx|R~#B^&^E4bBr5L_rNPTIl5-Bq zvU&nT=B}ayb5vh=Kj=;*q-oBr2i#mWw8%q+SE8WV#Pmf+AtDFOQB)L9nHz05VF?>; zIR|<SN2h~-A`yJG4_ILx+rSGNrV|o6%zbK0_4Z^#aXDzDfG0vXB+`svKjF=Z_dPTe z+%asY)~pRT**bh4F)KsdgL{Rlg#X^=<ig+Y#3usfh$r#+@D>+O0s>HUnb|r5<uHc@ zvQl1ixke+x$WRgwiv(ezGdN0%LE!!T%~-&mSjN5QAf}QCE4Ps2MP$>Ik!C1_v<bOO z6uc!pgL4r6qn|MVqAe`+!c>)#Oj!kVBCV2qV<r`#gCnoSXCOjS4ob{f&RB>tvwRF` z3d|q^ffW@oZ3ke6hh)q_VQ5A|Ld6+Vjo<<qV=k@eF%u>dcEdOnK!|?eRn8JcUxIk9 zJ5WdnT^~t%p(GCIqRBCW_Qgm>lV)bF6nQmNX$5fyL1}zI0*0r1SZqj!A~dl95${NV zv=1|cIHZaFfHshRa}~@39?~uOEK^MV!3Ez73KJPgLR>o7l)6e17&F0z8B9&J|8WRC zDHOy(&PX&jX+A>ShmWwSNt2;YmoT45w;?z)Y)R`Awu#09&1eE%_~PvQ(Tl0voIt{Z zQZfh;3wUyjv=F>t$2dxYf*`;k`obj@yyT%PJm3xybDtC(SD1lB1aQ8k;A|BbZxc8O z_)x{97hD$S3z7^|ScEJO1RMc(gg3ob$QieRV*WJNmy(Gqg37{f7l~dHGgxREp<+#i z74<eE<B6bzp#pm%!8!Xca-lMQChIU|MnIU)IOSW+Cz?|v=inRS)I{eX>LOf<Sca#Q zS@ej5&nZ!wVS<WqEm5q|I8MyD!bC}gYWsN<DJxhjY$JVihcuVDdl8tSqsDiDlLQ1q zQ*zJss*uH_JNS8?sUWU7C9$hKMKTK_%7%({5<4=apyVvC`Bs;iR7X=WzI*2*3lk1D zixTzMdlJ~R$)QbIc-Drgf=bh7e1~u8(9uv-2zO9`wHXo)lV%S0-;5Luj%_B#AYa^x z;SLMbG^sR>i|vuOVRB4KH_SId4$jF%>=@gm*x1N9+QiC9`Qg+8kF2fX)qqC<ch5v! z3o`EGY6}BA$hf`h@}5}6K(3Q4?^MxO(mC|<yw*;E83n7#m$wS)tQ&u2Lj3HjOn)g^ zU<QAw{r(htztE&>5M)3$(HWO*!6=>ek+bpF@2ro+O+klUCM`2}N#QsBb;RV$pv*X= zaB8cQo$OsL9=ci9ddH^q#bCvXLerv1`)gi*7!Avb@#!C3Z<uVfEL)Z-eG>ch`s7zt zb?ydJ<2UV4Y_RgerYn(6ns0QLv>@Kf$9l)C$PvUZb)Ncp!*<A{A`Jm6GdsI(E_t*= z5f%BR@afP_8!NMs`l^`u0qOR#Xh-8-2kI)4W!~z;`GL}6g+u;<p(po5edw9%RJ@MC z%9$x)fEN>=Sfjrqy&oy+Hbq|!HFSdPGAmZuPEi*Xeatlt+*18SvEfGP(4hrABvw^j zio<Rk2+MysG_!}Kw92%2>5Vk@$y{PqwWv5aA<aKO9Trmd6%VuOqX3wrQQIGyr9)_u z-&PJ+R6E@>H#&?1gA!mUd2LTO%LTXO9j@#HwZ*qweFf6XbS}LNIRwTbc)1bbs0OfH zP#lyeT|u@6z=ESX@NA9VW#A6wX+Sj)Syajpp0mNYwCXYGGuw5y;#jsF7bzR8fgKZA zQ2L4_K#<QE>0|?@&j48zvF&xiH@e}<0s@&JJ)n-!E{W5o2s<NLQMi&e^Y!&4SQ{!N zZtI~bmYi-b)W-GgP|<yw?X{IKqVNLF>&enIP({wY-U-@qD5ZCl&SsVpCbprh4MlPC zoH`>VQvth*>o9SB<s*1HhD4gP4bskxHRie^h68W`KWt?9q9w%e6Uh`Al;X~6)io9F z+SU_;Byy4HdbJE+C_Dpih(%<Od*<p2FU?{G&*?dDs9iJ(I!xK&x!z=!dud>0@lEEI zNID(P{sH3g5VaKwl4w<E)o6v3#WE~z1`&W5lf|V`SMcSD!i<ppNdWgipTOH%n|p|` zN`$3~p%tO$G9ADmN;4M|n&81vA8Mq8Ny&jALCOhF1@m&JpdhY)z?C7nfeAw@(vX-% z)B?;w&HqpY&Vi{Fi9OI!069p4oFO2Q2$%%DhbLiJV<3<Mu~Z3U2AUW2aGR>SskjOE zihG9T1TI@oHCp(HQ-K{+TSe>tVijMU1WO7uDCBM^SxiiVY9^Dhlv^RqX+L+JWSnVO z48{<v{Gp<p^b#ftQC>!)2~o~Pb#-v3idyow7*C88Wfuw+Gy3D|kP68ko>S(9?kMgO z<shDo=J$haFD<plB&YptRK#U%en8%ZI0CI61?LDiphuZt601OP6nZ8{j4LbD&{~vZ z1mCC|);Pw}#%b&65AK%D2cwE{iMVbueWq+uYdmSn7p#7agfD6X#QJ1A2DVN@&UVZ< zcYVJ8VX;APG`EIYKy9y?8X>zL(Tc({c>hymmbw6iFNM1#h#^*Rdf38v*lka;26vwb z5}a^2qBl&>adDydIBMQ0C<_PzC6N&XD59(l)E=JHWkDUR%*XRGX-)YRipB8!&3=l{ z5cdGCzzOv3#{@WmOB~=6@D$`9CK&M>0yv2>5q1mReK^N}DR9pW3HS!V7}I0~(TE%! zO)(VTV96a!bBu%1_zuF&<8Fag+E<`UiPS>7SaFpomoUU3=pnvfh(q&GEfpd!B-4N{ zptn4_6R3*>Gxn8io=Zcv%xtoyqcGJ5X`8PwN6EN8NWt(2u~oq#1IQ%MPF96Z4pz-N ziEU2FIEv^1OH@!>+NfH=FDlwi3XN?Rj&*~HL~x?}yU}9EDw0z;@`s8NQ+PhuKy>D) zeatloGp9V)6Vz<L1{-yWxdsX5cgbnx4E>9Nx=ouXI$w!DTZRzTAPNH*3c(R<5W_>q z=~FrfGL5qT){wr;o)XoV)%oK)gn?2X4eqT%GT&da(-emB)p?TWQ*OF4xmnVw6nh7Q zIg+UM85T0RPSP_I1|6$h4}>~T%Dib&`&CEh6niJPke~fqW(<$8TbK~q7eJGl@@UUx z+n~;EV{Ym>LuG-Dlwo<En8l)kGs|F$N-)bYql+2(nJJ!bmQTE61MS@`GE){_%^h-W zbL{GCK^Kj$X1};PxOkW}*~lViXGz9t3lAf&OCF$;O*>=}2GYGox;Z-!LNghT%`f=o z2yB*mUGjB$Yk2sK*CluT9QPYKHj0r4H)q;=U#q&fu>HWjlAhhFvXyNtjZ!W+y{U6L zxLM`tT~(!C*k|Z<)exUPdJ2bJqoAE8hQ}ec=nhll52<F%QrUh$(Ibyo<%vk23`OCP zo36u_+d1^<xj$C<EYjWTrYpo1hY=u^f>J=r^*#gKliffnxzWWP^Ot=7se7y&xP|Qt z?lYi!vIn>&cTsT<li)u6E;z`+E%}G5T%oR<n9rP|N&pNAFW3d)#jMJIq4&_hi+NW( z4hve#4Kri2%09}o@Q@U->R4Z3g|D$IWoC3Eo-wh7@9@J8GJg=0K{SSYMRG)7w8z)y zTSV;1r{k625|wf;kOpz#Zn4m5M6rcwFhPop%QAgqCkIyti-?RXGW{Vj5pjSM=eP_z z2V#^>B*C-?%g7`hs@diyuMAmtH?zti>`;q{-0fy&m<xw`mN>`GjaJ%8zRU_KKr_Gn z5q6Tz8#k!hCX=QB{HRT9%Mb>_NN*<32=QLI-nL1MYN~F5Hbj;gO!;2m%5W{Ug*+vi zqAL_0W=m0J6SI;;f}wqkP9X8)Y}iATwGj=T23w1AO>L9NASGZeI!jYng=I8Y?ga`8 z)o(+!5w0p^KLBS8HOS$?$>gCRGlN@&DDn9$NYP*qhY!d$fG?sC9<+gHLg1q5A4usL z?VQaKF7q(Mhh2yFH6$Kl9t>{_2>A#{FhPZs70w8NEzTa?l+xRR6BvsC8jwg~rVoFq zJJCX8^q>8#sSP=0cux<f)`x5r3rIgOk=n4u+gK?R2{+V_dS`^Z<!#Jnc#xh*lXhW% zgPY}v7;1I{SBY6WLK24F+C&gM2ZOJS_m?Jkpqs#{aRD26QU|GDmg!|82WvM7QHZz! zpu*IJkyu>=uX`9VLFh0D%Z0f{ttd0hVC4?dy8^9H?KI}W6|i(hEtM2uB{=XFg=~al z@Jpn}MzROhO4Lb^=V^bSsI9pxYvDtNQAKS`+n`YRKTX;S=mhk@yf9vfJrXrnSTqfV z<^d75EZ5Vbh)h4q2Q$)SW9*KYvcztVC_}=E#OYb+WQrwA5dWcP=*CN~SiQK&J2H37 zC&)g;d7OMuL!}#cE)?ZPj>aETpZq_3y$e{C_nGdk7>yw@RkJWk4qHgDEEKmWYEIon zaT!1`u)q^xuC0g$JfzVyhjw2xRU<~1Bn3r+s2L;+lz12qn9=$2U1MpmYGN9|*u?tv zYsg{JB$FAZ?RU*|cXz(u{rul|fob=?u9^6*_q<k8@B6v$`+5HVI;D|dN=Ml+;kEjS zEb|g&G~u(Utn#aIIu7`KMgoUOcnhYJdh1KAtxo=EZS6|(rVq;e@pwm!BWM_pM>_yr zXa;W7<U2<r-gxGe%c__PgN@>?`UaLee&RNq$njL5LqXY$`7(LDxQ@tzXoz?fwBgUq zo(_+DNRn|R$7ezPJK!s3?1-<pJnqD;q)eblHxd_5*pb{J&Q$63Y}-5O9bh@i$aotY zoGj&kGw7PQh{sdl7JDpa?0D0>2vUxb5+XJDJiJjoB;qsz%FIABLW<@SuFDGitKC7g z;yA9;PNFk?d!ZW&xp11)m9BTDh<%8tq{DyGAAwq(nVC3L&ePeFYrdp1IPa4)x506q zDt#(prXntEz*!zofqanh?b#Uqa5BOOrV=vBhqs$XVnWP|NzE`8_Ui-~)O^A#g&*z_ zeF?%t<Ozv|AeIcJS;^B@HeG&j+?f$3zsw(!aQoaRXAf-+bnMzwmy}c4a-x0<oP5Xe z`m?3^rlvG!h6`7Z%a7X;$?Ggm<v;SHKgfS}$SlmB)vp$h-4e;pS>5z>>WB%I(dlnL zDDsk+U3PN!EF%~@o(>MS9e~rwp2QJJN7Hr$rJVF6e$<{UOGxHWZeVlf7BrWii;mc? zeG5bTzg7Cf-kVG7CT_{U+H`qWTFJpHt+N*A{H{H@q<u$A-tLLF+`H@kyj@dEg2gGz z@9T}`YcqUg*?pH==CgT=+k0V0Ti(XBio+E@{QmBT5_hEyoj$dx^U>Dao%`DhFUPN1 zFukVk^PakgnsyarwY3&6$-Vcb;2rG;W+t~3huaVD{(tAs8J)hcZq@H3ne>c)cz<%u z_QIS~>q7_cmx6MdRLAAf>1EFxyk~XW)Q3Jw-g6}D%SHFBy0i3GQy<#j|LOCZmm6~q zep&br@Be*iH7d!=jpq-3iDvTmrQ5FXY3unL6qICBP<ErBe3<hqs0Q4`S5T4<NnF{z zY6gzaRUKM$s^W;)N@9D$hwME8NihlK+0y0di&vN##F47%RX_1uqN5=sn1r?j#dSAC zmPuz>cw|~AISyj*V4(9<RTD-J5tsAM=wWx7C`naAboRogkl8|0FK^95Wa+AM3JSrO z#z<9ZhodBoM`n7Iq!e}%_*xPRJft{Jlw_1`t}EG{H)lmvRP1E_r@>L93MPi@azYC( z=5K}1Og2t32TGG9G3K80=iBPSeYKJ2(mt7^sh@C{MdRjHeGpA<{CZH&3k6+wgTvBc zehXyZ8T6@$HDu!uf!hDGeHQEh8Rq_Bj?Fmf!$G|7{2U*z(1{mfnPN_p**pECYfvHX zzck3F2u@bP&GGda&oELW(+m9;(m=jqe$fy?*;g@*M5YkdjOQC!BR8-rj^jxqume!s z`7oN;Ovkh)vxvX+pRtlvOHo43v=xc9c>Li%d_J)f^FzdgV%a_0eH8s58Z3Sx1uGUV zaS{o*Zfj;4gV8IDNq8~**&cZ=o`zzA4&-XKD2}?ad5$~mSv0N<$qVOle=u8jSxMkl z_KG|ja-^})ZxP?^X{WFVG?QEk2LA`#UkStl%HG`K*~S{=+V~4jU?!o#i1S%^rn_mD zmT#y5uysQdV2HjLV?nEuS%Zu-4^GFg;*=H15SFvGi86pSKTE3#3fzhwb<qr-BE4eZ zC_S>cq;91<EQO27!qSAlIDQfnemt>?ej%T^@U<Z>RT8LOZ?xC2?fToLl*CDIGNoh( zWKKVjwF$vExCZxT<tv$PPK~sdQdva0mLCY7casb9>g8Kla|~Xi@08;Y0PN>A9kPL3 zkGHKnhKfTN2fp>*;LtcHzDxl*E4zNQzU)tfZCD@hDVEVi12rTitVk`NaB@O&Puv2r zL{?n~O}vQ^EJFdI`64672^{!4kd+XCuRFtB0BIzOp<*ze&cF`OI8m%Nrg3z@CDH}C zEMGAo)1rRsuL$rOPw?~??x5j#F1qV(p{$49O6^Yr@E@&ZyB{L)B#Z%J-oJ3y7%@Sl za8qj%-io_XT2ZRRUO`$A<Yj;k!~18o5;^g08~BXQ9#nibmXfjP3h(dO$5IFlLy|=o zVt4Y7Jt@10G)sY)i6b(EQf!y$ERL*X;{N<Pys>!wliE6Kx{OYX+dFjPjt|}`K0coW zZo!2$C>(b5lQ%f8<6j+H;gDzR*llDVp|BXmh-*D@7qnvN1L+UMH<-l2##0IDwVz~) z?R5M)?JkKTPZ5ZL#3Wf11x8a!;w4eB6)w!KcyI(<<*~TEW8~;m!lfz?u1`4@ZP{^R z{m7zF(&4=?E=3ew7_L1FV@D>rEr@BeIXb1eM|5OaPG#oiE2C@AV(m<PH9R&kdscM% z&x3(sJ0jU-y^Wo<aF+&XNm9#B(UK7}pd6p<jm!><ggl585|scFiAH88W=kD;J;&6M zoYkAOtEx4#w=CiQ(viId5A@P$R1r>CRdTSWwe*vn549)HX%D}aw`=0KdtbUg2da@P zs?i<IgQMhzTbJM00~fhrb7J_2_QFN73)Ay=)%<ww&I#G!BeQp<Eu8wD#QfbO^4j(n zhttb{KD&M!;)vvuE8$1?&!2M<f)dwMS5VOn6FE><c>dJXrbiQkAMU&SNw{v+En|-6 zoVscI<L4eNyPuDDmcH?&w2>vhxFz8pJe|{gx^lhleSNZH|L}`B72iJ>dbG6q%8`G# zJn58zCwwyf!~3*IpTsyiD!w-^VF{F?19Rs}x37)7?Q0_|W!T8vX{qa|SSY5kg*~Uj zGioAVow_T1$wZHcxbTUEZRO>xAUiv5Rc|KVjC>s>ai@FRy~B^(;r3fVg_KEL5Q`^R zt<#e@UAqryw>XIsCvXdSHi4eB-gJzb%p;yOlAH`v@l+B7lRRxgE+8oom4rpXsmVbj z9}CuB-ugywPJ2!?d7qAB`UFqEekN~DMe(|DU4eGiurohAYQg%WVkDD;(c;s+_a)ax zYT17@Tu~7o6<*8L=XQ^S+GsfZE@mCD;NOJcwL>+8K(;!X@>x^p?)S#rI|3=hsT?j0 zvh4;bM14O1{ZFjR8Bzo6F?9v+;t{1<y#6B-Je<+v)D;*>-Uwiohk>4QN}Rx9S<`n& zxyDA*xCOWrn7Kg>@vhP%0C#hTyeNxSd2nPUCYab8Zq(b`AtNWQSIP3S-*pbhVj6;s z#u)gUq2jTa_NP5@L$~N~kyfGbZ$teL(|7hshVmx`EgRtiSA#y`Fe3))ayFgWZ+L1C zXLd*_^2{PfP?Umo3XAxKqOsU67VZ^s0`hUx;4%J8whp`4#axuVg*EcCkZ5teMaDZ& zANb+yJ&KG!C~6Dq5D$|b2LSiC4zW9Ml__;azC%LDLwqWIjHOSaafb0uk8#uXq`Bbi z@U!*nF$&9SFrHi%){DSN;;mAp_b9=#(6kvvS4F3I85dw3z+#4+w4@89BFn5J{1QB} zWg<#EO}dOt{?(ci)~Ah|WHdlb0?wjkOKm-Q)Qua)=jD~XH+WtF|1GE~+DOtQNgD3E z8LPwlV(@aSdq*P|(q=+akaUWgkXbf~#Ax6i{~zv=cmgMjGaaRizx0_h$odhiTR|%4 zXJQBc{o2g${`||ABx4i~fiqlo!PmK|kO&RR)A9}8u;7;M5zpMw&a&`E7R>^qLw63& zFfYeL=()%s_E~i13#Soa4EfE~2m@ZD5lE}xOMmu*D2aNBCUW^@%n;v6LT$kF@huRk zDt82&`rx-R^$qr3KxD+drkx-U$^}I-1n=b}H}tCC)GOviG!<sR+tBUfB|tE<Bo@gC z(zhSLaR%Pb5h#x=*cce!+z}<oBpI@y8Lh*5rQjw;E&6p3u?>&YAZs9Xkp4g#nIKX_ z$|UVck9UxOojKBD8^$MMyaSzPFKh#6h)a!u$fd#b*|Xz=_s~!_&?uxUU=U&;PS4;O zI*gnlkLJwnCUS7~yb5s@+ex4E{wj`21d+sX7F)*j5Kk~EWN((NngiACYeY35C_`y- z9<g<3dP>5c+84;hFL@ApF|Osr`my{6ns?#+&}ehd!l|`qyK`q9UXfIt64=cj+jDb6 z%YwI!NC|8?Rv*dHpJzTzs!nQoq3pM{olTXQi!wi%BD3ZH{<2{`)T6m4@zcGLAqB0` z=@%ZnEgQzN<;=H}Yhf4Bm=3ZiLFz~EyaGI%P_r(^sey|`|0S>L=F(pud^`Jc$)Tbn zd8dAU-_afSm+o3My?xAyy3fOKkk&b;(ymPUUDfE;yi=n~+Lz?~E;zb1e^-3Tp~WY= z#X&BkhlrV6*wI>Ay=uYX-JgdmUSGA~;KJ6@bC2#X*coguxtz8tG=1m8zd5l2i>A6D zr|m@LzZ^(jF+F+Uhi?}Z1rM|zzWQ+0`HJle{-0I9tch&wDp~U3Eij~wSB{)M_*bi2 zCVjCv^5m&ok39a2efrJjh|Cy1-Lv}n^S`Ny9Ce?T4EVHyGb>NFOeG{DiGwuB^822b z(J~dI<t0m#B%e&5^Y%jVkSkN67Vn5!5RUa7nO%n_v8OV+cAUu{$KEy<rX=zy7ubh8 zriUjII5DrLa`)?4FH_{zOjNWa3+dwk+odR1ZkrC}-7R&4OP3`)7(nwdDWtA=R6#P7 zXlqW}sA5QgHix&_-ges?+l+`xwAGdDUNvV<ao**(igR34cDVK~MDx&I-;ptfa%929 zuuoPF)$bk^Xynws*FT*gvJph;$Ujs!Dkqe)5cwlG^^szuDzATRR0UR2F!ku8@Q~TT zj0Nj=CTlg}oY2EBe<D)CJMX)Ax--a{!CZ@o679;3<QJd*dK&A2ccIHXymiFns*Jg* zW4|)FLit#ECj?SlQ?h!Y&6V+o(jkttmamb#E-HeSfm|XB!c-DRMaH#Jn>y{n+aORG z%XwJh#1EJ_0mS5!6|uPOAV`nNDB?QO3xbvjF|M@T-iC86uIluNe#&F{6;D?&_CPvT zZcl7=DNDBG@Hq&;T57|-7iD@ZiV>PP+$CfO5Q(Z;ZQVKcDyeG8_RS>YKaN4ngvBVA zp)MlXBePs9kWUO6whu2<Z!PSk2<F4vf5BP;3bz^y0UxRLiIETuk%j~4B2#F|0&y{{ zihQT9SToE@>*}=@9eyb55hCd+c5qCHUg`pzG&b`#5-rrH13p6w7zCqV16ja`i~g9% zxAejyG}jm``#I7k?&w5?U7H8!2@1`C`EU>|T?Gl@2~5d@;;5y^(?yD!QU|r-NqIwX z6%nzth~~Vt5<ga_jnNr+h9eLB4(Kdkeqo#plfnA6YTf+e8#I^2&ed^N%e));3jD-| z1M@vPYyz<!YC%>fsCYS*aj#_#4_2i{J^MvZbe+|nh|=0TNuypi#<<SP4aavQRs7vQ z|Mrjn)6+o4pKfe<g%vo<^7?Zj1T{9GbC8B*A{}0Y7Vm@!)P%(_E_=R;BLrU7L_p0F zoz7M9nS~c7P3?*^)dXDxg~hczcXZhFUB87${Xu<XMSS*vI^vubZFt^GzbWIW%njYi z`FgTZ1=^;GnRrT!XX6;zv9T<k1!4hOb8CpYq=NPgaKpWE=~NRZoW#O-Vdv5C?VY$0 z(=C|KM$BXVlSWdS9h=fVXVN%B#Zn$Fc_NQREQ2p(3D!L?#l0d{z;k7Y97p0wIW7vK z?`u8}=eH?XLe^w{*Tiic?AtpuHDRXsNgPR5@fiXkb~j=qA|R8=ge;e5;&BY+K#)j$ z3UapO4Pqc-DDzG4;2!d9-k7)C@d|d{y@gmSw;I!W;_*c84Rev)AvuM6mCVSlwM0oz z1mR<3{4)VrEORTPhp%l&ZP{^h{n$1<l?&&W!O{=!-NOF_R*%bBmQxVeRUe&_S(Ll@ zV%D%o-o#sSmKLN)`B<=lwj6z=27q^Lo7J*|Kbm1G@Q%X7wdqMmtIj`*%~D#0<PjKF z+nuv|$NI#06Ek+!(QFJM`4|o4jvU!8Mm)CE_ZF-xQNUG-$MkWP*?ApX_O_gEyOezD z-cxCpSBH<3zk9XvhnJ0mKonX+?F(B<cdefATyH-cDNccyq_l^RKk?Ve3);un@gD{* zz%xWUqR;hK916EXJBpX&{7akLeFN(_wUcz}9l`d1qa*ay#6Ild$mo|tbNlwT?b;HW z{oYrbBS+J2E`6h~dEMh(`wHudl>3;UhUGE|&T%yD&V(vuR{P#<JpcNaMGw8-CdXy_ zL-%2wz$A9B`gZBnNuSq54wL_YN$g%-dEPvhHK$gHfE3S+k&N9&GL9M>Nw_P0)$TVd z7O5}ir;<S0R*y^gpk&RdWetsQmj=m-V7SEZ(}xMGqKlU0FIzYc3et_SG7RH|fJda` zQVH4A;piVZ(mAY;SjLQLA%s0}K^BU9Ks=;q>_pLsh=({!W>-Js$b)8V6``oAg^skL zb%a;6j~bQlZNeQgBlXaN-t?)XgT_4yrq*xe3K5xhmj;o1u~Rz8@b=+RcJ540-bw2Y zgd=($$)c5;V#oZL_Xx|5fn11>^rRhqxUMc&;zzJ;fzK(p<a{(anp_(>^ztYF16zl` z3cp@({`lOq{NkJg>xiQdKfp!LrF{%N$qAv1Ja=E$1X#;(4*odsX76zh-t*S5S28yj zMTR|)IJoU;OJQKvSZ>61700@3hA5vZ`k*Z9^O-|DW#k4M#^(>y6yEUrY^03%b9kw< zS)9OgSs*6f02Rj<l>Cg@F28x2h9dD2N%`vd{oG1u-yQMdv}b@r!XaoFVg+i=Nj1F1 zG7#j8o+!{M=!ZMWsR_S_n9%RwIFIMIR{uj!EO!DETWOMosUcu$HjS`IBeED=l7!PW z+yxf1HlY6LAPSNPn)Cp}(|p*M@L+}qG)mpH0IYEf#Wq;Gn`RvIhTMxzdPs(m*M+=M zXXd%^YE`8d<)k=wj?yqRD!Ui+Mq=3#&{*umTCc4g8K5WnVdG@HCST}|mvB8}kqKYs zkYJ)&X+~5`DdFdny(9$)Jp!JhUSvf(-i!N;hbwK$Uy6%eHxEN`@v`XYxx~~MHR9}c zYKr|6nvx^Q#9xmaq<5wXya$2VCtnB@1d%U8$6T^?5}b@RDe-nlpGL@`lD_R2<Psi` zoAGX;OIbu?M%rTGYGrcW$;N0(okwFDjC>l2HY3ewVOVfL^vMX4=kkbyg$9>zp~@!_ z^3;D0`p(xW*a=RoST`>RsFQS{!6OdySuLOi4MK5Ii;>D+@f?U7Optl=lwAc*#T@GW zUKtFWiN0C_j7oGMgsNs-OO|M8iWX_~f*NLjV8vJy4H|=Skba~`CSkyen2)s|<JiRF zA8?Ws-OISpe4t!P!q@{gcLe!>Z|IZ=Hef5pr4U%W(1$13ST+<|A;ZVlC}I(h_`bne z{*hFD%{!e}<8|Et_6nS2nRw!BCN9_EI%+PQHe1AY$=VUqn1Lc<->%>-2m+gJyqfE~ z@hzDfgpj^+&MH2R*}@Nfpq$~g+m4HkaIwgWA|el%mZ8APKmnt5y^#mRjFLC9eL~WJ zE29jEV;n|8bPX@1Xh<_>mfNk(bs4YoiZ>iw({QdDK_!%3H#m20RodMfigQB<9GwW0 z5;#(uuguS)#Av#7epzlPrTmjA&E2_6^0MQDBNA$&Q%Gf9nOfT!2~Hd*juE|NT1QZ} z3fB_*U@sO7Cd*BjE+d|PH#@897C6WgNzKGJa?5(_a<X%(sz$7zA5z1N{FW`l@L}8z z889Coyf`}?CY732gTf)kv0z-z!@XA;PbL52{+F6xJd)GVg}m{^GnqN3l6%KQOE2uZ z+?{-RyY!Ep54Z0~&pDNNdAmqN-l=4`NqWV*e}Gz~O9;vT+IG$hr>}hX4{LTIb2QlX zAEt4AI>N>i&&=SerfsW2hj;%H@#8={XB00v`Np1<;&AX_$>qrE8PE3Cr8U()?a3WU z#8vK0Sg|EEr*H2Pe3Y`1+tYd@)m`5k^Zm{cR!P^Ab%iIcTz?|JVj-%>s@@}W`u^Ui z#*sN+E-Wj-MOo54E}^j`Kke=KZPlyCV5t!6NLZnMn4Mx8X)_X*RYNC2d&D5NnWHk1 zDYVEQ8P$uI;i0tK5xf><Jz7>CuNxB2hbad?Sh#IZaHL|W&nnrW1V`G`G*TW3Eh}HA zIc9SSNz^nW7x~Gk9LZkD!<>^g1P@q(+z^Qz@Pf99zR0l)axqF8#{I|$5R4;Jdo60p zxw#EU6h;Z0uwf=jiFn9BlSK&*9XFFj8VLNLt<R$rHIXM}vOp;YxG0M~`rs=db@M-+ zFjoN(%d}QhpnI%C+1RyyYVfr9O4IT)&TdJ5{nN6VNPfv?f+Qc~)wnIUPiD-^pFFRH zXE`V-<T2;Uz;q@AGv<GM=3c2IJCQ<ay6(oP;q*Sjm5j>l0y+1Zqwv{=Drd^v81tB1 zd3=Tol8TJHH^MOk&an)uC!6>^zcJ>rQW}O$cayYYP;a1ZAnoNv#U~h|DiOwmevf!m zFZ*4w=uC{WKr=Mn6+BnU(qIxT0}Vkq>q4;-Tijb@CTiodd=e<kNi~o--tc5)D-%I% z*+!ee25QIo?*>6}3<Ce;Nt$IAs`13lBe4{!8ajf*nWrH|MNjpgHY4KVDY}>F5>&_9 zV-Al&?GP^z_3_8~*U}Dy%0cQu+1B@DS#)$Pp8c6J5azyUP>UNcMg+q(z7W;K1i~E9 z5!z}e8ssWgamEA+>ZwafjwjJ^f)iuf2skUrg6`xZ=_<39*-8W~wrw+ATyKd6?3-`Y z(Xk0Aw)PflCQj!^Zs{~{#TZc#dLcO1J9S9r@K4pCTKEC~bn-%;jnOSy#!tZHHlBsO z<c68BYLb2&MPXPIK*?1%sLhhA7%XTUnzP0_mym}^`i^!QstzKC-|LdvJX`F=jU#~w zvgte=8wRI-A(=iA*CgY_7b2?`VZn6?rKAs9&;peI-9PXA<L|7sHxQ4ZQGC$irgZ8` z8*s>di^lLf67iZ&f+I)`Xl;>QA%}#fnj-!zlrgeyUf!=oH+&!lk;hxJjEjoCVj&2) zi-k&r|MMcVJw1e*vU_r{O5k4Ttw_Yujv-z}VG@`^Mu=9Gs8NV=oA$;xQ0#Rr>l1pB zPWC`gt_^7R#YM`qMx76wG-3~l5s0!yBjYnr6H+bO0oXh7L865Vs(KWKjAn)?ijfvJ z><O;LmSz=XkOI?E99gMH5QwEc9Jf$!iyRX1q>Z%CO5)(23We(1et?R>KsZ?@++so> z<_JFl&)MMYmOW%lF*;xxrhoLgt{CwXae`|DgpKmSp4fqOqD*QbVbbGqJv`H+9$cWN zmo4sMWliBIs3;OM?%wQQlXQI0fx&shf~)SD&=>B`Dafwfgd{PO7Of~9w+|0SrdV?3 zHd8ZLGfQGdNb&^-@Kj(H*|Rbe&xJ8nP&2ZJgaTWR6ECf&+eJKs5hF5FU=;de(Ie4} z;0Q#FALK++QXK6tKJm2iiPlUyc1H|{mq^^$L`*bg{rqgw8(1e7+zx^rCuo4_>0SNu z8U;K$e)apG71h6(Zmi<WhusC=Dy^&9F4iDLV|#vS-Rc?770+SM+*8RS5U>uhiWT?0 zu{&9cN6x7|{j6i!KiEz<h^R=rWDc%>R@z3;ag7e+8u4`nE8o4kW>>*?kVFDk)_nDX z@r#Ax8YgbsRq#mSHhh+om0xY%7Ru;K&HVWM!4JON9C=sLMc3@UQ`;XZzi2u}^=#3J z<csg7eLG=A*X&M{F-}IdRWDgrH04OkyIap6?xU4uQrZMG4OEO{2OAeOB-|1I{xow@ zjvcx!ZAR()(<;v&?R;(7!m%Z5CeDFc{9o}eiCP>xQjDSUl`)WvYI!4n)$m&K;VEsS zN+(F%C>{%gI0u_JjwW#~;b91gP8y6LF)e;|e8;5#HpnP48B;8_VUY{kSXM^n+z(#E zA*5!|UQ2wmGi@gc4xK@Sv~-1<TM#Q6oo;bSY6U#R=N8I!RLpT!2WmwU#KdVFp0MGa zs!VB4+wR;tkr&AoZ<{NEs_;6!Eu&1N7$9*F<@hlPjm_{84#QV+LYN?E7=%mf3c41! z00%q*PsLFWT7J!4LBx3dbnjSB|2J5}r)A4fNpMpheko&fxSaktb`cT@eqt1484gZ{ znJ~{syWAtrK{5UqF5maFb&b(voe%LyWy8#vK)r7I@o6yOl|W;2IiSBz8A|f3imZC$ z@tw`$TPJ2&z&kJ!AOu5~os}3;3S&^yu12=SqzX6&c<pQ)%R@NQ(Vr0!Hu7jr0d;{+ zc!|J5!h<&>M6|@^Q3DqxxVTBLG7ltCh*K0><L=XLN{C&kIUSVX0A>`Rw+DFV6Gl;I z2av~YWpNl;X~O@&PTDPY<Idl;sT2Hns~XZD;;p{Z!PpPqdhjx#j({*EE!MN48>hz| z<IC7QHPd8}UNnYQSk01ul1q#zdElx+9gc(G-B{>DD2)$8po1KQHSJ<^taL0z>ng${ zI5JdcD|#WqVnzoNi;H0>d+JRaiL<OK?Y%ai-sA@-j&Nf;t1@b-(i_YO-ggE=@!>XZ zdc4Ua!O8?u6W)15I*oluxY66Moh-S+n2HOiYHWQ=BxtPWCVf*@3<`G8;A{V)MJ)c= zOO@EH6E8i2Of?$;LMhi)R(VFXu^-8P2`7`70t9suFX_PTflP3b0<cPqXf_&4Lw^_z z6lIOl>V$v##dm*xm-L8A;5lFP0GFda-0iCTj?>MPjReG5<7;G*A{v+DCnve22EkDJ zQZ^}IkZ!y|?g>#&(BHWy9u~`bk@UdO)KZt@>@aVm;gta5MV{ZF;=&lCEemq%R@D5C za-%LxH*tub?sf8>bqWJq!g_E-PQ3fV8Db#{*ZoRvqt><Cln!;gMQGh<uOyj*M%KRV z7F<<7Z^UIY9PD@bZMMy<b+qdO5Rba?jjofJ++h@nF9$6Ur*LfHtkD$NAkr8ne7w$s zeB!q3RG3uH!wJC|$&a0dmLOIk#)IUbgO<4v_)Cb8%aKL5%GRMWZy4|q;~qOc5DV$T zR7o*b0IO&??`KDIPdq+SBt)FTqampYBWgd`AWpF_{Gq}YfnB%H9<!sSr{uvw9he<6 z6`hEnMTC^X7@87T_+)l`p0h&2i5JdK3PxKZFpAt+QS6cQlwmZbYzaU(^0J2@Ux+*e zj7g|7B|Nr>s78uzDObe(k-SMBNE7MMJoJkBp`l4FwZBkC<7#nk*~vP>pr!Px)V`Hj zPZo5?8sZo8uuP0Qumcj2GUUjx>Z7?QYJcB8rm^GqhnKuxFgpD^-{cU__GVv+mX@PT zoIKI^`}T#emHu!5n}7^d_!Q%x+j7!E2RZrDzK#oHqQyl=z5|6QhC;-9x`b&Qy;n{? zQ86y9w`*?4@2Bs1c>IOXcMAN?lHSXg^H$9&?Eb~DoDn%~Eya%&FX?z@c2?j1bql|h z{Mx!XOWq&0U|rDzhbE_uNqBQf_n3vS1wM!*e7=3+1CWF*33o+|F-$qQd({AG!qkY) zH}ah$lJ--WLgns`ibb#mxWt5n*H>Pb{@~Gv=>zFQ?5wGfjOEG0L>cVz*STVuM;}_) zULL;}U!$rC79h)_F;u#8TP>Rh`ZtB=mAhLiZZaZ4paO-#*&BAQBM<NhI!DZ^2(M^! zrpEw@BD$c>qY+AER4GQ$p98gS*|LuFm?Dxm%>SU9Hc}Pnb*4y;E`mn5iw-sH9!Jm= z10>j%dH%YQ2gOLI5+eoFn^wfsin8eW>jfV0n=7KIMW*vdcDhT<aoKkf^?|LnKH~*l zj~Fi)C-xwxq+hmpCp_x0WT#O~(9l9C%XMeKTzhUD9D)ze-D4D^NHLG=b0H#*Yjk}V zqH_A{nWQQEb_Q+>KCMofrN{o&e2g1Nfwiv22!#*+VEcc#4w75da0|w2)<>pw#t0Lw zLAIy~-~sJz7#Y;#uTA!M8ik@DR(msp!{FXR9gGVj3qdD|4I25iE=(U|wBh13bobxs z#-<Ng6Ui7G8Zi>YreJrXg4cFSVLS15Lw69kpG_2_XB_*Ybgk?b7vOX;Pa0sw2)MH= zz?~-}e&R_SawO0UJT=1^F!C0NNRr%Oa)#?-<%MXX@Zz33`X{zZwb2_XS;?<#T^epm znVb}P6gK)od`*C9W8$$d+_Ho$aRX}7iesZn+&lEU7v6$=AU+y|!X^l~^srd&Lqo`{ zpZ1asPgCnDDGRI-Oa}9N#ChOCES?Od(O@t+F~n793{luZ3`UbgAXx*}UX}wRE-|#F z2C*hdSZ@pfeuM^LmW8bmXxUUF3(^x{9Q|#!S=J3>P7IB_`eLT+5d9c@xqi2wadn&} zinI|M-jV8>PxN*qSzr`nZi6*s{P(Lb{>LxZDO};(5iO=Kv}|{f$|5;^MgF)|8y~9m z15x@@#0@m<BNoM!GN2R#YvedXLksJ0Hccbjh*-*ru$GpbMWPBYfDzCaf}U=7r3eKy z#`2cVf^oUaS}%X8^YBs3qwztz2Vl3xS890)9gZHj<`j$^=E_S>kkas^dN^cNJn46} z>eXUd3Kz3Lofx>s6bCpGXiv>A_rvwV4vw*xvXX01g43;H34CXg4?N7zVp#OkhyYOE zsB`Sg=}pxYE23mWQUQ9o8u3nouzQ(4fmhP5^r&IKXJw#m6t90A7Gg1u3v04?9*P2; zCTyW6D7`7qg6&*7Ngxttet2n&KNBb#8X{XR#0OIkt{(&=cv0fR;cG80ZQ0R4hC+GG zOXuToEoKtXG`qu66-z7CNirCUez-NMI*^!mQ8GkGeI)E!k+c!H!jy@e)wkqGwJ-<7 zafj9@Ok!K^yxg*XtDBWm89iEMhRF1vTdD%;Q2Sn34oE>gjjQ+?pYBN<UE7^owsXaJ zsD&s*WnLZ>V<*9iwBG;Gd*w{UrQ{cne5dNrV<7)i#ug0YM<ru^z$-rdFfP<S<~0)( zitnfKb<C@%3`=uPjdx_B9<osSQq`BZ6^Ib{Ax0ZgN`EN1V&%K%r`px9j;~(0zqGbw zp4++Lz>zr!8*9F_owHv(b=#LOqy&CHJyFjt8<*VlJkuS1KYheKg%y#?WjP&Rw={q8 z!uWNCr$rYMqK-Q}V9<|~F$Nwm<<RXM=~(jSlE12+(|H)hVd3$W*H=7?>TnE^p|tIL zI?HDZ-5j{fJFwP2FasLVU4b+KL2zz`+g={uJ+0zADn;6}flf%o9pjh53YHa-ba=h) zR(L~WM5ioZ_~_=6w~7}pXsg^!S^`63vo>!Dbb6c7IiV@e+h|~~{0hi`PVhFx3x=am zFv+yzJV@^Xp12%-*N9q0Ebg!~-L;Cy#egk1o5Hn{_{YToP$HbmQ5S|Wgjb+cOwd!6 zrf>p-D26jUpeXV&JQjc`aZT<8{Uu6rlIb+-V}i*EH+ma>ABun8$DRk`x11zf&J#ZH zgMjlpjGKsPq(TK6Unly>7_&OZ7iuGalbXDp7qMd&(vUquzN5xddo8xn?UM_~DP9Zo zr6xmI_I5Wt8%(|Dr<p~Oyg`QjD&_qy71i>4ng-)9{86JX4E0s*dj^8vQeu+D$_Cfr z;*CJ1%C1j*vND<kSgRkzLKRaRypdtnmf;;i{y=vJiYVo^YBI3*nL>}!1*~-yT0s{k z(ug98))8y*P>lfvZA)4E7q~^D;2BQ4kfx!Y1H}z^S?8;m+wqDmkON1FtW6&;Jbf)w zM}e%HQ9)#&XxU%BuR-m2dlzv5VEz(lshB0+34m%^0ccE7t*dAE^j1cP9JCHt<t+Wo zr?Lo^yR0?t!a8{V;=?wNj36c2is%@kjaKOsKHJa1s>H6Dl?SKmA!HWh9U%U%C3@=S zSx7jbV#m`F!kSH?_kcuU5BHM`L=Ku%0e57ET4!~LX7Qx2lu+PchY2ct9XCFdrVh$~ zmdBH;0C({3Y=g{@NrdRfV#&&m#j`BKDG@`air9^saR{e4H^*MZACys)Wn(;Iy)#N} zTFlj3e8znx7Z5$3PCrP(|7!WszD500Eo>N<Z#M{QD?RA9_6<XM!8fME&~w7-8{`9I z1wplg?)q|~1jaoM6sgc}flf%oAfS0P)|){OEa>Uci~bR#P8jGAKKoLLV*)-S7%J-E zsD_jhF%eOXK644W9*EE24jTw(KvFb=%h3>;N2u^cJ6y&xMj`-s!LCbW4w$6n%ooR6 zbeaDMyMCP>A$}o^;f?@VN(C&X6mTof9;6#;4u%VI8nHlY;M<}Jh!oiHP_zdNTCzHf z><%@cj`zuc<OHZi+LIGJ+afHj!B-tTvw~4y{ieoSPzTy(E%Kln6M3+P5h)r3FZFU& zs~(^5Q7Ewc;F{SzMY)9^3=I@wRdm)ir5?VvB>+XZbSyp({&0`ni*Jv|h}gBK_N#Qf z2htHxhi{LMpB74~_+$#hDkgrLevfqfpfMOy9OPZ(hKBJ0!9rR?INY;vG`c~N$b+&H z(`ihN(&s@qA}KndzQ@drU_r{$1vSu(>6c~{ZrRa*_VB@b_4RE#&aAvRvPU_HB_}X4 zXjENOj*nr|L)@#u?cw-;T6rv+_(Hh>^+->A`0&G<zOyRSmJaqmbGEMP%Y0;pHD7J~ z28F0yxaO-3Tp<yHqiMZYj8;5zwzl}nYYF3_8pCoret+=FtEcun^lOBLRnrd~@fZY# zMnN_^he~a@zU1WVx78*-fAA*<B3qvM$&TQG7mC^synxm)YsZkshP^iI)e+ebE$xC6 zwEsh7dE^dUi?87Z%ev-tVqqj-{0i4%86@G2?K8KVHG%37e`V6uNk=<doEuScsgJY7 z1750LwYy`9q=os$BG!({;?Lq^2hZbDY#$G!XvdIPxUH$p?UzZhYPUPTv9lxp{hW=} z8P)T_{f<k;;tg#?FzM^)X9cU6k~Jmbq=yOGY(#}<k@Vnu5oib=ZD`_zm@8oxhNBoR z{LpVu_`M#qWq2Zk(<4g70KE9Z01*P;VSrv?$HfplT4DVkI20lSaD^swD3Bwp>!YpC zc3R&louzesIt*MZglW-B+C!$2a3I^T$eKNTdxN8rAYx(7(_cTTl!R;$R_;bWkXi9D znF?!JC75{==7w5F-U*k#YFW*3m>d7Da0F-hJtPnbG=;AhoP+K-=>ki`KiwB4IO7lb zMdUxNEzRj15E0163K`016I1z{EcNu)<63IM<r{=9HpOAsE14J7^%@(CPOi}n^6>Ns z22psEB+R5>8JA(eF!=ii<sb1demmEKk2mWyKAwyX+%lZ@lbZd-zvOmG`dI7|Xkn%) zIs(lTx}Mw78lZ$jNO$*IRn^FmWrH&YgY)Ddt|~KWy`{=5GXFukhSpbM{)EjHwb>n} z4}h98nft+a^um%opIOi{zdJ{qf*6Opatt1T>(yko2Ao8Q@4t!aaJ(YcsDs8>zlMZ( z!6<m2hw_iTfE2--cy0%Dz-2!Q$J`?yWuPshz(_ixy%%Z_YZz+Yj#iXYy{<+IH{{E* z4MoeaVlajjE>P4`>!PsQt$JjEe@&85PiI+g6;m#ZFThL!dc<z|1|7SZ|HWy;O&GD+ zWG*HND<KI>-zR>=c&RAfgo~Dlj0P8;98CYoYnl9(;i7!;l`vujY)YGFnrDRqT80j3 z!%i2o&;jSqs6STJhaI+7UC(<%YXo(t{@30g?fr!u`R>@rtOVAgYp7M`K|QAA7}R3w z*4H)c4kw&bU4Gih5UnkJ7JQ^Er{}a3#8kOW))Jw?k3Eu?5b*1PCMKvg#8v)g3>3Mw z+c?g1kIvNP>4W7ckZCAeL?f$52aphKoW?%7LBZt#S^yCVYep3q<2=AY{BaUx;U0lG z)Wt@eikzs%AFqdS_dR}K)UI+k&k>JrI5J@DM(P6oON2;(r4!0U1w2PYu7p;0v7Dnu zVX5?&-tZO^F4#m|cu#)9D+x0hn&GB?y4)jT0V6>r5y)CVQ}D<`K|d?dmTv4$gARBz zE6@+n89e;}9ubQ=xY)wb^m!HBxUyyc@uAS~gX;%BjX*GBLs2LNascelI0ps5jkv?< z2DROxl^=A%5Xd*+L%<v`8y*}KPE4J?v$k``3n38%sS0B|h%kg}J6{N;n4ZvLsfHqG zLVVsdu?1b8lC-soIK$!l&kfr_I`ZF^Lm}L!$cU$N>r;~G0{ub8HhM8&2?z=GZN?AC zFZ3jSwkLRt4y?aaLj;0mjY%Ko1lt;F7xCx%%bU!Kcyr|M4@4>tL?kHmbA{{S^eM$% zpg2?k?H~b=|Bgo$zJw}tWk^IgdebIohO~&<`vY)+XadTBwz|YEezGI|k>WA0PP8qL zADo^#OEJsj%hO)Jt*+|Vm&-*TnlA);e{!(vk;E-<f_O27cx{O(M1FXATH9^4;bWIF zi(j06bN-S$NI()hm~zN*1Be3L;8gyvpaZY11L;3lcwtZ1E_y1`q#3+Ft@6Y${@hnR zmy^U9EWwbEF3@5cfxL+uIKzb1V`e+fplIX-w{78se7HdagdiE7Kug5tl6M5>t9IXt z{E&fa(3_dBRtq+zIyf0XMB<y9@(()R=3LF3P^KZK6IiQ-rvt=X1%i|6?KIax;e?o^ zAjv=oJWw5AsDvRtv$M!px}XA*!$9@GyOo<sF*_L549_~xi%9#V0<Q#sez@KyQ5e8; z*s}@_Y3m21Da+W(3FQLm*Qy2_?ehj&cr<~d&)tXXpyZ?rJRmE`W~k*R%0)~OC%}xL z8^pWYb7LV3F`D3Dex;YMTyTz{#71|A$htuN*AKr0C;4Mo-Kc(E;^PdxU}FnW2($*d zA*bKbXl2*}nF?bY55E+Zr(ul3@drR6P~OOhrw%n{2=(a`Py^{OMJHm7sY>2Sl>e$n zfeHK#=UO;|(NN2u9nO0|wot~wvI~R_bX{y<r^{8SL~W;1AIC>dWA-MhLU%!{lnU0- zt$I2KF};I@VmG+<OvXq+KC}pn0u5J#Aox6+vw>xAyB)cR#(n0EJ9s72MIYpHlxdU{ z+@YD!BG})q3<KT?(E{e0OJ0y@57ZMIbbdvgGL%Iy2q_NPza<|zY0TXt1mByqY@4mi zqL~jSD>%1ep5ePfli=k>>$@0)S`gs<4fTme>dWy0seEPsjr4<>z~SW=ML<B+4R|yo zJI*L;aK;i8mRzK$N8<3b2?YfljaV#&z|DC`@=1=poQq%{^wGYmia-HakH`b5;D<Ci zak<{6b^4td@F{PUhtn|7fNU`r<wnD{whZl~8kbe-GXv`bk>s&ZbJjbI-?&%<?1AwX zp#V)Eyu*LRap;cx>7DPs`|vgjZfj&{1@2uNXl+@ZW<G3`MNm~~PJx0B>>Mxz+=K<$ z3LOTwjK(5QQ0Qie3x_u|PK(f_n;v0n!5KOm1t5>8R*zPb4A{-UDngJ3x+E~+0@4Vq zZ6nr2y3RK!oX8+uA~kOBjk!oCJAlo?f0g{#{GepxfIXr&`l9j+Tu_o;(VY?uN?m*a z<TkDWoD0M`*X152xY&X1k?zms1s=!1JwPT<;8C7|YzM&qjhXTS2Ivb+^)|@?t3W-S z&PFit0f8Y_{X5Y?c7o##N<r{qrX0vmxE9k8-k9f_B?v*n4EXogdVFZ0zGTK=Bz}nn zMNM1IVXGAa{=u}n1~oT{8VLN)5L5`4%$U*=!Cj~(p-`}a{|F%oJG5g9`r8S45(6j! ztb!&^^aXl2qs`so0!*gT3<;!z&TyiABBqcsEOIV?SwUvUuAfg3sW`Tikiv+BpHC>P zukYA$CVGw&SaNmw=-Qs9yw7$rG&5L0f9G-I6zB%E^%xI}&=a<7oV9;-Lw?62#aEhw zV0+8(rw$y+Gzy^P<4+!g0yG;1c>drMWw(rZwWG^8!@UY32;{Tss`?sL?jOBr`(p`s z1N-+qb${ve&Uj!8kHPMNEU+r$u~KOPK0lbXBVGIeeE|H|dBgVaE3DY`YFfs8xJ6+F z6r-m2CkLO%A2<F0v}B`gWnM=|h~M)4t{*=V+18a8JRF?x{ZOsTCES5R@T*B1p#~`b zL=<PL_@B}aEubyJA^%^Z2OFUYcEKIfxgdX8@f48Xlml=3j_LUuun%^l5|plNCr-dA zhzoaQ=2urwiR|Y85e|}wAj}WVwd?`e6UP&zA)NDh!d7^~G-yMWlL(|Cu<3*YHouW! zwB}1<kS@;n4T%7`!D$Tt8^rG?4?_GHc^KHT>EwX6aK#)=e8|<1E1gMq!-DljD8xOg z`WZofRgI@BeC<Y8jVhpnVuBQbMiu?$C?G%(QMCRFQyrudDDSw-<rl>b9M<d7X=Dtp zn}p!-+lOn7>y%#LG6+-b0Zu|lHksg14ZRqSF63};)>Qb}Iv)I3R}u{1B07f54ABN- z4ag==o*0)K`5S8+eUj89)ztvDa8W5QwQ}gbyvEuTNJ#T@cSZ8ZT_Ik8!>L^u)GQc5 z>wpviXHW>4ey3=qRyzS<h5Oc*X$nM#Wf`T-8{)GehEeI}To6A1kxdXM!kBG+7@nPA z-4d*8+l}9USyLA^(aLV)5e8c)m3Nx$oQp}+(QfLL=mLofL)s+uc+|@<aV9>FzQ_bx zIkNdiK$EBhfjd7M!9GKF^+rgtAkLt8fRPV)0Z#s9Mu+B|m0%!%G#_9nUI#<8Tu>uP zsy-A$BOM?HoTtKB*##^UTUjK^ur9SKcp--xq6QM<Uo2v1gSW67ReQsRV=IX&5>rrt zufbg!JC3rU4i5`SNGfq!faX~q9^Z;M;hH!l4|tQas+_LCSIjFNG!4JN8!%-e2j50n z5n(nii{uFr4Ss@BKwa}BIyM9?n5itp0ONr*O5g;89o?~0`2k!*r#dxV|15b1#Glrs zo|4c?7Sivym_|IZO5uV<|6lH(zUL-6Z2&dX$3{JqfHnw|04%rwKC9d=weE%n8wv$_ z<M7|2kiZ6ta#D({J`z(2o*5gx(+!NuI+}t}p}Up>xs#LRPiQ)((g|4tX23SwGoW7q zA^-{TU|+o9fPpgD?vUJV7?p6czBCJ>hmJzHt_Z9In<eFI1S!fBa0z(?zT?0EqjpF< z`13AJX%7y~ZQ&2~HkceD@xUs1><UE<?6h?=<Wh8LK7(WdHBh>z!5c(2{6vHF0eFKO z6%{ia5GimH>`HNoGwItzifpE3me)iP%PM-8c85QlsqTgBrRfu@Qrp+?ul6AS0Qbih zAr92!mF7*Hah8A0Y^$$<W9$$cDEve`V8&VH2b4z)Y&p56d?zRFtX&*T&GfAV!Uo}m z={3P%)x=;<CBdE(JFWlWLXF~zqn8FS0FLiW%}dSP0_aOzsA+twnVjOQ8fqCuFW^63 zSOLutlUZ~%-#R7voJq%IbowROLS`6&AT=+Wd_wPXjD%Mq3~d)j@9pSD)qnTx$lbv& z3j)&bhp+DyDJXpRU{Ytabg6K^@ZOH=`Jnp~B{xTY*bAhOdw+0WG+;CVr2r;C8sYuH zUp}T?w|%kUdieHTiM?Gb-#z#(f(0-EDFu!b-1bGkW&jg-qy$mmw%>3R?(k~bxc7(U z1Unl$K3Z}TA)vTxZm@6vzA4MQbXwZDULAZba6SBP<J4JsKd^^=zWqK^`stT!xzy*P z00avhBk%w|W(RzO5p>@m7+jfD-OmVO$X~hpFdl<gz?4Y$w373S>2dJ10Ac(@fW2j9 zd)+9r4``U2LporJ*UC^a$)yhPAY%5x0O+^YNI!t!bxC>=L`4l~h9H9IssAgt#Wwqc zi@@|id%=xxqW?j<fMDFW2V4~4&vgNV`JOcEf1tDnF~LwH1R4<4FBa%djqjLPAONS= zA@Fa4)V3+c9EPi<f}%dh9@%K|!&*2*V<#uE-^NQZ-!e&IMoqd*-eXYTtd4Q-Aj*L< zkIi6phUo{??}q2)J9!qReSZH)2%HD&iEw^{=2F$54g6aWmT?!v<M>=Q`W=XjS?*;C zCpeCf_HmV^yC*B#(C2XmsT&UX;Q=wG;L8cRRF(*G!hxRh?Js}4E|+%~W0+j|8UqP) zk(#OHX^Q~a$qxvlzbK`%LddO(91B3^KR|)Bp5Luu0l=ysT5Q0yM}aU}LEUaG4iEs% zSOB7C4-6$*uAzmQ*)lY+5)kJ-UIO+|PfOP)8>d+a)Z}?un5{!xLhTcUfVQ~{RZqtT zHI&B2OOS#n6qaj&EOdv%W9}s3$2+)*)3<sAhwGW+pj@JxTWNI0Wi907JHenx^n&1@ zh7~Yg0Sq45fxy9B4eI7;ge$y-PQ^%K?1KP6t3?!T%(ks6D&u0dRF3g#cQkW?ISw`5 zO<=Q;1l~<dLPUgr0mM1{IHem@DW((Ru0tntBO^c%1xyBn6njC{>SF-uA^c|kf*gum zIF?|@ZW;$y74eJ17vL^P34_uF|A;O;JcL}M?1HlrCQ%idjo@1q`q$tuUt%6Z!b=f` zLw&XSZ$JBIH$aIMJ1k_tkSG<xS;`b>2!cU!>7tPUa6@D$1+-cYK61ohGHr}L%$sV! zISzrV)PAs82kD*EdS-42WmapeI02MEHFOH%fGs2@z@Dw={<^=<pv(Fy9KwfOFwp!5 zB@mv}1*j129c3{<5-eY++@BW%fSWLV0pL%y{)^Kx|22+*&IR>IoQ>C4ab`o6*7f41 z){5ZI#~#QR1_{11Ov2Zb-4j*zE2qF77g8iFU@K|B9Nc&)FM2?eLVtn)>Y%)UmIJez zpV^b@RzORzE(Ed)@&%q$CXxHZ9D=GD^UC8(LHk)6j_^3qz?S{T;!~S1&zJ&-v?@Pu z%h}RANdW&63M^b(6Pz{+@1QzRzi{n_qTEpSawQLc$%TNuZSN6h*aM^&Et!#FY(b^} z_T>r~)He<$t#~nC<C>1|WTA}U#9#*8AhDBOBLa!%^2-Z>dy<Hp)|p?P2=nO7j}9Zf z_)j|%l{bJMm>cj<{P{wN#>lCgY8h+Ylut`U%b8EkC6UefMdt2V3|(kD({`>paJ``P zsl!VSkG$@o_olnkX61_sv<<0#q&W0Q$+XvpG`t!-WXS&Mfyk=fYJhz-rF%IR0AT-^ zNWzw9vVN%616_wvkY)wGR08lCDlr<Q_Z5K$@CgLwh!2gyPQUn<T(I=Qn7zSGdyNnT zt`|j~Z+{|x>~(SjfsYE`-Fjk{x7BzetE#hc!~-SMS|<IdD1X^w!|JM2_P^Pm1(@(X zmj%$sgZ4e4TK+6iXuv{*!J4#{xC8?KG5o3Wz8~Z>FbI6Wx8}u)+f4kgN$Z_X*`HCJ z-`Pm5|GGi@J85cMFv&lU-G~In0|quFSgXQ-z1q}RgHoZm3lt1s1m6?`EF|#fVgT&} zN({~gZ~r%KkggS>FXkku#P=p6Sl!R0$G2@xH89UAD>g16#{~v}X;v)t2UV8?!m*i8 z1F&Cl1DpP|K<x`TAr<ZUhhkEJiTpXCnIJwbkE5(MS8?wuc_anGgaY~rl=<pMIP_9R zqbh$H1=0s39=z=IeKjN)Qp^3HOMt-wk7X--Eg(bny=niNq3zg!e@rQY#+Fa{duzDa z0e9Xd6T%ZFJcFQ%qF?p`420A-3c{$|$X`$3@87k$i=vCCqX&xAZ;8m!HMaS=adU&` z^e*;NYO{Drw=mtnk1=#Nm1blOgBsLpx{zh`o~<0VXP(AF+Go~ySG5h`X*45?mR1W$ z4Y{eAZE6BI>83u};^sDm0sq=s9e~kkEc!WIs<-gfgb2#_RK*j<847Cbq~<o5g+MmY zrZEV2fp&+QvKy|JqP=7JTXUs)24E*^G5jTJC@gr;+79fUl??>0O+Z-4<N#~_gY(oE z^2~q+Z8NKKG9c*|^_02K`~r0__NZ=Fh0Y66Y3t3I9i_&KAt!~L*(dch#zs5;zT;{s z{SK7&)`n>HIsAfK*fdC9A0D900m(rLAiBFU3_OoMhjFF};HS`QnI)9w9OGT)u%P0| zR<Oc<P-$ulqbg&0M>-X8T3sK7J%Ox2`heyH^+UdvX%>w*fVDfg1VK@j)B%efj<?z$ z<H3!{w#iZEKFrIy>v@&?fA`hAzy0iz1O8yyY;_O}0$o96vI7*dGWR9b`(Ta4A5!p8 zdOkRNXFTG4oQnx?iiPmpY837gLE@s3r2X&`yu2XuByq+_A^`to)amTc)1Q*~8Ia(R z*bQqSXVA0J7AUpiUo8f>43<1JKi>v0!X%{UqlZh7aM1+sl=^seJSwMWRG`tN{`4M^ zrvif!HGtc7d0@CY4g2u)P4b5yY_}!^4pPPQYnUK!Jp`y8J{xck1;UjWh=mY@;FS1` zKOi7zEF$H2hN^#emU#g5F*3u+h=JXdoz|(Sbbz`S9a*3O@hmvszGfCEoNmCqG*INw z`{0^E-Jyi^n$+lP(?@Ke_&)qgGJznzv4P`~_<?;#41jvgG`Iu-2q)^FfIOOh4`e|8 ze}R(+1o%6-f9{eQg>Z!B69&_pxMD&^K?*GejXym_lyJEee&qi0MCgOc`^1U2WNgdL zV~z5RjWP)=4UoBObK`sALY4ebhD`Ya{7({9V1Ll2B6v}O+?Qkp#GQ#=oE>?-E%N-~ z58oX5(PM%4C8?i%{y@4(|4Uyqi5_Sk-1n;I0T@Q31vGvua2-+rlHVTqJvTs<zu6b` zvz|W?5d+YjA~iA*njb0d%76}#^^-c_74Z*N!3zxcyQUPwAt>VK2Yxa?VG`v(4F+R% zi>@CBKC<U*J>DlOkT$M+j1+<3*~=$eCOx0|b&Kw{r>n**`hzqNcou%6K|P^>l6O3) zpTwWjsNJp3r&yonnhPtm-)l6yaT{t-9^9<RAoo<Gp<;ql$6(yA^gVxH37A78pqq7s zD3HTY1BM_7sqfbmg4m=*gL)Sj{N|=##xK)|q;cF{EeHM>1KnVN1(53(|3(`;3qV(? zc(<!6{Nf*6RwzKreck}@?zp!)g^&6UnfuSw?C3iA|61_^M5fM;Em<+Dz~&e5^*~(O z4J%a0Yvdzil0a8e?+uGJqESm=%+|UXxf0j?_CnBKxk6<E46^gxTm)Q%d<*=M^J|+H zC?60C)Cyme`4EVmfwF<ki<=Cab<A&PRC|I)8va`IBF9C7A4Iz{t{IH$0H(o118}?S zxx0Mka4pQJ{|rKh$rKy;W>x&Ikr-BoA0p^VadyLL`3{8-*Dz8h9|kZ}>pHuQdU6k0 zUu(?(ew<rhYT1{Y_0!CiWE30G-xZ`s2Y7*z&WZwpb__5ghp2H;)t4yQN%irW<-Wxa zz!uGBR_egUF%l!3EE9oiKQ~tZ=e`HI{LW0q^{5}f=0?+!*rHehW<{*H7q{>$d7Gfb zU7bXKhPv7!0S2MRi1f?3cQJvXiX~hP4*DY@K<-WS!7&)v#^fqDq=*99br9-{NnbFT zK&80&jK)uYLAL|}0nI#c2?Ja5OOuAgBAmyNWeaVM2b!;zPO|pHk^V4A>T|uQHEdc_ zfUEQMtISpjkCZSbLSrCvqhpCcw2QDze{WH6<ojtMsFZPmS<7bWHbWpu9Z(JZ$Vx!a zoS_0AT({Q9ks8)`jQReKdkl>=EHDAWS~-yfSi$qPOvgWpmTiY~xt@@f&dH#}S5|_b zicS)}=b+Emg_wx+qovpWbI^2aER^{Ua2MrFwhA@_#eVDozw8f|-PFPWf{_FW(BJXT z4dM~oLCJ;&R>tBeXp0X(aE}{74zfJy-^W!S;Z@iJ(kKaAdbn4|Cd~!13LFF984tt| zy4NYLX#7J>JXV*h=r`Quzve6v2YU$y5}25tfn{IM39|QLBF*tG6$nqbA?goALue@T z;{@kwQ?x;fD&fUn*sDoJLS;`jP#j=@<}XbiiQlM3oPFsTu9oj&F$ln3An!Q?!gH*D zSPeHtx!28|rLPu%)9t7C#Bu@B1Hy>;Ne1#nN_Xr(HfBeJ+Px(*d)4FjR0FxV`mP%Q z4}ValeGcRD4-N1+gMZ)X_tN|o2y~vlbN$~K?5cm2`3~6;{v8h>0HC$0_E-l%c)4<Z zQAGz9U#JPP1oxGx%ZJR;$`Kr4rR|!=_qer#e=2;H`-1<%)xbYRyI8<1hAxg?F*K>Q z?H7-*Y87Tb)qdjIpt6BmD>d4A_w2-?-1!MFtVrtI8*IU`|9<FpDt)V?Z!dkm?FePP z)%QcSao?4_!9(*CZu`yFSTP^N^rr@ZyN~kmo+}XiGN1e(Q~*MNM$e5rrM`QZkNX+R zyB;XEhur3~gXEvN(+$ua+Be>S_LBH7_5CdJR9pO02cMX;_)nLw1e$y5a(-nBeH+k! zh<KmU`}tn--zb3mdp!G%X3o#`pc@<BihZZtzvUVN4BfqOpF?*IEo!el29A%?-Mgnw z0FldsHPrWJ@#j;ld+EMBx0y_tZ+n%~i-iJj*pvZJ<}cO|ct{O_j1NH6Z^tOmCZhW{ zGk>PNFYq0DO&TykpLD((rg%fpZ<O^8N(m5X6AO?DZ%IA`eJ9CV%wKZ@Y&-$*ZlOMJ z05eLwx&Z7j?E)HE1d>shyMad10hVVdu#Z0O=KwX)xzEY+O8PmaUUj~Q+%c=)o3n^f zzy6V!2#`Zf9dTov8#S2G^$n0r_J$L9%>|wqFjKeZCGR<BFAhU69iP9e)?Is9t=771 z)&X$#>rCG9Evw+2XAn~54qjWS4p8SUS5D9kQJNV5uoWPv7lIQHTpRczkB9KJEMsVo z73F{<JR5`)+!cC=Qvc48@)vRedSZrcuJ3V&6oMA+!UX@h!ME(Lr&}5#H?NyEuL(l5 zR4~?~Q3BQ<K%g*4;_n`{6AD~cx_$(qY%BJFz!b=~Y#+0Mg;SUXew|G<tyzpF&@a|9 z5ON%-IW<wyV-x1gJ075NS9f!=0TTt}L<rAS=t}sX=O!p3paZOVo!+zpM?rA!S$k7m zm2F{M4Synl%Ipo&-kC>?<qqCTJ>bfo9<D&@*BB)z2zR7w($oNX>?-HafWRGxlbjep ziR@}^#0WJWAPDFb><$_c9ChH%+><KYLA0&>Ky=YZ)`c7ktlSV!I?t`lZNHiC6sQ89 zpil(=67qsh@yK%H6wP_*$9A6V9zfL}?ipzdOUZap_AibIr1F`brSIH=xSDRwFQ_lP z8H*l3{nI~w_mVKOG#KAkjtt+oeM5b@^7s={1;1YA-&4=$WqDTnNX`M_=>h~xHRfnw z)SrS_(tr@0J4mV*1otQ^kFhRnF5-DZslp`|th<E|f@RJI@1l2Vb%o32+jp)LOW@v= z_5NHR^W`h`Ob@@^aA&&rOtzO+5T{AZ1m_vZ=<cZ!dtKQqV*xhV2laq=fxako?@E5a z*A7wr!v_FdW&4Jzco(j_W5BcD!Kcnbr?sO5@Hii{DbVR4U~#8y#{m7o%sTYu0AL{$ zoOL&K0|DSe6!v+l*yG?_Veq-WL>TN#@{qrhH`HE-Q4cd!Oi!M@z#jcQC3|Urs#(w- zViPI;jVb&K-*Psl$D`E;Df9<5cT=Q0C}&bYO2r3*4c0gE&kL0P=_%y|`(6mGuyXxk zzPJI_JV(#v^RS8IGPc1Brpj?|%3hpXGlGdk$9A&L6Qc=h8o4sp?TkpT-%;PQaP;z# z-6qs;{zf4`Kd@=<#9>u|2a3Bgi>v27l>A~mrMv+0W{^@F`6I8-4|Jo`|7HWly{!1p zH)zlNQdgTh_>KYk4|}VpSIJ+$8+Tu|ePgWn{&C>bHnRCo<UfjBAP~-9EPDWo@cH(8 zgH-g$_M@=ni-#h@w@or+ztU>E%&G4l^GKqh_sZ)s?@|64BXqCo_|DcnuEziMs&Q{F z-b{3V`K65NOsxCGY&&6oaZH$(7=J5OyW#wVwPR+7Jj|z)ufM(DVSBWAxPW_%75Xar zzfqTuWdH!nMNapF`^xYOt{Kte;`~+S=9?U^5_>>45B0x4xbNXPAgjkE`@Q@zXa~>l zgBy4mey6-^wMk&s%kaC5zJqSp^ry8O-0|=zZ-|h&>8kNPJjY@mV9=YKU#zshY3iO_ zFP$CJpP4}N-7_yzVE4GCD3Jve#JAO<KvJvl6PKGHpTq#8jK;P;Rr8su=F{?v*TDsD zX!Sz~2wsc2%3a{?x$%c~t=r7HmjJFGqjPvZ>M_dxYgH=#f9DJMb-5V(&RX|w0NQd{ z@(#PXdG}kJdnK$B5X_A%KmAV8d~UEy0({>N-*tC2{$r-hqfdUNmH_JRc3A*D`1H}{ z$uqfum;s4FPt#Zbvrf30F+a**r|Kp6!f6Db)q>QGL=oKa;N|+S@4SQGuYAYGYx!Xo zx{(h->`M7S*6^e0@bpy)3+!GOdN@#jdmjj16j>Ue*vnF3PJZ5oBWoIf(ARVR1@%na zllKh~Kmbr1pK0*44+v|YrZl&9K~(ry(}5~)CHSm0uPC(Hdw{I@9?<m?XdmmSH;mSh zASeWlcpviD8MU%hcf@z<@IeFhez=3W>HxnPoF&<x2N`Iqm0n7`J3}Ia4KrfpOr`rR z7JwG-A*wa>sjbdf0Lg$-3Uj&QZV@OeilvO(0A;-J$<o_d@0xB!H%BO&-$?d@Y<Fk` zDS967F#-3&{_+vB?7?Gx;F~mGz{wvs!<tO{*FzKwK-HI~!U;DFATV<wPD@ZIx}a&2 zB0HfCoX&Y*xycXGCTb5qQv!Ya$G>~*x3g_Du>^AjbQ8PjE@35Ws%O$|t_G)h4#4ZH zm8b4QDm8k%0kq*ab+B{o(fDmnfYkCllzPwUhcy(*5Fbp}V9<*CyrJn9n&ZX}W<$bi zS?x&WTPdSspJlyofn}sm+?r3v!Bd0+I|S`==;Z~Fw9{cgnizoz^Inso1An-$E8Z=@ zcV^~oG7gZ}?OHS29eDd4{K)1q5jM`Zb&+`K(nWWam%BBVtXbbGaNEUOP^WM5j(Hlp zuha9sau8Y~4R29uH#G=!TQSwmStn-yfwXi9=p{4a_-|>R@Y#>q1FT!D0ncHwcNJ~= zYgnBi!5Qqn0*@<B3%}fVA-=lwMyLw6ZOVBk#-CWTOjR{5JH2&Qmlv)MPKnP8j-UiL z7+)sQeH_Q>?B6-IkOdi!?M&nZ?em;@_41>`hkNkp_w(PB%5qxwuZ&g{pT7Ra_v*Ja z>^Sp@li!~@{9&{ZgzmPI+uQhj>x~<w4W2Szo&C`GM~WMoq@risE%0Syl)o{B+@2H6 zzZLihCtsL-<iRRc^Pf}A8)pB;!)yo8hS_N82jVLw|A%6r?`rT7FpCRAsoBk5=d7g% z;v2p<21Vbp_;VJ+C?wkdN_XJcmbGIZ2~TMbzZ$yl`4bb&P@jtx-i<@<8|^+mTQmOb z&c@DG>$G>>bd<;{vXd#tTM^ukSjJBIH!J2h6TsIDAFI6^J6%U!HywHEoHM*n#-Bet za9WQ|_Hntm*ycjX_vuq-crtrir3L3a?R<_&_7=ATVtEP7^)|nx#*!Z>vvaBy(q3Fn zK0K#7%bdlL20}dj@gS<_)3f~10EqAJ)*sNjM~Y7Vd9K9w^bF{Qs^fmkox`r8pP7(L zUp?AEIVi5Bqos~}dc6tk;pN^@hWlM|>bn!^;RGh952({6&D)xf2H2*s!zkLP;=+64 zcTKWNePR9zPaAMGzohg>BUbQUbcOZoVD&kA^g&|D0-i2E%J0#8rx3Ul7s!lcKPEIa zx!sr1QO(C%b*?I0Xg%D^;d5e@s(1?g89Vk_xepcj_b563t9j1&_vCwo{>$YXECCo2 zXont%4EJkv$U`OAy^jef!t%C<QRwHUQt#Kg9G}?_K>I}w%JR?1o!^ym=RI$|mf2C> zNM(VrY>j@%_;SemRs4pg5oEt4yW0q4b=L#*nsXeR;ZMoTdPj8rrEr}I(4^%xT?qGI zdHTR0O~*+xC^a{q(Z(VI^RnOwEX$y^2P9YPWB@o0PH{DLq~;8a_f2&x$OnJeVo5o` zo6&txgK0DZl1&S2cDK3pTP`=qI~ohYy>?9jJh{c$?-MON-!b$B1>)%JvwT4il7L>o z^U(9*EM)m9|83YnRTV`ul{~We({3GtS{FU!iRzr2reOolKe$!#X~XzwA%_3R2(XGD z0wVK(Ux07Jy(sFza_I}w3krz{%xF-U&a?Q3ZX&O@P({C!8*mRiYE$-}Q2@`bxb>cA z0l?6Y{_4McwnD2tdw^XDxTz{<okUg61mevs2lF)ZPd)OdL2p&%WI<-5GY`n#S$&-z zS6jvn0%fx#n`h)Kil<<9W_lLIxChf#(3?V?l!3&p9{!9Fvx9}c;H5DDw0D~xC<z?l z0EJ!?a>fT-xZVtFq<c*5h8hOu82Yn7k&DSo7U%IQtcA^x6LAVYy54#7#Oq>`I30U& z0C~wZ&r_F9&udv4uHdCOEeD_+o;mOSS&G#4F?jE6Veqn+Cy=AgL>_>=v@|$ld`l$l z@j<xSF@Of8sh6jzmUf$}wKr8#d=rTrc#Jq)Uh4D_1MKp_<l0cyQ<>^3E1d>A#Q7V6 z9IRejQ<|;RT#5{J?_>ZO^!BXuoYfN~+{<mxbjo^QVR-rIh~YRgz~Ks7>Rmm~Okm{l zY_rmvX`|DpykZsN<m)liJ6#<<nm>T<vpt2Chwo?h&g~tEMKsrCS3h8>xXS$@;&DRB zR98|re1DE#TmSjSTQu0wV-L7ezgx3?Y@__o_QVdk4Hf%_zfb`-sww~3FnydFJ%-3u znp@m%>+vrKfV5y<0A7vjK5ynX%J7d0QQBYd&mK#<eP8?GROEGq;U%@JV&3MqPbv5| zM`gOh>?B}3T<3b^zfpFFkF`zlWpuz-F*yYDPH%QEDLA`OVDH=L>U>w#Y&ttl@SQ?W zX7@Vl+vVtZmf#r|+=pk&(8tF03H5zL+#$6x^j0@}NbTw513=w{-+)@v;nf~j<#cox zjQ1MqM-^yf?-Y(H9B0M4tx)LF@*2J84ck$T?V9Y-%uPL4)oxFBR|A3Q16GWaojYgv zc&+%%BDY$A7EY9YZa36?Kbz`DV|z?L&oDJ!Q}^6WxYTdAv!Of^xZT|(<lB|=lWTY< zh2(8lzL$hQ#Q7?qbyg4SEA?>}_tGOlTa5U9xzxsJ=rP+I0->HhT_o|Gy1WNKmsnoD z$=C0#`>t=tz6eu#tPmHp_XLB#YdrAO>8tt0Tccf5kEVdta@bE>0e{cAZm<3p1;|Bh z2YzoVRItwE`xzF^TdFq--N{G+(E}h{hNWZyL-uoYFoM}kKWW)FE8t20mh01MwS(8y z>%pwngjDebZ-yk_9a%cAWhZEZERNak1aGx=GYOc{cHXob4Fq;Wh}G~NOX*ReoJEV) z48wG+_f}VTTU3u#7*O!7W6e6=WRJ(pdehv!764DxM=3WiI!_ro0MmOBVsTo#he-Xr zEcx?-XcjLrhg<V?6$==^DQa(5kibHFQXLG)&qU+iqbopGzti}e7`V6Ff^=Z7XN{}M zR`9^h!{Hu$O)6w&9{|UBopJ-5+#T0Fx01D|1>H|8YdD1TUH4K61WnTHt9WtmjjJk0 zIw+@*cMCB-OJ!|MfLf@6qT9*#c9QOYqiRogLh7YJ;lz9Pfs|c8di-xcD`0Mp&8`7H zrJ8HB4P9*3<?aR9^M)qjWD|4)OF5;SA$<aGmEb0EYp$PQ9=~~BWY#(=-i8Kbc2)1X zkplCm)k4rRDt;;CvFuq3QogQ|#EvoF)5k*2Jc%0pWA?^C*kIj(C=Zg++^66>MmB^2 zz!s#tNIVqd)J&XloPOr~f8-2!Pf$<Kb-3+a>UrS6wNv4l$nSFS%Fy*lS06lAH<r@Q zkU@*E`;Vr>?Ug_al;92;*}DR#(sw>(xZSejh42T%_&3sO-uL6mt8Mw&GOX=ZE4rPE zP9iNq&1{hdde{7N-0AC4OmWrh`;Xa7JVNa{t`wY2$#H>q-PPsa-pEMJL|@kp_beZh zQ`vID9P~W`=ZO=zQA9%eFo)$^P5{P~>`^_HjyLpjLU1GN>)Up4B>b!axx90MbriGw zY){cF4D!uZsw*~+x}MFNLDc9j4xfnhuDZND9Lam?@VK0(RQN`=d~cM4?~{UW+avh4 zn)rL8$ey+AO<U4Es`FKCjI#};*Zd84sDF>0<F4WyHa7ij_}#6s()wkk=RVS&dxD)! zo_g+T?B|d7y{e!avvLihyRv6)x8hz(xw}pfZDx48<aE32B$p{4H-fY84W8|#T0dEN zyl+cj(<`TP-&}GRskdE#wg9#<rmK5kt0{L*KHtqLO1QZi+N$L{XlUziYFh@5TdZvk z({C5|7u?a}#cFDsgB(8)v6mGr^K)yIpaV8-n!c;8V~}o`=o;EhYWFj6-<ZKaVEo;H zxciMJ_yCif;9G3kjpB3_u8y`@y0K|FuA)D!0lieag6D_Tt>($|fU=L-AihIjzw3=I zd6Uv%30{&d=BDFV1N|P3Qv*-%bpb*3j#sO+OI0=UyVf<fwsa=!>Is)A!q1FT@-0(V zH@diw${E&o)*qQeo@bXEx+^#@->w(;cKLXzTmCybciP7sfhBOu9uvfuXXHKxrXpPf z<TAz;zvmY)Ebn?i;Wv*<0JC7YmD?(q)ym&NWuHHcxBnY;+KuA|u2<eZVtrFtTMOMY zf!kewT-%*vL#(|9yST_-mqhB}1I6vZnml>v`OC@U{Wp4>?M8;?Dyw9)^TK1VNdri| zbz81==)Z&w;3@E34|Hdht?*=h{ZK{t{2k%$tXs(3`))gp^Gc{|!cOa@sf_Ef$vNK0 zo1EEJK|38-fq6t<D|Kndw-VLVb&JF^Gmes7OhC1|^l!$|sjyBG)Y0xu1g*dCUTADF zcumREMX(4?bL$e4a6<;S);AvSI^;E#j<ueh?><p!IM(S?&$<`H-@wXARKXeqOml#n zL02m`z%PzLV5@qALtzN@e*PV8p3Xmw^r4YIOG*4fdl5UyhVZrQBFK*DP1Q~0pralS z!LZn19f`uZ-=O+h85S4`O2?x|q?=s9sbuV!(?{B$W3x!mDc@fNjbSQ^$O_)LMC#Rl zc<(<4Wl(Y3QatfsSzPVru0cRANjCm%TOCXti<8Yi`M=qkme+Io7HZ|w%{EFuBw$m; zOi9gz+)65TK{mxHcMyPr-3+_a6gv~IiP1MS?0So6I}fAIMKb3z^)5hNG)oG%T|8Pa zADQ)3+y;Q%)xHg`c6K4SpMuQw@snL<egmyyThvIOr3QLSwG%kA6uxhw^CoIVH;LX= z*D<&ja+mGFz%TOsa0T1eKh7&qcawO>`>x>&eR7Qri_pIn*FbqavM4lR75!$@LMii> zrc)RD=Jw7^xA{f}OFB|zN2cY<{q_`cp*apWI*m$k2Guy*+eXv~=Vf?XY|UlfR$F+@ z(ruL3UJX7>vN>~QD8h-V{Zcop_@I;GS#9i~x0Lpspm!=_dOam~u3(=t6hvb_jg!-{ zz16M85p?uS0GqHIxL$ECzziB(ZkuUSac+|?>QobZv!|AGY!<gTwYl-^GY29RuNRug zu6<N+PZfwr8LeGgzK0D?9jtmfm9}#!=?LgoK+;#!mc03Byfeh-JnAg+mDinIjsSjl z@NJiZ1Dj(T2<TvQ3~W6d_DXeX=B?M~-!p&*0M>6x2DhjFrFvR^d=U}03qw=eUNEg( z%%U}cLAIV~9;?S^#I6rTR?SHG_NwgJGqzh{O$DvmTTN$vcNqyc!sRx{R)gqVo?SU{ zO^pGksm^Va3*}cYkGJ+PH*CfXZ8keqWKU<J4VAUmi{@=E^Rj5pyGC($1v!Z752Q6J zP+^a73*<O(_EPCqIa68R-D@KG|FQJ;!tRF7UNFsbxBWHwTwmINSi38kf%NBPc@u_{ z(XApqLymc!%3>;Cwr)(g{Ta4fvl>lrrjmp7q|g2J`MfUow!YUt9*|8}#EsiOT<_4^ zTQ#^*;(XbUwHlwq@h5{(n`(n0&O4X$RIj=Q+ViVaAxki~b~j77Ww@R>uZ?VnQgB7{ zsnFF<2H3R#$volJP>OQtx>%F}7VjMgk!z~p8`rJeruzQCO|r2S2VL^bs&<bG@G@1d z1uj-pTh*@eIY&M1Jg&pu(cwPrZ|2lnA$`C?bzp6uChrQv?F;iaq6O|NTQ!n|i+41N zx%@#vIFW-JFnwphE6@j}q>!YO!Y<|gsd3b7uR$29^aXDJxUwrKS~4?$I65f5=Q9h? z%Nw>fE;ljnYANyZV27sBs9IfY>G(^5!%3IHC30O1-ce2+WKwA>cb(E!v+6CKCjA~@ z{x3pQy7O)D%$=E<vWfexm1eNAseNUPtJhxoIXKTp0p-;)5^2C=OQ*T)>f57KR!VIG zNGo`hFWo_S9(kUXe~HDtH|DmU&n!vy8Mhy)=>P=dq}AKpz|!DQiQ;|(S)8sWRmTE} zIYU{hWV_S5oybk9Tr>9S`R2-@>#3DS3c@47a6@wx`g)FQ5kRu)snIw}|FB!yN9Oi+ zS_W+x5XXH;_jrIywEaNkY{Neu{_$_)`zS1{)`7G2>|wPVA6~)S)5EA}$2OyVtNe9k zIM7(%(d;C2wW`HYo#KP5LiPsfe^ung$q2N?D(;U2_3CyrIXt10_?%150fm#3Kt#%R z)zAd(>}m^+b2V2{mJi}T6MD`7Or3^I&3}=xSh$Jf>NVFHU8&xcf>;I3(F085K3&fr z^W2+pQ`cAycPU#GFQzcmDeVl4mv*mH5y1z+Lv~?Z%b8}}@Qwa;bb5LX_C&jcX@FW) z^oBysjL~Pb?Fp5_Y<+eGcGS7v`)$^|soAQ!YcJ1;YXX8tY#^<<@`JOKu>Hcgi=bm@ z-)beb2hvQJU%Mf3AYeCW5Dl=6Fiya2hERA(f7#6WVaCg%f(NIlDn|vcClY6-Hi0!2 z&&PKrj->OAJR9uNgz*>XRntrv$>cF%JS+sSEOIb>#V@BRupbD=KSj-IiaA30^Dhf? z9n>25Ug~qwx2fVd+@1Rk;K`|(mX2Uvoh|V7@!d8i{pvn1Qr>c3wI$F_KJN-`5Z73N zF2YQgOYNu5Xc=>W-ybaRucaxRt=CMbo@a&sn~UA`w_TkCaxXnFBz&pGFTuN)|D?Gm zz9_tQOa@8w`p8Sw;guKa1kKEb8CVs22{cM*D}^UvR7YL@e6H7Brg1T*f9Koe7`JIN z=v^@!^RL7G!{nuJdnGb8c1f&F3~WZ~c8KmRZYMw{&Ne_R|I0PDca_2TU$nB7Sy#}U zp7p<Qd_cMEjfU|GYq`-(qqiaR{$LsD*)hEKL*?G&7^}d)p`_PzNwR-ZO8RiGecT$( zb;)ynf-PZ@*IdrNw2yPhvUSajmFHXboojq2W|D)>Zj?(+SIQ%i?EC?lwiSNE_huIt z`?O35yR}*M^Qhd%Bp-k5zXQ=SQ`6Ng7Wl#?;;6a7ytX>(b1LD)P>P#mH!YC3jt=t$ zR@N7WG6<!8A=^9CYHv4>ZZE%-kljn6i|U|V*Cb08&nkOTeeAkJH|e!0a<~t|I97ni z=8|X3PgV$B^?ArpHrl2rx))MYH+vBHmm)9(&)m(e33SLR=kM>}wdL#d-3Z0CAe%OV zz2&b2ED?|OeGX5cJy`t~9q`Tycvy!-4O$w@)}}aHp1-prllAf)g>fri$t>R)IBVF0 zuHIBi_m^8CM~!OMUrntD2tTPQ?;M)vmVU97_vo_XTw?Dam*v<%&pR`lxiHS<<tMt9 zba((w-`;99n{DQe){Ze{8|?339-kJ+lV2^@o=6#WHYn=_(>Ou4wT*!T*R`9u^MLDO z#mO#BBx&vnaSCncGAG$M;P)`2J&7G7-UidRMhB~0x0IYh^se`;%I4H|_yW6)s_{sK z<Z~$x2EV!x_j(~ZfMw%g4;)wfyHWwXB2)VU;X-w-X?~56-{tCWy%!a@bmAY*{^y|o z`Zc90gWmX8S&AJ!8YFCnfC<NG=29JNqvE>K)8mBX6uBei-xyGX*Q`=gJqW0-1>l90 zBO6<|L%d?!9_C3+w;r(AgnHs-n}JbeXO+XG&lF!bx7#MQ(TdL7IJta7ST9mXu{>C7 z&@u*w3z_<q<l^M-8SsO$uBVFt9I#s`Z0|e0Nz1}CV||k)hkFRanJA+bW-MH8jq7np z-Zmwk*JZvuLt)h!-a<P#DeQDLU6Bs2>2~$870F@hVWq{XiWMBsE8TK758eA1Xr~5m zzaQ*zwQ4zY+YD=e;+v(%Ra;BrHXL{D-YTneR?jd|TpGGpOM94}J1-ac+qv4{v+Dy> zwT<LG2xPajC4cKg=F6(OR{hOCv(*+p#k6fZY5{Tt@k$!U_@kWHRNok0HgUDgltAGR z`8e7|&-xMECdhBh&6_wTe7Dn|o4Qm|BS{-%j<<?B)k^Dz?~Uqo>i3(ErsH(W;1<rZ zanb>}EMs4)-ujWlWJ|9pA8z2RbH4%3-bG5T$H3VExrl+`w_e6GwN<ba7Vm4_W12jb zvmZCJD4Lw?>;aYYj{_}D!S|`I4XooEh@_d@o!havtq}=-`2M>>b%_$TElFlsvsEr4 zzV+aFYUe2~%FP;aw%|Q!G%DL=4wW1I>e@AA1G*Bn^BtONk+>LEOKtWl@s^4;c7jFJ zyj0jX+P}_w{o`)ryYS2!u?INJrbp|l^Ip@K-wEc4+yhSa8n|$lz3y)l!5!ERaKQh} z!M64>jA=Q;17X=Ta8=ohXzX%UI)@z?qkO9=tg0W$ne-yKg(FadYa-0~0jm1&15Fs= zG)v7)NCBU}F%af&sfKO%i`nJeLv^7;+OGdbKHR@6fH_UIb_aW?@FhA|)kM3jF%1l6 zY^4R+SfW$aWmLUr{w$bJ!ihp~AtJ>-RyR-xewqtz-CH0#^(#R$b%n_d$EH4>ONwo+ z-S+I0LABFZ2l)eluj*4yG_0iTjd($IYGXnAZwzdyX3ZZjn*XsS(sHx()_*+~5Bwri zVshkTBd|*)sHAFX%Q%hA9$6;09U0yV_ya{|gagg@yyY9=h?tQ<nr6d&5eyvDkXt@h zsrPbbg(}%5$9;2{PjPtTR=hXa7y4LbIzz?{xHn!~I~EPrV;zI?rtvp+{*cUYxh9@d zB+_<<S#85;sGPMTo<HD){Q4RCzEvXIvN5>Vh~jwQ7NT~&>p0YxCR8CF4->jtkWJvI zrZ<rQroNNqrY@fCLnkop0NTdivuGaq^Q&&+t1X>}iC$}CT4%Fd9KmhiU7<7qb*VYj z=>yGiTd_q`-<(HIZXOab=ph!wiKXduZBv%!wbAyia@mF5NYx30<9-qfFpAdk7@I@; z|1<VJz){|Jnx_z;V2m7a8e49U_mEuDcH0(3<A!)~W&+6Vv|198S~#{fYz;^;r6$3J zW`=ljQ`vwGGH#2EKn;<F*@$+lLD+HPq@7c0_ijBH$q5OymIOYBP<t`XWXH^`uae2s zU3|0I`#j&@?`?@Bb#+x!Hgv!J_S@~u`}FhY`+Su@H)L*Huzkz~Z_;W60_sCV^6V#s zr{e_FLz2}0_;!Ks%KzT=)vtfu7RWm(+xEmUk>v)n-d=p~zTAXpt|Q#g%v+fuGfP?m z%W|H~%gdet@i(&#MSNPiG=w;L!qeuP4}yYU4;`@KW>6m%%|<+Sr#rmVdiK&pp_1Qq z6ZvD4dn^v80<~UV^r|J)sF*Ry+g7ucaEoE+AT_@zq+B}!uajL89P?M{?}XzN5BHgH znDTR~UTKUFMZ*QRWpK8m4JZB2pR8~60`}EPih+RQK+tCFD%*PLdzSMSsE&Vev9p)s zxvk%O5LsKWO%NRTWSmP1whZIrQ}q(O?HRq)K$-|R7z<+-<#r%VJDMfHd1{mLWr)(8 z3bOlM2ett!BTV~@IPVzb%Q)EQ&`$U%FvZ9mdbcsiMX|eLY_D;uO@(zia-uAj4|ubF zP<Y<Vm=_^%gK0O{9WV7mwzWt8v1GT!xjz4+fFt*wDx<H7*wAO7aL`~g|6&xM_x@g^ z(H^?ve+hO6!85Qs0V8G-+avWmrkF29G3O~rZa(M0wv7B9j~&AXk0T6{@s>8K1^Qw@ zGoTH2JNElmGN6gSaTVX~y%DqboY^_u6TDo<BqHN_#2@^cK2>h(cOMI=cImPAQklh( z!tUGR*#XMbH3Qa(?(IY1;>F=(@N1E1vfxhN76L!E6+CkKwr00%70aRQ7nXXmD?@ou zvs>c5qUZCxWuwz&v=(re<6;l}eq78&&n$&@L*8uOtGs-DgVOEkw#B{cqK3<IzmJqH zWoHY|+Jgd2>ss*`O9y+6eSi$|wj61>vjopR<3nGB)u>&GlR%pX%Zyp+Gef3%8xO(% zK~Zu8$BgB~l<6+dfCVPC3!BBWLwpaf#)ILmKlfAMVW_mxU9deqb!{X;$(agW>dJX= z8}3rDtW2Cexqf5{En6g5eQV5Q_Za9=AcKoMe0pZZBf{E#%}krx4KoD?QH0s%;u71S zu-G>!3)(9FmF_fK{3D?+zXLupS2?I#3oA?p&c+CUN$KX_i#Wd94QX4ioTbTaHH_)n zI!v)Kqq~fTd)VAA02j9g@!uVV@p84$*|+-m0Wdte+C|J_S5qmSNjm+d9FBFCUk9Yq zb(KWOhYP3Eoi#aoA#5C|-nh*ad_HSIXJcdt;D?HvW8Q;p-pex3dXww<VS%AdO1+s$ zBl+5I>p-|&YzrOUJXpVQBDeGS)6so98C$m*X92aD-RCTu&bHb2V5y@<dM}2wppNw} zgvnUnF14G6)SF?O<fg54MV>S~9IO>nw`94WK7*xtiJBqwF4o#BqwdsjU{z8#g*3{j z?E^XQ7*$a_K+irnZHLLpW@ek6ROOw-x9=cL?no>!ec!?}q`?l@JefRc0^}B8S9F_3 zc$<$y-1ighaAi_!KrMf$U~-I3cqCCy{DLLQRPnORZ;+Kbes$*UTIjPYWVI+8^I}}j z_CLNir0mph&wlzxC!RyvCJOFmuWvH0ya|h#uh~_vgUwW{(205o<Yd)5a(58Y?gl{f zUniZ`&x2^qwQ{xPBr6z(^{eTuNCQDK7xN~sg_yh~Wpw;zTx3SOl-+)q-WJK*mTD7e z=Y&MiG*0b+7k~x&d0V_=aqFP=%!b90y)~!Bdy?Je0I2nZsPZyMzaBUkfp4d-eKFRO zSouke<j||qoyWh(&%2J!JxfJ+^^eyM@?VjERw>Pm+c5TRJYA@+pOF@WroVJvq8kvM z8`N_Ax2$7JvKB~_zXoX?^9>r(k*X&R)uT~2bM5)Clx{R?!L~Y6oXZ@f#um_5YF={{ zjVs~E=sRsBzIdc^Fqp``asFDN@JS*3F|lW`Rfcm=qIyScRHF3&^{P~-{V-S0;P#G& zc*Fu<7r*Y@WTU2z&tAD(5LVW#0o%Njmc?G(A^&CGA)24QL4CgQknhex_NUTW^RMSf zcD5rKO_;}Q!&+Cox=q3h%v3PUyk>Fhz&$Q=VEC=Sm>a3@+86I>%fH3%hncLnu-;Pf zFn_*ROy$mPJ(2jE>(K+92dk4xfDPQ^a@w7^zLx`BovoQ0vl1IMI(t7L9amwBve`S- zW-_N^TmI|wq{s{I*tL!Yn;;zYrMc!4y)4*vM&?^>WuDIlqt-UEHGiV&_gV1Vt4wG1 z0j|=VB3&$t-}3@qernoSv?in_sW)_)9~{m&#oCI?9|=fww;RKf3;f8BY^a)-u!q&X z&k5C|pW{x?)687|O-TKvb>ku7w|=ZxtC>B<Y2ez5klS#w&1UhK0L{j$`A*y{G+}Ui zGe5WGOkQ=9I8cW63JBLqC!VnZY4<vQ3ApN0EneXuPD-FFwj~a`Ewa|-^t46Kl8i=) zlCvD`PX+;Jqr0G;v1UP|Vq=0m;E$=T0GjD$bs%?g$_B2Xr-Dlmn<ekjfV5_N^yr}i zl-9!K{wM(0s#L^>8N&7owS(GA-H_1+-<^WXogbdUk<O;7;v9;veLIz_?@GPC+R>uR z=@pDl8Q+EBLf$o2rc2U9mn3uElRTO`G~Hf_G(h`{kzcSimN0YrIlG*VA2xvPofFmE z)4TT*DaXv7$mOoLcGmC>qPlMb^}%q?$jfp#)Ht7zc%IzAgm{X3_L@&HEmdcJ>%~>- zYFB}|$;nEA`K_bsVu32UvFPVz56e*26t{(`eVANK6q>8fl8B9wL0Uf@rxIQXbnf6N z+7iA2Z{wb{!5|pJOYw49ce2?+TqZ+{s4A0H($Z8jtVO50%oDy>Zgp=kepR%+b2%(z zH^a>emUcvU81bUju2D_J@MOLDabROw{t}jM1MUx^Nm~o6rO@uz@K*ZUF1+pFo+_B+ z$F~T^`u^<lzy8gxIE0b0r<LcxFUN7mCZ$Ug`dY$QDUg--qA{%~-!xm%qWA>Ycujj` zIgv3orlC!XAX{8I5n<w4@#jYPDo?UUE$Bj#nyv8nC@S)+wHUWspuPYv$JSCsrvKHr zQu1iu#sflfvza?K@*|F3GG1H(kHt;46gZ}IZs|i;Q%Y`CavIuCL-dLf@-E3lmh4<o zx*P~=lLkz+=T4iD%4biAj+(MO_U+p-U<2tHjJ4pk%www@(~y*GW5Y~^xX_?oh)Xte zxsgl_WC~k1)*CQ;;%ksy5%+m77un)@Oj{eIl2Yxqli?+w_xnhU11A7i8PUFuTm;*u zu&6Avo>Q0oIv*D{o8Nmvo6BIYswJ}$GaTh=%V_(k*C<O#7^da|dm04E)?jKd%zEIS zT2F89c%|JT*Rm^-J!3SR0CS1ZdsKZQ`F5!4<es)`52Ul3@Nloxsk0P<DJG0btRu{8 z#tHsil=cR2%lh9%=>US!u73x}8>R!TS!}m0ls^S98tpYbx}z<0JpfTD%e)%(8RY$F z56vjXaUsonTh^1>R=-KXpjctAckcVEvCwo%P@Lr~@1?(R+XLx;#>)=9@CwZ*pBF|J z$!tj}HfX(!RoY+BfD_P4@H#zWa`oM?V$slE^LooUYz;GawgR}`_GN6DmzkG4Z$!#7 zVViq$QZj45$V=lqdsVsISF%PyuRla-=RkDc+>|>sIWN35lK8g)9>Z>%gZ?q6YHMt| zZS5amw{yJI;@WP`$x2KNG9kY*mC<FDyvB4TZp9w*8oI>=qea=mAYD^1ekF<5Ww%sk z{%R1olEhqR8Ei_)Hs8}~%gk#sR$Pj~G84$fz}~O;H2`)~25LdAC3$sx@{asEH;z3( zm|NO18hG<(&3T=WXsf~HnH6};GNbj3koAJwgXRXaEce}JI5#{sve`AGD29~|!#_c8 zwU^agz|Pf6nQA^$H|!E)rbUwq1Ca)3Dg*m1o|S*$QKhF3m?i5nW2FNw=nV(v;DhpS z)mH|u{3vA;)({Tj-zKt4f@T^@7ml&ads!qbkdU`)c<T&x=UF+&)}wkJ7LF9XA-j5^ zIJSe}0daVQ#bI|z5aFXQCa6g-BQR;8iX8WDJDdTon+NztH%GsA&0zUsnzhb9zwe4} z$pfu(s<r=Fl6YgY;=_pP`QzED^@i?1G9PdBDYj<ES{LE?#{7iR%rCUMQ{860qfO&< zqqtU1@=`)88%-wW<;>R+d{&!dvfi-UG*?B@*TA%frbSg51hcAk@nGBE;z;Ek6h#{R z%2U25e%oPExUgNA>!R9>Nx2?S6}Nz;_th%utxmB4YFqM0)nYEu*$r+h?!}5VuoP?# zmEo7u4Lajlm$*?)GHz{|I@q|gx*il8$l~HR{;M%i>)wxY|D)o*S8MXwZSA#)#d1_d zFMTUmUyId`Qmm<3Fj3Rs>Dt&vFiat*QnwOVK{xoQd|+Yj@qzYL)Palt@~;xOOFC@v zy@#G;g~l{<(7f5kS66|zDh{!5G(ekjxh-uSeYeoY<_&4jeZpuNy1s{W3(LM=vmGA^ zP<R!;!GLn@Dc=)X+VyC|dyvYjN=!{iH0DpKs1eQYiET<Ee!=FJOejV(HYHh&A%?Vu ze1^2bQ#@UJ6&!U8rJ0lJ`4o9+V#-3<KuES{z{RRlHxgMQ(NJVw6x4|ARPvhcFtJ-{ z(!rP$N;b|gk7@+UiogNHpgW95kd7VoRsO2s4e?^7v`Q=hIj8Akl;!FW3&B#=p?*j( zy!$&t75sdFx~d8Mjy38Z0cPneSvS!Cv<zQ--&{JKoy<MEbWb6aADgpy^9O~j;+SCW z(-6Oh_8PhUeN6oS0h_;b2r6$`Eq(|jS0)+?>vd!U>^HwT2ghY_47^`WEg8+N4hXir z!QTRsCF7|l30ir~ePtfowRf6xe1TSn%iodqoJrjM*lYhCA+=-E_&SK?JfXP!$AMXC zvp&&Wv-K61u(|`(U30_eQdh(8m4yIhvVhADZ`q)AJlGX{npf+Fm|fMk1Zu1Lc7&4* zm&e*b9+s^8`z>KM+hn5fY!dl(PDn03417U3%MBwseV`ft4yw*MxL^yM(doy1`XvCs zx{VuwLd>>Iz0WlrI9$Z^<)?>ANf4wj7-%shY&^A`$wDAb_w==qR<5<BU^YQq=DM8Y z(V%^7V)jn+n!_p%^Bye@uO+roY*&D|yr)H_fZ@(CLqcM<?w#<FNh<*tLDX4ht=~1C z%v|k>IDmfY&SU~HRlgDHp|_wLAB6;#{Mb66sfg13jL^{xT_Q|4yHGr!5HA$`zb<Y0 z$F@iG2`vG^%KZ>~7L=Af%jHNdmLb~>{6bJobC!uaxrWTwh9D=U{BvD)uc_dUzOq+T zqAur9+bMo+?s|+W(O}qXPB=a)B6_+#b9MDv!#j935-{Wzm^P4v>1s4epFv_W0AI_` z2twjFBQd98)2;0ZVJ34?*@_g^P|k(^ASP+qzTyXs{ze>}KeeEQa9E|(bt{)ej%?$3 z_%N)Pd$D5KeF<E3xUZM5^`l|+gU_+Zs#w`EvJHlfI9#C|R({Y)xmq})5hQOJGlGN^ ztArLSH(-^@U+tu$ECX4F%nAvEsCGR9_D)Yi)n)!{niQFzPxkcJwsH)b9*p$N2)4zc zebuLGLUDR+^a(W@{)>|AN1gl@u@0iu1JiC!$y>M3^+wBmY5W?sdf&IxzYqh~NY_3p z%|*0*d6;@xIPciSRe$`aD(m=9;~)Rk{|0MC;T^Qa6!6SF`P|Zo996jPa&pw*?JA{~ zrioiU2L%lsG!xcM922Nsu9>E5`%$8yt(y^k`St-=lQwLcmj`)9rz~{`9Upxy$<30P z;hi-cKMHT{CI;=xMPSq#yi%muFV#@$Sr;+0Ke<^4N>OI68A2>$nvtU?SLL&U*7`ff zC#rhA(tAw&^aNlvh)IhqF)!DQJiIA>jDI?Ut3hEkdB7n}PIkFyxT^DTh0pLrl2U5Z zCV%Bn^oDt*`88jFGW=Kgiu=nsn=C@*<z)!48MztcWD#y@$W{91rqSugnK#Zq<AB&r zDgBf^TBNDA^Y&g`R)fe~cStx|Ep|(kN``J+|734Aqe|qd;IfDKE?~T0l7OuJTnNZN z7%jvxd$${|?);G_n{Zj9uF?B@vo2=k;!CHO4(Wlx&Sz7{cb8MqA#;A`L8B+Lb15r_ zi1wm$xipdEi+Lv>&t<eqpSh*va$Es?8ptd9Tt;E>TWIsBY1){>K(1V3dAN@7La4=5 zw}{L-Lak?rRGs5TgmZwC0dP0G=3QR#-30b=GpL-h(6r$BE)?tN{aeqY57!otY&P%( zW-VVOEx72&?Z^(;+dFO#w)bmAE#Fj|h(PoQl6u`AFB)~VJ=sqGb<aB%I~RyTKt2=* z$Yl^!s;ev@lS=X@n0wV9Ok9=I%ku={V!4IeVp=;wv&NzWPt^gcxGNhmoI>0r;KoX| z%NIcMtHHfyjszd3G<)tf#&=<_12fW(%lL^_objgXStmJv14620TUw(b5BCl)=o*sR zvg_g+7}n2SB#J|hXlJ*jna34X*0|Fzfm){$&#c%=ILj(WTpIezg*e$`#iLVCY}+Yl zJUT3`nKKvLe@q7=<oEV4SPxzG8@qEK#)k6>F@rh%FDB|abs^pPfz1<3*LC)&MUm9r z!Q<fs$eIUw9cmjV-CM=`SOd3qbSiMY4;GB7d!9ck5Peu(p($gAhYFIT!Pm$FF+-s| zcTX=i6PaS-S%n`1>g)s-=WXn;`fiA$p=ttqmHVs<RfE`*`pNJyfD_`(DKTnqUr^$1 z*~vt5OJV^bYddS^rO^9Uj-s#?*CT39OEUmp4<vJ|j%^fn<{hVIW#~b$o8K04lKXg1 zu)br<&(<r><zd&xqL$$-hqhH+8vuySR~{a%ns!dQ6-VJV!+9eMA{STl9WIvo3iOV2 zZEUO{1oO1>aW@O8tWhMOpl$+LTSa{HB_63!Uu0dAe;I6M#TK0#Uir29u@Nx&>NHzO zR6nM@9hSI;liK!9zW`L7*_4gB!6(fHyPYFainVHl3nU1}4765;GmgaX1g9TY8o-*X z3|K4fMKF4KsUxvq`^84asBMV&?*Bd3lBoIC^@acP3h>uLx>+#!{GpWGR2jCe_PTv> zV`%AnSwWeQOryQYP5jmEwxWGY5;OlJp`<f1W+TWb#RVC-l^SdUm0js2DBVbjNEdw_ zep`hNHwi-Fth`qXrtAXj-2zqAT`|h3t$eF7bf6ORz$SplfZ=Q4f2EdrZxTO+q`ok= zM>{5-TtK|nLdeZ>UyJWAjlyXGLZ|r}5Xy$lp7`3|2CsB!sN)*im7HswHZ`|}Qa-L# zUnc4;?!2;EmM5ImG~(LPX&1CwzX1MdK-`Y{tEr%hX&SIyhIuip(i2!s_c}MWTA)r@ zN3&`(W!+-vs(#Co#<XTvX{yLrEAzunWmd2m!ut$!Mv6)O)G5d32B%Su&*!t%Y`5Z< z#N@Yc6}@E%28*bXjv>AuPuZC8${bTh9f_XWLu{(5M<`AhM_qdjk2WQp6}()f5!$;C zMhb|j4oHQG4|I;_(T_`?DFbRMx>)I>Kic3PDO<K>SGVlP<~jSOlwR!9Rvs)}Zt4kv zrGxT<f9+nKS9qELxqsOrS$DU*T+JPGl8!c_R`x)CUfRi-v8cuCpZ}lcu+q!N<Clci zmv1r2xp}0x!6l{4uH_^nMVRgSTzXyWUlm6>QoGtdVR~@ff=^{?>wvaKoz$ftyxUog z6RCX_^k}(dPyvT6dbKy1VT#B_m*sx`4jDyn)-Z4Y#703~ve=wjJk#jUQBYekT1}eX zMYrZ!;Y=_jWFqR^i0zHwIY0p<*9C9&W@x!j%R{C_-m)Vrv3l(gjB_rHY(}f3X3paa zuMc!y46@4htW{sT_%j67b6$a!o~7*LP0p85nTPAUTG8g9TF?iITDJKS?YEYbiK0B= z?A=|Yq*iEfmpzr1l0uAzt%g$?@QF_yF-sBESuvtRoGMlvAten@3@6s}c5by4YN~_B z*ARroa3?t*XVGp75!?t^cR=x_XST#;Y-+E?B>=XF>?~j{9q2sl2aH5-Ybe%aXjbi+ zxSUSQMXptXi9SLj#jTuerrX*)To_qyrmNXVcfMv(WO^{sRJG)?`x}O63Jim60;-K7 z&|e~O-6KLG7>1put)9y!oT~Zp@UA>t$;DwQ&-{Ks6Q)8DB!!nAWmX8v*mJ9>Zo7P8 zIQDy1$yKM8ZC!Yexvm|3&+*mK4&nk)&{^IQdD{l44VS0!m%X>!2ggNO7AdV5Mw7Jf zfUAd|qcFF2LXiR3jUNK7M^C<y67Y&hC)Vh##Jn}Q^wa__r(_!TKbFhAiFk1wKO(Lf z+K%x7_t`+PiY}9t>dscnG^0k^aj6n+*K{rUwqv^+>S2mWjbTvV?~kgmGCDVs{I(KG z@LcVha9cT;Z_<qMDh)PsxM{k*rZkHiTfL^HeKq(5nlj#`fg#(EMV5-NlU~uaNv1EY zor*(4zfqn6WUS$bnV(W)rn7u?S+9KTTQi{Eqrd*=|NN^_!n!1VE3b7sG-cL?K8|Rj z#s+H$`LfF5CWPWXoAyD!rI-UT81h(8zIZ|@CiMAN?>&eIFlbD4g6SRS)h-dZy3rku zJ=hmhl1Y3OnYe2+QZwJZ_Btqfwb(sdI)L<?$w-#o7kzi!yjTt20%?wl?jw_QFY&k3 zJx@yNmEW3uw5;D^q5`cyGpM{7^zzjio|9%%X15xiwx~)HBI=D;=f?KGQ7yI#UYRBg zs0JRaj8?z#QQ;}VPdfl<h^g<GhRur7`k`Ji(g0(D)J1kaqqDr<z3cyWv1g(T3W2m> z>^XWW?Vpl?!+5n~wcq(-FCUK7vgBXRPg~YhmHji6qYg_EX0={IYk8tR6u!5CXtS%> zKo3sSQQakM4M)aS4uu_jE_<ggD|PtDD<1IHAIg&|HnbF~F+}6>^`fAWsM63JR?3h4 z16X+qmWzc8-pxDIkhj?oQBy`@r|S)*g|qXRtiww8jG3fC(5jg$v<Eoiq~(?KlYV5W zThXR$N3+<qa>ncE&`8A7*&(##oKjn0rp2s=9((Pa#)^m5K~^*TNNDRc(mEd20lPO8 zF0a9DZGLAYaTCoLnQtQfhC$7{0arss01`bI1e(V=0{{hJ3j)wtVcA?GWv~;X|AxXz zYms&*rNH9zF2wBY*nkuoz6zC{E?jLqvz&>tLTGs0Iw$dNB~}C({DCLOCMyRCqjKWO z#Ngma80EjuAnalmyDYJ_Rg?1>$+*1^Uk=S~^=4{jWs>~x;4H6^{hF}}9y>k|oTV5C zz*r3kJhCk_z~CzkM?}{^mL!yZC;Xb{jH-SGZP=J6EL;#do7B?COu#{D)etTH06vRp zyE!^Fn9YNu#D{^0sbO_Iqw&5B1GHIL1X)znR8Q;fTCzvgYke|l_`~>&0L-S0!nOwz zP4>aiu_hrK#Ps%XPg`y1pPI8`wopu0eI<zcP^MxX|GwW9T(}wzN8na81C81pfk|p` z+|f5MItxsxsZwgR7D~8`vMIid)Z%n4+YK%<X;hRrYaCdcE^JH)nn#8zeeEc}dF{Dv zsm&a#lrl+Uz9=S-RwR3kbYi{Yh(Wn6Z8a&vN@iGu8Q+vJ6oI7TLQ4_z>Xgxc)>%!A z&N}#Fku{gLLJF`88r!TBRP{@dJRgbx*W?;IrNUDXPkmCQofqZ5&id+MjU|~G{hIo+ zrx_UDM;;jp3x-CoR`Ecpsv)A(6tCiU1`k9`H#Y7oWUqkKHqiP7{@Nr{BP$g0#|JtW z5OcB&GxZ*o+UsziW1sigLg}uJ4-$OxTB}+v0_~W*5!1IKnDAb2xvrOfjMR%Tn*(!2 zNB7&_O=8JR6x-Obo7l~jn094tW*}HQC0a`>rhU9w>#Ib4&5U)+r=YyPi&|-C4HozO z#I`m3+3d5wX%P>VMT)TcFpC#7fyyXU2jmosb27r$$aB|@Tk46%r{v}ZNUi`T{FAoI z_h`RTWrf>!sL5G;ScY<1fZV0;ZG=xE<W|6bv*4wbQwx6gMQ?rAVB0#Xm2?8V+oQ}7 zsctHxzA2Kwq==&1fDNeU!xV;k77A?1P95uGp#g(5P)o}!0h(55(cw61XWv27ZR_E% zYv5(TWg{dLAy_)EPY{b~7S>t1$?Z}6QvtC{47<#dkNp}S4TT;2A^}V2UCapuc@lyL zr!8k}byYs7)U;hB)6vUn-WEiy%vQTsyz<ip4j66aVzo6-5+Y-cHf8-()JM(ls#1?t zSL%mKH?JFd;wE0ywl8N@(UO&82hEN}@@3R^f&AFp+BKW=cyiHLDEHpuYX?C{VMn*) zifwtHOA?gYxD13a;i;)OYua&D=5oYQZE*H6<Wy#O8jQ5wQp)?eRy)L`-I?+utpQ23 z9F*+TcLHJ9Q_&%3!75k;s!D=&>=jh)b`MBYhG%-~)I?fGO@}@&VEhNqH_1AUjnJsI zba$kn2_K6(?HYcsrH#1o*0%(|`Jr{KU%|}nNb@+MX5JJCJ$E7%4L3Z{o>+By@5+Yp zfx6*cO|3h&9yV&KY_Olck>zR7=Y-ubQJ#4A%W_YFAwLk~(!Pkr^B*+F^b#N!D7e6> z!&n|%5)jY8Fg1bmo44KIeTsO619?{=rMY+XSbBqV>NYNj90s9Z&u`n-5i>IX5qygu z@V!w&I^(?6glzA5^%1v*Nu5-|MT|Vb4g_d&I-K`R5k@O&341)y8C|=<DjJOgZ;t+A zB%>D^y7K-4LZRzhef<LAIG9>pdwQhxk<k62{%;WD?JKT7A$Qhe<<HZPtaNQr^ZZvx z>jm*r8ICZ_e#}bA#7oXjsLTSqdJ6}Z{wN8_M+KQM&H>)mrF`FSZq0zTR!9l8>^u{< zp;~U|PmuFja++ycMT>zOSZz4t24OhA;KQwL8qm}%fN;&GcPyW4j8Z%`vCt)YV^=dm z0tKhQ%eVT5C8w?i+ij}WB0<64=DQdv;!Bqo*(kuJzCS-)jq(fI<8V`J<=sN-=$<Aa zb)IOJ<B{xf?Cu_9b_Q0A8r&X}plgj+bX)Ap<pNI1`ic(qR7!4M9RY-$8VgbC2+$LY z6k&LR1C;)ymtzCmHpSOW6{fn0fl6I<1=M2Wc~~RKVpmq#b0@kXHPj-T@LA4W|KPqH zKLGZ#a?exJh~VC%r^bh4E}_i%)dFIUtS(KY7k$|0o<P8t2osfLbZQWmJyQ#9WrFor zHwi1Lt+whXo>kGZjmF?#Rw}})h6xf(7B0R`8DP~ps(jhgNNuukbGz1nDZM$t0w=cs zlF$)E6s_6jWI^wxDw{^gwE`=xcP2(<%(UkxAM}At_kOhNzy2nnZGYLWjrF!h3H|l$ z=tejtjwH;`W^{yfV~|O{?CfH5N-NQB)$+((j(~B=CLp&DJy=6FCe~&$7USiwwg`bh z5><~@wD_a}GQnU}-mF5s(T)5!0DdWP8tR5E8l7|CX!2{Dv`=B@Jx@X#Q*8s<B<KT3 ze#c;XVnM-Ur=^DYN1)B#xqyJ~ydGtjQc|abKn&~zq1@9rt@1GWhYU-~l!HaYDFfvo z*{kM8P_;bLDv7qtCruRA>OwacD+kmdkvDPGPbSsMN)<YaYO2T)0e1I3_87TvFcYl` z^Zt}iEE?%h*=LZVnFqnju(aI>pbrT>`phO?kfU?i<l1gt5LFU*AL{Jsr5AGt9ngIt zKt3}*(^+YvSeWRzuR%mXBnMFt&vijk*AdSE8d+fQf*7E3OF`sl*^P&o()#Au0~&Z8 zIgj%?t<aEwE?}H+!sA~ECT#+cbc_>W^}Ly$EARUW(rXzCVZ3&&!f~-ii}d~^cFsiE zkyDp+WI<vreUwTW@kEISVmvVh6n-sqy>~2h*wM^`&H0{#fal)kv-<bUOuV&|<P3Ck ziK4!Rtpm~iaR-Wjy)@(K;7ECRH7=-oIic_^e}eAG%OoD`kT9dsk~YsfmFPK=aU-9Z zmmhwv46gGASA(`hW0*Tl7QSp;)XEy?<D==aNU+sz4H5{nE@>k*B9M-Bs`QwNnd&%C zPFes7QYE2wwk884W;_sbiOIPHk#{fo1iM}pOGMF)XI~aeH2_y`cP{PY*rc%V3cn&W zcRFb!F>zXvi1XOHuCctWqnwiu%m9M9z(eIsTrKx-`Ip^;Y&h(<u~lEV{EI;&fJ>M~ zg?K(u8)E(@*AFfhCLaNYxV;;b<qR{H@)1}g=i2EfW5u-torgga#yWAS;iQAJXC`At zZZGn%6*CoM1%OTxs?Za8cc%Nr3=%4=P51T^s6$Ri!>IbJ+fE?JL`Zd!AOooGlgSK^ z#z03&xi+|RxDdZC_p+H#Q`ovE;{DGL7)P8kM^SGH#*%MRc6swW`&95+0cu$`2tu8Z zPV5R8xvtUdc9TSVjMOgUj4y?z;#r1WM^_6}^``tyK_H%a0}s@6(|Y}&skstOz7!%| zq-oZtZZ!zj5Nx{rcBOPdWl*$r&e?pIaULC&T75hJN+{M$BNYNMDz0(P%J*YRaT%dx zOxRFzfz9Eb?qhtjuX!VN{~kE?JiiJmL`-Ao$>`ATf;Uc0r+QEK@el>k%#sM1Bk|$< zunn?;c3+S0i~fZ?NyT#uwM3ItvBbhA^%*B_!}JUiOQz(ic`@Q9YDO1p&9SV}`-u}} zBR5xNI8mkVZ!G<IW=0t(6)?M&ip6&z=Q>@t;Bvz|tvwRF{fmct^ZWnRPt;KSXEXoT zr!U-0bAy#4LLniPvKB|vntlmn*8NPUQhF>}N&JWK5RD9a-d<#=XZ;O4ckS5udPZA- zJ8B$aIH=NGZG<Hz5_%v+1C%9kX-D*PFC=dP#XxIK)Jtm>gG?aYE)Kcz(PM9IhY)YQ z3fKr4-P7iE=1v6oXGgk_t!0LeHSR0rIz%gTK7`9D`BSoYK3pp4<5{8<P$4B$5z1y6 zprHK0@ka%NbPk(1m2&HXLPUI?7u=e3D>>Nk(wdJqDU%zY8;Ut9FO&~qK*({uDaK59 z!wsEh>DlKAW1{G?q=>9K8SB#kR$_0^gWR8uyfS=~gj(LRu#N?RB!Gu)WTp`NOlnVI zY~`{UNvj$RF^Tm$&?I`e0X`Qn%m>mlqH|Qr35WE&i~amT#_5kRf~maDpo3YFRi8k@ z|7>yiI*%*{x~ha$GfrP&@Ww-?S53dB2TF%Mz2p?SKKYqew4?zXU$nIASxLeKesn4h z*!mXWjt~oZltP=l96N^~i_U8QMwo5bz~3W<8_47fTSA9F@kf#P(<jpxJ8LLy7@SR> z1;j=&!jx~`rk(~U(m4;6gR_FYhkg$LhvI&OboO)4`#+t-SyX+I0x)(S;GsD3`%^9f zkqqWXe{eCdAn98Om-DiQl;x8vt!pPAX_9d2gyNAWFby*T&yMDSI+3(~p91=_Di~(( zj`s`odKn$XWCYa#Ht-Bij2CHBpJsRZ6+l~TUKDWhQCmr$&Wjwe)`%h<540%+ubhl~ zSheXC09Mi2e()9is6GAXgXh$IgqsPd_P>~kan*gv40qy~#9lt~h1Mq&0}2;J4RIq= zPDZ7RaLR!+EHMID;?5Gy?Gu&F!A)by1Wirw%;M|^G5FurG=+z9Gy&ImZYnO6Rs~@M zAQsI$LXUyg`j)Wn24^8Xn2Wa0r{21oCgk~bPE5^&6%^{}jh6(4Jh~yf^bQ#8=BQFZ zjGdZ7t0pI_X_8W_ft8->MIz6jD7eGb%xcy}SzP60&np33AG3}m50eW8(7zNEI=Pl5 zMUp?em8<35b<I2a_y!B3FXL%mhgnvOd+t9B_Y~VhwOz!=>*Xy#TdY=Nk0`nPKX&Mi zl-$fR732rQiso!py>#Ism<E_upynoG&t-ASKq#1A^lEpy6H|79ePYKa7v2fHZCkBT z)f`5Tkn$++Zj-ci`zEeJTkF{~zB&rlkIrx+XSc$5+AG6cnlP3~65=f9jWs)z<R=1o zCipCb7^1a9d=tF+kn?wvFlwx4Td!**T!23N3x-%=coxaUe7hmr%W47|kJ8_EIUuEM z4J}JcD5x(e^J5VoqnAv#!h)!pP+NrCh+JWcE2?jPFihW~hEpq4t3*Krdjuw~@t^U} zX8xB?|L~_cj7slR;#LZz_}(f5*;7rugleIcv7~WB)hCpg&1A_g$1zS4L}iKWYVgzn zEWHT~yBtt`FiU@;y$(S4aLo5V32>MsdM~Vr8o|Yd{Ly1?ApSCj66#1vENw$OZBD%( z9N4BjOaPSi0OOZ<M&wfeAUxx>(}?!&=t0Y{dU|L`XdF@JfQH)mCo`mXx<7hV_5ZWz zAG=feA6{?cEKRmFz+<Dyrx=nxAf&g30)|mVHJ{=T)~To9A?MLJs9;hpMuNY2I9Ux^ zYEp(&kI(sp(N;N2`g5(68IGhb>KX{to}1@XR+jl>HL2RlY==`-<vSjNxIIn0<xu`4 zT(9}8*HR&6QcRl-oT&akqCXfJY<ji}R!B6}QNAD%lrQ|QPAYBl24Avy#D|K$+xxr~ zG&G!X2Lv(Q<GYxYnFocp<itUpVd>{p@4LLz(zFF#Al9OBK`N4x0(Db^&w!1+pgfrO zVl;>M2^qX}g&&Fpc|1rO%(h;R3H}>f;;nx*rltmgBAKAV#m>7V-X^E@d?o>jJiKOh zvbJ!z^X~ZUXX6HMxMx5>ZxC;-P78{bjN=-X<R7+u%0O}rGcGa`-9v!Eblwl0NE+S2 z0I6(FBXTwsVv?p2OFN(8W&mHNq54)K$R_Bl0Zg{)I)HU*DxmC*Ptm~5(Y!i`W^w$s zTD^h<R7NYK9%suXgGp-)6fkBy9Zc?W4M*w@JYq=dqOQu*B7Az-{C8Zv&L_&rlu0-d zpZ#UC762JYF<kqo;ce~8rdG?b4uPI;N(F6dTiNFcVNixtO${Lr$xIw#g5<$a|JlE* zmgWoi{W#tEg93mC7MS3vU40CnAf5UK1ulUs&dUQkR9O^8`W=Ow$;ZohSJWKBYrq_s z+q@+Xujxi~MOGAx%fSa#H2gO2a8!ke1Gt)IC(d*`le0!47lEJ_?G1=vMqx~>x|1rq zf;t6t15eh5DgtE0^R%E2r%{V9$|&w#hb{`7g19+$i3}=3GqtyBKS>*ASdl3~E$ZgF zbJLU%LSbDR2(c~WM@@h?9r%e*jy-x-CCKFi9bby5;z426ffVW{Asey37|02u)q8{% zYYP!SA!=M$M>ZzmUB@DkcJ+m>UY|`zCW+q&4i(&yb_+#GZ4W#~fu-v~8rCm@9U$0D zdkh280H0{=*kt{hPcV4_+9@4;vp}2Zk+3jek!nh2Gf7MHMm#8eT3uFEeTZw>wrG-v z>;t(A<_ASDCuieZOEcdH#0yZTD=}4}MLnATq~8b;G{PPrsiI2D(ql~9!u?{0P|FM| zsQkuzX?^gCAVRVEEaoLBC-n0*4!Dwu(Bh|$`|5?AZkBWman^Pfy!PQRfz|A9kADBR zZMK6}nb(X|P-cADlk>C1{AV3}nr?(?w+wbb)%*`E#SR4gc=%=<$2=S3($lHMBw|%& z4@~Z}h>l2Pj44he)4cMl$8iofflB5S?om<|>5s>N!R({LBoRUp!1~auP&WV9MTAR@ zIhJKkO?@!`c>E3WM+HHG3$GflOB=5<1Qd^hAR=>uk{%${av*{zY;*#r7@j-a{at#h z_Y!}fC3=^UHS9>Mkg;+=r^Q^xltpY5uHpRFxht2@hEnE%olSA7FTvt9G9%l+u>K7h zj;;XEgJspxXTZaAL$Axxd^;y_JZBH_zpvU?6eqg3Ax5$Yudx<}xE;Lfe0l9)o`0Qf zYuCRHHlIZoUH@V<>`|>@n!n3b6yAv0?RwV4(1tlZGXX5xjK-;RNUJUhYtrhv&EA-l z*1BrUiK4>Jbxj9BoPV?H@qqG4l@)&skkZ^h37CU2`>+Wes_pd@keH6K$J0w&9sFGe zL2V2C(AEtaJ{=Mfe40<eCE0m{e>cc?JWYso&scGm58E@IfG0luoH5PU(M^Sb4?k!8 zk{<!crTn<)9i}5twDKXFCxHdNq|uNS>99fH{mO6_9?7fpcGu>pjcDAh!Hm{*y(OYC zm-<I`0aS!$YC*c$c<T<`&S$qiZ-3x5z}@}H%rA7*KwK2lGO0i-F9C?ih)S!pQ&<6m z+w~49T^IO#02^n6cL?IL{7H`A3Lc|mK<5()L~6|xIuk|IN=^0`F!O9C<ZMFuS6Pm8 zN!X~~HU29mFxBtZht0Usj?yrVW<OwBTx7V16XFX3;YIXf)K)i5nORaCo)w7<d%_t1 zCl_{2W-bxKDNKc>g~D14F|Bb3@Q5Fyu%Nn1+;U1-`X@(Uc=XP;IEtuh3$(88Wto$F zFv6&7WcgM5$r0F2n0ZV9Id=hbQKduz8Q2`iCt<NrCs3}HN{UH{YY5AFVv&T$wS;`2 zS?aw#9X8SkOD7HkiOXHz9ChX)rlBQ9A3Pk_9UJ~dl9TEL<#a&4QtrCw7Kn36a3&*9 z#0c7k7bgdmtJocSA8KbY((dOuYc;qoI8vfkKv>LvOsLvndaC$lci4f~0Wcv^?m5~d z{I#k-@w`!i)EYQhjS@8Ca(oQHh_q|&eT-4x>Gw&^QyO~MEXaN?hD!YpVSl~$x=RN- z7a;f+;F{nw?jxfy5y1^$=#XYx)ie|Qz7+wOIy1R&;z~8%<Q|22xDsJoRXt!&J7GQZ zCVUN=hN&QI;{{TAo|C}nVv#>MVojdJEr<#*iohbyrYfj@Pn1KksE~;_TGhj#^e>;P z(vn8-UHw|PiRL^wqOEkphP*b&5?ztC3S~_zy4c(LG|3#c$_du!Hd1L3?2k#5SBR?~ z->0(u)Hy33te}CHI$q{Dk82(5Tt2ql*2gkEf@E6x)_;TmR($J&h5vGVsgkDm9@<EE zU!`zvI&tnjzMj6M?KQ_ee41G53{yB=T`}W-rS_y0(ryQ6U7N8B)2<$uB0wc)W~P&X zT%c=4BV&6YX2&G%m8sv#Pb$)a_~)ahC-&t^9nFf8hzRB!%d?}|WNK}C7Mrn3J?9aI z8Q3ru7yJW#6D**fz?TTDw3KPf_9_dIdLZ;E8pOo-v1$j5M(rs1nHvSc8q`T`Qc`|l zmlH_)Zye;XNe|RbYHDpZ#Js*|+-kU2eu|fu*!k`%O>X!agAiL_eExKYOVWrwa{5kc z`_{bldZ?ejfQ*cL*q}#8;;xsKKV^(0#x>eX*THvMdx7U44m4T8K|C^cSB8nh(7{j% z@B@czh6B1KlGg%Yb<7-fswJ5cghmZrIQ24*!3K$H=imGvN~48P+q(HTV<CZb`ncdT z?oOpp4tW+G*fJN1@ggSk8?U)}$ihz?lRF~H85a;MGozf3VbxNw%!`{qo8Z+LAo*90 z2Y0b04NZy8e8NAlj?R%NTl<utkp<~b__%WcyC8g*a0gf3H|?k+(HhW@>Y#XQ*Iv+& z=Y^V$cRwWcbS69W&|BfmSZGCZdhL2(ExhC9hYvA$_*vA-BfTU;$E%sfz=T_OP>x$t zkVg${0F6js0fz$4dZ%L$Gmf+DjD{)Vm+OX{8hJSnXvAlEwUNRygv}<6Jo*y6&Nkq0 zjlj`{Jgj^GtuoY4JXWTpgF5s605PFK#z4$Y(p#DeE6ORY(v5OhhtGOuI*JCH_lStr z4XKf5wyh&$nkeiNc`#v<iRJkW_3F8^ho+r$%3(vy3oc<m|A_{x#Or^dX-Odt8l1@- zhB0$H{jjS?0M>o>eeE|D{tRJdeF-=a#tG{P!D9dEQ0f7OLI7t6C*cQ1)Mz2a^A{AB z<V)(Am^Hz3YWPCxEA<`J3|RdwQOqTyvxf?2HM@xJNm51mjp|1bK((gLb>Jowi){|` zFf<9h(RJejgg}*+&783^J+A!Z1%+ycsmV(`FvIRQow8jEVNg!B%*AX%`DZ;7GrsfQ z1}|l*H9IYDZ~fX=0lIe!LJMM^@nugK8w6r)ybva%YZN_mkr|9PfN-^8E*X{0j=EU| zff|HB1WlJ{w(%yW4OHOcEW}hR=&U37*OvDrDQc+E?Ttao%`F2>@IFbbCP>XlrevcG zP_8<kZRySm0K9j!2m25>2bB;}VQOfR_73c{c?0g1<tG8`McsT5;|T(!yc!5lUjYOL z3?yEo2~22Os~?ga%|@J;XtnwehJw9xvB*myals|v<r`o!Lno3>7dUQ5ST$0U16%?S zgvWLW1o^&}iE|I%lxVD9IMIy)3(hh-x;(sXhSq#F<cbfL_5qO;&$EawKL`c%OXcX@ zHDQ!24&ApJm@EsW8W4$KEAsq;|C7MyboRH0KmEfsl9``BXua%|&)Meh=(dF+ZAd%7 zQ?>_PTIkaE<OZq+mWF|3CI2Kcs&q}|(@$2U_a`*p&*yQI65vJZ#6IFeSsLCtn56Jw z7X?K%jyMz#N4M<|w^K$G<`>=dWThSB(2T95nz(SY{^DhBaDr3jI+{@dbLPpV-82N0 zk=h;bb8ds_&Uw10H~RoXr9lIlC#WS*qm}@a*7?uqjYaE9AR;@${Rl=mTccGj?m@Io zKAQ#{o%shs8p`QS>`hTU6<hf!--dBJKLL61+a`E2oH)Y(#cmB#GRHB~-V02Upb7ub zTHlGQva^(SS+H*Xns~0`@ihw#Cofpcbe~y)%qld4KFh%@5ib}SQx`*V_wO+Yksec8 zAZ87_4!SYK?|@?Uh@z%T9(RhS*FJ?Pfjk-f`(n3kXh{pwfG|Qe0IL@vo$?7ElOfk? zi4}JSL6Ffl@jS0;Hk?6)Rk*YLmtf#=7jRMdv+3XlLEXH6OOkBZ_3SM<{KiY)eaK-Y z>@+>gN7^}_)yyT#?$90(UwW=%dSIF2rTHUy1~H<EySKgtALKe9fTb&-^(XFXxuQ3U zw>GuyfTXn%i^&v4zosQMVmTGZZ##r}C-=|I_e*G0;hp%BSYS=&z*ZtLN}~V<IDX@| z37e!Uf|5+%8*m0p&!+T^D>jRBt%G2B0tX)qj6F)+#lzYhz6!#o1~1p)qltboih(oP zFA7>W_+y*n-z73Qa}T5c%uTo{hRaMrI=;6uSy+>8(oCNyosB?(nf&!)TnEJjnN3^N zXJZH~S1$u(`Wp6cBzI+<tXTjKh=X1`!GMGs+m5u6NYOaOk>;(;A~N^iNtzUlGCfaU zKrO0cb^WKZPu`PlRd{nG#oVDfUYY%XR7q=updm#v1HuK6LV>!re+X_JR!o#h{=<vh zX7kewC6bp}#LYd&q&`GdBm@E`0JHRpI&qYisT-bx*I`Q)VRZipW!2slI@NpbOlHn2 zgV}#FtJz7e{!=rsB2dSPnt*_xR&-774)1<_fDt{|v(487j{-il&JUDH5zI;sz24ff z2QLiZ(6Vx-Gpeo~eG#fPPn8rKvSAN>aUCuzN-v&(Po^0xj`4jsF_`FZ&&)hNqa|lr zc?PbB3kNXEQUj<CB>*y9I>E+-ananlYaJ~QM{0OTm3PRbfSS0|jm99D#^i)B_9U?x zTj2ur;|p{2j7C})V?`g$!L+8uE<x7qW&#RQndhWcKya*o0+#%2xz4l&V7jP)WXaok z^2T-;vC8ar!hNAzu62W(8&!BqO?^k!;hscLU;ERs$IL}qS*Pb<kBn?3g6Wp`%eYsp z?0DGi35UpODiYn&PjGCulqmt3nO_i?(Y(Zt-aH+6HoK^8W~I`CU*Ezk{^VB^-}w1q zHMgQVp0CmBu><5)Iuet6NEnsWl4Gkzy4_4a2)u0*|9LmEFjSjIfw@({cj_AV`GBxB zkAP%Hvt97C8_;b>;*P@j#GCPX52hYfRz)vtZuX9x%eQbKV+jS|C-?d%7tj^pOK&Rh zLjyz4T)lD~ju2A*9_{G2iPag^EBDO>1diu}Ivi4#!I(r2jN|Rj%%wV&DJ^gA9-Nsm z%;KaVuz*W?B`neMq@sFpoI8+8r%r=>z^!KX<DB*;!l0TG6mJ9f)ynQ2zsJ8<*|AAe z`W<S3?dI}N%&W(t@<u&6AZyikY|r<*=i`8&?J)^o+?UHA&3&%5;Km^y&);?uY)W3f z86-mw>`3wdA1~xXa3_r!EM+u;A;PU3Or)hXaL?YUo0(ZkE)u*$^t@kB@0JYNwFi07 z;L>1B0w%a7(bI9T?g+t936toLFi8?80ZB6;3jS^+jhPGqTuS`0m!JyoFHSd`*x)H2 zI;6u*yAIyxZt>0&z~FM6xN>|&u@(Qa?pcA`&_iN`T@RD?EKRqhdxx(ZeVaD=wqb0f z*eK9!kbLQUyv!wG>nHBIGLlJD9myLY%!bD`vCyw=9@ug_mB^%lRcHYfgOgcj8flfe zJtYt}0C6)-bz*GFVVLF_R~HRv1lk!CdOxpF_s!4?ce(7SQl#aCrdenQU|XL4)p4@* zx{M>HRswd8TIn*Z7JcL>P)mYRxyyA3nNGEgyCh1uNsGbE<r~q}lhSO{>>sVH#CQ-b zL1G0*J&?+IJ0P$eyc_~Pb4IL`7%9}9u}}=q;Sws;uf_%xm$AWq-u%nOkteDZ;2_=- zpK6B~k@&>2E3>!wRTN6i-j7$ul=r~!%-Zg4K=JA+lM5%HDY^HXK{>H6!O~T3>UD$v z%srm>LP2E^Km27Co@PQ<DHUK&kBLL>${7tMs4I{A<Rg7LeKLU>XVdDL!z>(mjiJJ7 zXbl3ZxEq(UUSAj|R%;Epk*OJu*{FXebatm+D(u2=KY38rq<~baHMNNeCMPtO0kqg# zkVHwZ*!W=_6;BQ58u}w)3Q{q6my)d)Lx}Ct%9V%FHjR9Kg{y|%tY~$5WR<XjKO5sS zQ0@-sl$<vBl)Z1wFik1bd$cT)=|m@MqL4CS0VFAOl4xAy5+fD6^*cbcPWoeanokG) zi=hzOv>)bPESZ7X^-6y{M|&I}fXo2cDl_l-ee;qpHz^hC*p<DBA}#2m9W6j?r4aop zl5URuqCAqSh*mdhop|&Tc&~+~lLUGIShQdEXh7@$Uh%qaxF#tUy_tqIs4ZF+faA%j zdUY0PXi*o)bml%Op-<iQW@s3esmN;UqWpk1tjyOoU$GTsw(hJ{(%zHM63rd%d+pb2 z#6o}j+^2u=GjJ<i?l*5FxoOSh8*M2jGa$?LX<%$>GRME`9qWVSSe!&utbRU8b9+0y zJlV&6KP_02?3hkZ&@^z&4JlCA<~%r48S&-nLnpYcqbhd5K#W-7)7jC-j|NJmF*pmM z1Sv{G2sa*Y1aArkX6Bt+gV`d<&pb43{E&ynb^Cf5V}Y8;gPggda<B)}%W%+3l2f7f zaxeveZ!%aB|I+hum)vwzOpMPa12z7q5a_Ab_RrBYA+0%e>+GLUxOlE8b<%PvmQ;Cy zFDU#&5nI|?ExJNPmE6hGL^J_1=;Kg@RgT}hd4~V3G#gei(B^G4jJ7U>!(O5w$!I2g z%1pL`2d*P$LwgO$K(w(@8D0@a&_M_#OB_?X-Wv#*3aLB<qDhYQqM}Qfkld7=H%}yV z5C}pA5fo)rK#|KrP@zYlIyUq^TMndvw4!25Ng=`9yn2ZknGgZ<F_eZwdmHP~D9c); z5cjwdJAm$S=$MXf1-p(PRoRToX98U<I_W2rM9HP&2$cnV#C%}e?Jth>72<Wo88!aC z3rJg19DzN2?)irZpQwDM&~-P6(uDG8y5yJtAt@tmBy)Ns6Bu7@eypJ2A}upvQjlh+ z!GGX!0FJG&x<>|_!je$CQ~e|I>tJR5BfB`c%_YQ%T#)%N-bA9(oHlX2q3AL<!KSn& zA|(%@H5!1NRcZxVC*9Bca&AoT8o|vZ@km&m?e~C`3B}0xThx+3CJG}c*nF(7sEt^J zL>ku2a;B!%Qx2k3>7vkwifO?2C8w{AuoXnXc?B$4d-Y-lO%NaLD?X)pI;=J~+YPm{ zNp2Zvl^f=+&xnCh9%VkSU=;G}8~TP2c<j+gh8we7qCz^%d9kwMInpJ}?%9nU1_kv= z@O;tc-dH(}riiU4Y;+OL?r$*pcQ~%$^OIsJ*YLicx^ojED*C1Z7PmuSxJ2OZB!l-P z|LK0sSp;Q;5-J&Pcwkw#+_qbfn!J|;xzXu%*SfGu3^2>T&mC4-N31(7i?%^OpTER- z%O8hMas;6cW07Hs#W{SEJR~lh&`Yy<OA3=wiImX1CB=oklcvMTNs|C*-RA#7$OZZa zQ5AamK%<aKlM5O=0E0~JM1Yj!M|_ia=t731E|rW5i0L99HT124Ih@ADQbhaI69R5Q zrlceCBLLZw|8cgi7F4hTME_w4sh~S9s*|s#V%GSS+_-&Uv3KcO?Oo*3k*<`AnqWq7 zg6JskGjHNS10IA~3X>H=JD`l$FBI74-^XzxXv$f^vS=p8JRq}=+zmlO4RkEF;eC@- zJ2pz8j9raPhT1F1bui=D0ZVifeG06wG~|9(ir5mb{f~Wgj|LCke(N{4L$^w!?bc8l zv8g%~BKTPTI7Me_SJTMBQYuQzrkTertUqarxl)cjQ)N31Crxl*gXAtR`3CGGy1sJ8 zPn@$Q!-Xg%_lcLG*$HNThm!fJ@iH{I4OEg58v|W&&FFM;m%*R=hcPcBNr0edW(tAK zP2N?ZU}D#m>6q6AZMmc*#;1(vl|v(*ZdsCK{`!rbqFCX6nP2ViY9`RfDFHuQJjpb{ zfGb7CDqH7Ml@dg)*A#BX=tn@mss^Vq;*=iQ$pwV(wd-e1B!8z^6-2xs(~bU7YDiDi za93Ws=S(B%p2d*@n9zZYXf%eKJ<w&@$+HAm8M#|0m?MjS3y+GtIL34X+zCHQ@3n=l z0~<i&aT6$oYu^os+q5&w=AL-$c_<RVX2zUm1HKl57V-jf%bG`OFJ0g5mCR}8@;uXO zkpe2u%VktZMcPOmX4&$*5+i$sRLq|*J>H8X%K!fCg{#KMiJDh-H>bxUYZh+llS1ow z7w0FIm?DT~n8urqUE-6@?BxG_fX?Xs51H6VoaA~J{WWbIRUIlS^YNyVB-m^BJN?hb z1{Ck;E$N;<+h!?9{$QYj!luY2PuU-m0u}fcx@4dqzL4=Fc)}o?0w~%RsG^|9rA~;S z2!s6VOh_z_02H%rao$&Ora+3zp$JDY>1u$Yi?yCV&8%qC+wpo~S?CH=1tv8zDq*AR zntS6_p*2ENO_k3?ONx^uY7ZF4f~ryM$p`v=Q=5{M{aoM$lMGLxA%bJAoe(t`5Rr}v z!XWHBeq`IJLT6I_*cJ~l84;M`d#Zb(8TF7zJHP~=dB3^UjvPt#pj5h9`iWTv9wi%H z&?byJ#Z$~Jdm*`lgey4mBwFeRF>v*hAR|0WI51`D4g|thq)yQW)rBexIOSBr!?DsZ zVG&7<pan`J&`3-Zy2V;(bH^Ni%Uu^5p(`TBxy}?p6xoxt8g#E47F&a0i2*7>Nv?z& zuav>|jLbQK0vi}JrbFVsfnmA^#VvR<g$wVR8nGL^X=yqQw|tbmT9L6W7C)&%sl=!< zo@4~bh6je#<XuM;q?Qr7+xcxkQ;kSn-2m?*k_9HBF;;494T$Q7h?&R=0O%4vGzk*M zCG=gyO*;%EahsR+S-sG`mP6biUV@+s-WZ>&+dMNa<tm_PBjqoJw7nY0WTQv#Se#!1 zz*A23EKY5N^TEs@V!RUx5ysQeHFLQMh!Za&t;6ABPMR|i&<uzXDisQDBQC-q_f6<C zd<YsA5DX!p36L?LC33>yg5M6Qmw;hCl+G|y3NC9d<zpI-t(gGhMBMcH=8aW~Q-1uV z-buR0zV-Jl-}rgL7C#jhBqEyXey)WLO;6j*H(3$$y>76$QaEUFVGUpvSX>SkM8a|% z<v4$H>Sv8mqpL3P$emps*mKdxW1p0E=m2id(ym|vPJ18>sM-v7#OMs$fHi4_mC!fl z&FaO?G@)kLgmj0fXbDUAbd`e{Gs<4CmX2wHV6e~PhSW%TO1!KeGOZw*M$l3uP*Huj z+8fhz1928|B%4o~(RkQ1dP*bSh=J@ews60vXA7|AkPhQmT!?`tBO3Zx{3D=guqqX7 z!>wwo>C0BN_A`&a_FSTh^oJ$^c4Etoe(sAs<A0sLrS$rJ0utfGLlJQ>cuylyzwx*w zLh{fnOFcS23fOSsVqknFO-{r%0t`Z^e<P4HAnoBZdu^`Hb2P)Ky#`LQ-_#9SPKO)< zH$`_G7K()d30#Dw7vWywcBK9tB{b4?>561ZOM--J&zTBo_8Z~Lv60#g$^HOYj|+ww zBju#h0~Kz}YeIlGW7n!K@&kc1X^_TvdM4g9Zly8$KCDi~a5KqY6ZPO*z_gGU%^%}? zF`l*t#`O<vahvuQ6`Jl<Bt#sncSkYI<lM`N{Qb#{d@AK4)&A+myxWo))WRX=>&Qi_ zOvOVSe;_kbOZ%71E0-?8mf{aguDvaUBJ<!vi-HTGPu;)gRLb4UW?KgkhOxC^LKY9f zteb8=9Cs-aFiO0TGjZc*SX?`xhQgWBKgrD!VfzJx*bTn#%Q&2y(7VvoXIds!88ZP6 z+gRuDzzh)&^Uh#bhnK;zxQ!_qV$%j7;uG~``^9VY_Ti^YvsAHJtfV|3HdvbuK>brL zzYr%hsQ0@Z!Y<34hx**flarR4NPW3@Z3H8VQ8ubmfFFS-_j|M@HG~q|ADykaB4d&} zx9hOB&TH<jRC<D0VBV}+z`zhlR%c`f{n)z8_j&zI4<Zqo?Zr#-FQPq4gFM;1>CrGy z!AP~31wca(!tx&k7cFCfZRM1@T<&@kZ*zcKEZj|ON9tZd9LYhHUP-?wgLA%=Wgm-} z@<JcgoJ^6d;{fP|0qgb1f|8?w2#`eP)$paZvU)*|a)ofA3I+2u6{kA0dX2G-uGW%9 z;jM1^jI`SkP(t0lbuj?Z6xqquCd1k6AF&e+klQCi1ngxJ++v=$E47KBcuk{s%2p&b zBnO2m57R*k7up)fE$>-s)94Nf5|yIdf`dgqlCL4;k{gxRI_N1A_?<RK>tmYYQ&(Cq zv`r}c6r+03KVU^<tOF#4UF|0n>WxHwDpL?|<YItPB)@N&zVy{Ddf5%IMTm0t!rhFD zP4mA?0VUtxf(TzP36=!$(Lebc-u1T!zW>{%ewkmaM{18$Lar=szr@3fZ|s64jXap1 zfL;XgL?sh-jOc?#&*rilskVK@FKw~!F-89bOO8_k9BGSX1Z#gSw@3`%CHW1i+=fEL zLK|q)>lo8k5R!)KGH408CKOl{!6Lv&oZn4#n+v7$1dD-hJ<jvgRQg&kBXn>tq0SCy zlt;cGo)J8w*)^f1Wj6F6QAV*xlNs^H2Hz%wAp^`F^{XIMC><DL7QmQd5fW9^w>oqS zN6vVak(CWXB+Rf%>@@5$E*HsAfkv^clP@b2axcggPjiS6;>UCD7PtJp4MwSy!Z%eA zZ--7DWIjYdD#DsaR!J+gn8)5#001zu8y~1PqdR*!vbg*@LY-vB<3~lXZb-<dZ4PdF z3(=2`6n&h9i_6jTG#_V#%o|<&|DEGcmPWMWB>yF&yV^Lpxo}3)02%nvzy6;A9e@(M z3>A=E2qj)79(Fy<Ux}j>rkDD(#u+CP>OJ$q=C{%_hLXG(!n7PQuq8Qt3xCtUKqN%d z+XRKos0jg^Wss5Q5XCZ8v#W<ehvUxaf`=5kYBEKO9Fo!~3OyW*fKB<gVKa{Ugq=8O zz?5y;ntkZ=;vv{lFf|}<P&l^JC;gAy!M(y}xqFrr;$*y0WK7Xh5Ym&V4q!|O!|mO{ z7?2ninSvjA@Peorz7W{xX)^0-uEXT4<il?y;ZWzIT=SB%5qR76ChbU2FV^LieI)^} zaV$QZ%D?&@dt;KUAhxwGv5fn<!iM3*CqW9<CkQiPkxj}FlFtyD88JF}LD9#V70hJo zh$m&_ptwyjFdc!4{NKd?$uf!|J>rvrMn_a*B1uui2@6i7My?aF!?h@Z6h%WtCdfCk zzz|gv(&PrPAzoBsGUdi4RK<mH8rO!CfQZPNOmhdWmwG5A6!OV651?xlF!gC>O`}_3 zQVG`ZtXEGGv?oERM20&++5Xm^4EmnkhfN0D@Qjaa@Jv!1kW%JoGS77%J-LazBcJ+G z`y<xGrG7~uif9K~*kQyqL#sMGD84k`@zK=UEx3>fd3=B*pQKA+(RGX?Yy6B!kE3}@ z!f6iIXo+FhdX2)tYe-ahpwo@IUiW*j3YRU*+q&gPz{Q+qXoGFJ>xAwR5z!ol7`z*Q zmb110>SnaW&IKiA(iYfA_jwYfY*^G3n$Xe0k6#loRTzO(kn!m7O~`yGgY^tIh<a7H zv$m4RFeA;duv}vzZBObT{Hpsn0S#@QQoMsk7EAq$lTo^&?*v@JgySYzPWbz4h~$4} zgsZF^!rB)8{YQ(9Q{DeB&ssE|2>pBq3VK94*rOE}6^f|fj_SofNQNTvte9`+AF_gi zu8=aps&<5D-m_m+GVn<bmTt&h@n-;*jZ@2Ua(0;GO#&kkpBv}K7Aq{sjoSvpfFxsG zjz{?%ggsMjSZ1emrcxP<x_rmh-0AOBWWypB$Bh^9Oi^hKpSB1}MgR^I5>FYNAns}0 z+FY!uMjh(xDWwRF-Ki;yxIVuw9+zHe%q&G{aFiAHGTiRf3+mDP!q6v;j3M<YRcOe@ z242z{qMa8RsRXND8$HcEw>=FTA^INQ{IybE?1u^JLg@8!@?wGQ`1|hG#tqWI4hc@s z@r-We(mT1+uNu2+moXwGFCHR!VZjK|G49xRDUYbUp8x^~OGFBaZQLxe4=~c`b>eO$ z#2FItfZ=sss|zrYIn$vRH=o5cD!nJX@Q~wPBZ_s26K;SL8P9{yNQ|6;3vDJ>@s}1$ z9J81tLHd`*06*h-$A{ob8J+QF-ls(%rZo!>AF_)9iB3Yg3@`I`s5HOZhDG!)1$`s( zv)W`}$?obLzir>l3T}2sGz|?e>i_0#{UbXRr*}Zby*^QAnjpy4Q^Pg|jhVrP=0TS+ zpf^3yl0+vk(m>V`G(|aF64UsD#=bOk=9!TGkU_S?>FVk+1#Y%YV5BU9_z&(>=AI+m ztBsc^nNb_!&db6A8(Vf!3+42-w!hg-ZecbWD|EIodz|mbHk#7k4=7zhIB@VPs@;h2 z3RF6uUa>VRgu6D95juekE0cvdbSF+5rC!5L(gvTEUzngW<g@W(e2OeQ=m__J-f3Jn zY%v?x8-hO7ucsB)AgK839JDAbA!}eq0delkQ+H@P?h8$A*g?|sRB;8o@YZApH4ki% zl~p?gd#r9d;CoG~PNv72pEF=8bA>^4P0AEAaZ``tmW}l3tELR~jX0<+y@*aG1 z{QhPDi`I^eI;{-CM01WLjKHXmOWGg8of<^=3$cNmw)qJm;3+Xlb_#1GP5y)1C`e8y zz;5DA>aYSd{OnbXFy1qI$TkTjqV5DrHIM{!BhZQxc9Qsz%qKpjOhX+Z1%($iKAoah zL=4J}e;G533zNDzKu=wAF$)&)N<y=D;z{oLmh{7<vWd6-cJ+`Lq`6tp>qB5q@|_e& zm=)R_ix2`51=a{Y?7oj_C{fYgWI&T>@GLjg?XrPbVCEz#JgEPKz)J>F(@k#BX2*cQ z?g3*@1X4)H*NnQ#XbFBdIpa(Jfuv<>(Az@y2ODlgIx#65)>b~lqwmLG`k*)epGH6Y z>fn3a;e!~uvgn9B;w46d#9F`{(Ie2|-;7TnarwV5p408}&k%bL7}30Jg>I^Lh7%Qe z7Vg-&ghq3O$g&lNENx;7mYWF7DM1o2WrCc|MT-?3b;6(VlN+D090X5$R%Y?_K=~7x z;4*dNi3#w^e23VAW~ApDuEqi{YLReCu8{JBUfOdipHId+K#{Zu=@MzeFRDJwm-4yY zEbPmlQb+Q417b8*_-~KDwjcbIapm6ab6;GZ3rE%&bnTp~<tqfAa;5(7Y_Bzv1R@Y5 z?~=E~?|;cv#2;!CzzS(Q?$RP7+<cerkq=dJUQ!u~=CFk<{4B%C&OlP~n;Ed=h8ZZ9 zGqV(Q5OByT+N*3{fK(pI1W{J4NFXZ@aB*j6T)F|mBjt~`zTP`eR<!#*eT;%8R7Q93 zeE>>vmR0D&KtGq|2%9VFkW=O;*IpLzNTL)7a-n<Ii`&@ylUVN{D&c^1H?v#7T)WDV zZTbv8w3yHMqt=cs40K6$EKNh9<WIHV(?Y5up2M|rq+~Xsbi>anb!=QFzGISJ2pta0 zXsT9kve3vX7cq)x95&iSrkrSi!tOwX$$nn5yG)=VBeGGn7eRXJP~MFF$Wy9DOVjD- z70zhJ7`TFcWSh!4c}-4%4Z?uk#2dKj+f()k=!y0wQBZQ4o)QN$CNyyxoh%CJ0LTos z^ocq!n`XJ->1Kk0#3zXQ#b+}=Pji>&mH!C%{9Sb&IRg^~4_N9>n25LYLQ|jMz_on9 zOH6zFZ2U@(3?ax&l-CicXqT|m7wR7AnRwIU;I3Ut!@^pgL+%19(j?-+oxYtU`mg&1 zP+RJ<y;>J58nj*-l!m0QNqu^%W+oCZqAy9GqeF|kdi~;UyQ_GL1iJvmGJ7mUSIvYN zM=h>V&Q8(|UC<giMczd^Ac_*rgq;e3#~}+Ju78Fg+sFEdHfW+*8_0Mnp1WR67k`sk zM@=%4Ld!C$|1&L+z+VZ__*ftL089JXD43+U{jiIYZpw<k1w08MN_Ls4da%}@0h#+O zr5KJT9m??CuyaoFdDw;+mEgh+O<BI4(*K$(<oT}3W%6*;p!glH0)mZZC>!yB0n|2D z*1|;4yIKJOcnq)yN|Z#q$hj+R*S86qN0m&r120X{l;U>OKDH~r$S2ZXT!E$$BR6Nf zSTdap^Q}P`lB8zHMk-K2cS(-?rZ}jAWTh<nQ1hT=5=(_dB<&(55Mtc1x&C&tneR#h zm1GAB@OAP{vFAXFD~=VqBbbCzm%aC+rT_Ie%elvPsyN@~qp0<FAmd=E@1Sv&d9IN( zx#pJ6J^J0CnvCc+-L6G+{Cw47N(6zM&+KBzs<}n?{Iq#aqnEy?IVPdb+;(#p@cUDj zBadYwc_k+3fV$ZqdE;yq{)~G{l3Y0?Q4Z+=mB$)|dnVQyiE$YUmqQmIc;CpFkW@yA zaSnE5T`_FTgYX)!-4)JoHD#0mJOzEpU1CG`)F2fS-ZOTj7cJv!kl~ao+E|s5rqSu- z7o6@^N&oN}1wYW_v=)x9V$N&gbk#ej4#X`M(NAALh&i_ML|FP$SF7;Hc*<XsCkKvh zL6779Zs0_OkJWJ=qauODG_=lehbdeaO^4gST6QT3$6%6#K5`H?a4dm~9D~#8;8Rp* zNSC|LY%V<JoMgg>ZEk7{m@t#YM+%?1WZIZBYcvDpTq>Png8*+_Mcp2JaH}p|;S<;; zBgI9}xiXK83pT)U5EZ9ywjAE__hyuiK>eFRm>Y6{1)aI83_TLxTo|HJAhX3nAR|iR zcLP_TS8E4x!Cft_CIkwCO6YdS%MtZtabypSC_{q50tkjdK+p3YdTfMB5kD}ZZOuQs zS}D-T!IH<5v@>}Or)op*6Zu1eGX#4c)}w|Edqld_*~F;>oepzYc)H@VfE(_NqVH;y zVzMU~2R_mUo3dy^hWwn%HxR9pZ1)jjUtvl$k<E~(3yR1Il$LO>7iF5kyZQhsw+tAA za|j>7qDL<1hCc)8$*GEQ7JeW(tp5ymetq;z&Sj%9xMre7xWM5UHwVuARD^aXQ0^*W z1UL<pYv@jfmuN|h>^5{`AXv>5FEoh_7AD)L)EY$t#vR!u`u#k`JeA_oeADFWE@*rS zy>6uDiV$i_fj>r;ERsjS1R=}xG@)XKtRbkWn0NsSVH`!-2sJ4N)4QoB1fXbV8VN#h z1nBB$sBa}62+xu#SKb6Cd_yi9oPA9N7i7Prr`fM>&S@7&sg;`cVNrF8fD5+d0tu+( zs7RqB49??W^0nGNZclQ*9Y!4l5VuTz(sk5hO0A9nTb{qz1~>yGbSTS~GY+iJDW=rT z?**U7GbQd&LJ5otg$OK`;PMv(4(2@MflZfkZ=}EknJvE3LZLfbq@%U2yg!V}!GjA1 zPPZ;HyGX$jFUSEM7I+ZFtZdIvopD}P&@hv5B9h9bOI?cqHLA*xbZ1<p9@~gax=5b1 zHa&qv>DZY%sfhQ1Nvr@++Cf0tHjg7&(+FClFgj)-h&77%+3fPdzrPZVeCzM;{Kn6d zz=;JD%#j&{byz~-*tx$|qTA_i3A2bSt3XOu3<<X4L8;7@fEIq`%RCau97V`u5Lpxh zwT&R1A&+ly;#TiQfF-dx!$!d2AjLv^2~n8_eIv4JelOV2XtEfb$lFB%21jqa7I#j1 zo`acm*uDIWAAbUNO!=D&HjH~76VNlCwhM}#d>oHJotNtTU=&dnpIT^t_iaA4=9`{L zG+Ca`_Lr^~%CuAFq(NYPFDH~@0MyicSffD1yNheb;#PK{ke({^zt}5xe&gHDo6%iA zWf(-F0SBk6E7fK9W<ZC#JIOqNVU~ej-He4Q+|IcP|FxyX9k^r?tNy{ourtxj{XT3* z_D#eI+3TQF;ZAWF?8*!z*)g~@>R3vsKCm2xb7I_(<thG~X=MryEPv^n{v3v5<}($u zU1Svy5e1lTgemyjT~Ri2SYqL6)pVQzzaT#2iS=~zE|=UWMG?|;ux=I=(qi(qKE};D znf&&d6q;bGebPj8CM#IWgljJ?6+UW?DwAmF5*>392t>f6vwy_y9lj)&f{PPrurRr4 zX2@wfuyh0fn*3cRXWzo%pa;qwGrpE7=Mc-~VH>r6%{2~!T#%dHK1V)7E0aN4NP?S> z+bP0llfO1~#Yit_!41K<sTCDVhkFZCh-eJfih<1vOd8f`Dz*qw@<}_+Wi!T*Dd3A6 z{z%x83f(U>4<P=7QIAHe`6bT`tgolI`bdaQTqoY)wtQ+Pe2N}H1s7~s%6fN~#dCBB z$4=#dE~<p3ZY9Vitk>b)R`P_Oq`-sXZP9^@qSt!8&Py(9J$HBb7)W;A#%Z|$!iaMJ z*q(S~>i$sfp8x>ZPrNfiJPv!JW=6$GS~@ClV2sHCqs>L&iX_S15bmWF8>dFxG?FHh zeK>C`WRHl!>X_uHuqj)5PbK4+^5w2>JGi^CNlXR<F}N}bfDGwag1}Yfl9NEUvN2(~ zUXT!e+Jg?5GMM!P!j+ay@F8PNHvw;hv%2X^zDpu|iR)l<ag(*%H$U}N4X6>OxLfv_ z?UG_Pd^)U{1K)~XjK>44F$G2KHbqjr2s<mSq@zXA482eXweHNdY%s+{7+V@0@d2Ho zi7}z$M>Q~n&}goa(CDu7fHBcL^sgbPQjB^f<r0*8pvYgZaO>uX3!<ATB4NAH#6d)E zMk_rb0(`XgO*s$}aDC0Kl}80sUK#|+CZ(rwJ_R9^^R_NT_zV-p66Az@qDzn=8yf~q zp=I2*b;0};p{@T?ZkweTa#LTqoe%o&{zt`M{7aU5dVnLu$q<Ip6O$L~LuuWz19ykV z7Kcg(5B2x%E4gZSXWiI7v14!CRHi<<LaPJ}0&_0o?W!bBh)`Idp+QnzP>zcl<t!dR z$Q1zk)Ip_BA$ay9-r$FF6>fm2h{xy{?&%&&wzE>x<>7!P11)<^s(PikQdUE>VBvmo z7)30=D=*Ud*9USNY{$_gl?qw_T{&*e@A7_#a%o0&x!kZK2!s!ormCw>Db=7gXVtZi z;(#xN<l>-HJB{+xOz4U+e+IFHpf>1pO+@D|x^{_*4AZ?|+#WrL&-3(PDbN4!OjpPR zlJJ(%e9@}AGM99Zb{TK62o4>3NTE7%2tW>oO#U_!2Ut5`4|ifnj2IJCB?lQ1RiQWn zQH!A`V>_H(bxX(1S|S$!!rZ0~CVR`pjW#o@qC%H$2r_Zxw|Nuhisn*n%)mOQh`fOu zB9|o4OjRv~`0|F3_<+pdS&cYlO4nOU5z!{;ZH?>sywJ2b?M%x{C77MAm+>VTLdx|) zZn{7*dj+46>&)kv5;}MMgj6;VFT=iUJ~xkw76pu_bp7E&oo(@-WvZ13=r6?I0YBDq zZ?(ubw|)_oq(`CW5wDEpIFKlg5Ls{`?WlCR_>2V<SY4@1oISHki3LY;YDIG71D(>H zp3^ImCXxffSna!z#ZjfC&u&YmE0HTFT<uOT$4DfqE!02K#O>WhwsncUB2~atk0RxS zAV|VNO-#@e!f*|+9P~5-e53{>`8`ova<9<4USrtlQT6g6jlDb&H|XHACH_Q_30ocp zXCWLw$$P+=hE;6af2Jo=r}Q?-H{}8-kuaAgg0rQOA#s^QZV5CHGF)sI#pxfOz0*Q= zr=TO6>M2^~yvAD(SyUP+G1Wuz4Q6Eq|F~)fixx$r1PN|3A#_S6=x~t99&t!e&0U*H zT(E`6u@y&TQ%fgcY~fVTotr{M28>XA&Wpm->V3&q=cc#3Z#PwLyhvGZ><$%`yGEJZ zTlGRy1X{D506@arp$O23bOoZ?g(!TcfuUGSHfqr|s%kfL3no{{EEq>I8D!><_3fc5 z!i>N)f`H1BA#l<6j@%Y&?G`ap$oXMoZ14x^Zwm3jEJR?crm40QEg}z~20wv1xsD~= z(-Eogr1;$Iy*4{$0YB)p<ppq&$ORmsWp>Cig4{g?B$AyrS4L=xCDa8Gd#1&;zpDZ; z;>MDMooHureW+35dseT0`$90Qir_*>2nj0!vc%~GQwzCGTGW6kT^=AN;lNKn2ZX)~ zuS?!zOl!;g6FCm9?C`Q%#Yc77$hZEF55Ib3KlH_LWexQ>HsNZ}BdQ}E%>j{U%u(`a zzhnMDTLKD{dsRjAX7P~JrejGrav3|uY^)Q)A%NpS{vDM+;E+c9N15XYPUbe35MB^S z%w^o>o}L$JGlmqXY5{gZF%Zn$t8vdfL>R0|`AYQz7Al{0<FpJqi73r6pEF<V=He^? zt_KMN=sK6}NcI}<Qbg`)R$9VrLSfFGE9F2QK!-yhZp$i<vgk{pI|6S)y?w@Db~Ll$ za{Yo$SU!iB^a6HkY&6LhY7TS&{448E$;>eUNh6^+_WbOZJ!3XU<AxKY)GStj+o9># z4cvImY<KPI4vQQSvUEU~Ll&_W7epw8ZcxE);5OW;%g)h}vj#jG#m$3868oG+=G>+L zyzVx%GpYrY@i(p>wQn4Xfk3Bdc<6;*jo}K{u6ONz0EEbJA^{`O0pnFSXl>wyK}@2) z@<=Zl-j%)f7Gx|AbxBKmf-gvXMLC2}>3Pv34_A8bQeg3nNN!_rc9i10T9b|}?DnhZ z>mn;|tmssZJG+K(-n0}Pg4}FtoKc=M*n(bmLZpQW8}~pNZ2B#L?bBuqDG9NhAH(!$ z6F7nXbw2$_9bJ2IXoQV1^?_7$*=dxAg(d%XinQGk43{P>9Kpf?vUY?LRN%m5&${HP zk|KArE*hY+1~*aE0~YC5uQGPRvvxCBNJ#rWiZiE(n}I9w_>{FaRj=(2tLlh10%ul8 z%YqXquBHGsfoyfR?^f3k+dir-fPgk<%2piUKqDKEZH+4v04Z=;H*(U>URqL&JHA6c zTOcO%h-0+ZBovvjH-dbC4A-mYYG=8R<2U&v14#j-Id0IpDOWSp$`5vE#c)BVF|;Cy zhL$?1z6Ki$dV*JX55KMJ(%pFlb`qg&epOfT31s|}-LlNLkqZ$h)FZJCAVBS`B@4^R zF_{q~s`@&kM6RG<x5kQYxyFgBV=$TxT!#V!lbYwTAy8Wz1{^Rq3%c=6DzK1Q!%h13 zTg$*BlHtP$8b%WCY=TK0R(wv7#h0hqRzx{?&KuIREHh03knY#UTYw?11;!yojt@6~ zL`U#qd<nAz(?=c)Yr_B<4JtW5$Azn1pkVn73`D*P?*(dV1GGP^?&v;lX|AE~=*e@} zx~)$M7@@y?DJgSQMJ^NcAzEii1fk-*kQ`8>{{o;UP?-Qq6^zhS(ZEMxLCce0J#q?Y z(NFjC1Q3lsRQQzFctBy6W_(<_91eisG~W<pyGbbo?xJ+sDYUl0<CXNQlu;5kDO(so z&#v;Ehe-Ax#1+3kL;-<RfJc(abo;gN!CZ5?B5OgyO;7iO816uklwdX1Vuv-%3`xuL z`r3JpB+KSA1LHT47SWZ(D1Inm?Y%H15fvjfe8gi45+rxkfW6{0xtTC)wK&$TY1UzA zV(zurF<iyhE-w>Aod_%64GeWaVVY9R{0PW)PSvBIfkXQfkyn0_6b#rebw$>^ROWu@ zV`_Acmx+mHY9w3%1Bxiioe^tMUtZY`LH=57sv0s`VEyCf>rjhZr#fa_c1?|Q{Qfs3 z4gj<Ga$aNz^-5x$n}sC-p!6FrIVV>KOGqy<)vnoPsh#|`*x&UbRWK&Rzp_6hNCC$P zT8ruEZGeq{;NbC$nptHJCQGhN$R(%+Zr67=Hjt-4PUCetG9d=z=n`utGi#+cD&ydp zOxe59(mEmrO&iDJ61U(Lm+M4Mri{M0fPjM<hzF9A9GQ%Bc(@@WSBV+?2q_El;Jq5f z4ww`=BEE5(zjs50bS_uDY8it;<(L5(weDGxAgvJ`bN-Fi;G%#@sBcJDq?R+qGcIe^ zk0>T73;Ty?wCtB?41Fn6&E;t>H6zz1dg(wX>!d?aDy{dJ;jN^dDM(j$f)P^!Qq5q( zH6;m7|GB@$S4A>@LAb42?-!L54<U*b?+=N<T)0z1OZQ|o217=gtB(G921^KAzlx%| zRA1g{YS$uQju0|+YCuef<iKw5kyIN03k7!y-0=~lu5#~%c47R0w<*)CxMn#?8Ld2? zfzcG(^`n2(ydqw2<_LFdwRca(XloEA@b0Q^a2bFjET637M?T+%Nl8T2B;S#`h6Erc z^`Pi1!u{Z-sik*jWqj;jq+Ed-6HMt*u>%5^XpmJ0t=5>VW=FZ>(vOgmyCa`p?z$`x z4dBF7P;NoDZ9z`VH3YFa5tNoYW8^><K3Or?6WW!lxvP-g2PptegcWR=a?F5M2RFw0 zG=h}25>i%Y1`K_scA;m0OxVjHt*v^*PX=)lUjuIenIdGF7bB)6cza226m|{H0w<RU z$C0&>;%09^Os;}BgG%;*3x-au@u!A9J%<Bk+f?K_#A!;*S}_5OxQW8YH()9lA4G&k z9+s}9lrxCZ(fCV9R@~6+qqT($o;c_$s@?g2{_a2j>Qj+<0qFYV&CRr|`o=lWLS(gA zAWc~TZ>U_|lnCWsT{EUUS!2CL*BGl&Z@@-5Bp`~P{sCmRijDwP*efL5toA2oikO=R z0&~g&*}OPFv-vEEma_I`W(xnvxwslPd@qebdVoen+HSD;MT{Q9pQ-k-0NvOH5^DYN zp=LLdT2{NZT3XpK>C}KNVbs-&VI0-pL6Y;M(}^bFh#VRp>Y2yCed{xX3%JCUa~x&s z8a-&Z0WvB0Y+R>XtBFlxLzANu0SqKF9kw*|!ARls*28k~b>HoB^h7su6Q|5YKPVqX z-nvTY5_7y}@GsRcu#cFR6PWDwE>Ph_{NR5Y??Z7ke!x2mhR^`|m{MLgrKz?8lhp7r z>Sgla$}`Z3US)5cQJes3AsfUl52v0Z*PF4D$CN+ptQ1R>%}Uw=lGF`Lu1wNaVimY| zi;~b_8*1I_^`|cVuj5=EFeqkrak;u0pv$I^DT<ff?MWEWYH_r+Z)*^zgk=O~jXUj2 zW)JV4xec>t(?%Z`DB#7=nJ{Fj0f$>eth?^AxOA^!%50(-JIFSTVF^w+GsV|EJFyv4 z85JmB{hHos5?!Ixn*ke<6O5YpV<I*IxG2hIcVh1MMp{h6(kVx9T1bS+*{OC31R=*P zu>e9<#%}UpPSJ|w05TXzVTznHCu~QsLSZW+QDxvfp|yjv=Fdp9Gb6`raT*qsr#jmt zumj5I!cht!fEDV?6;y^hRR__vHPc%dpT%-P7Gi%Cg$Af(r$k<)aABAjZ7M3wdrD)Q zqBaF?bTPRwA~W3O(EtS&rnE`S;#5!sRV7Hqf^DS3`Th|cl})2!B23zlP_tufq=f1` z+dph(zCi=O-b=!St34SE8*cRNd}dr6ewEW^P<7m_8*ceXKgdfH(%m|1E&vcP7*oxJ zIi@@50$7KEI>p(sr$}aZ=w_?5*MO#2D59B@xp<t38}TkdiSGZsqupTz$3UmBi$LQy zxc$B$5`hLOU$_#$id>iWUiKN19hdN>xEc5DdS-H}xo+Uev?^37lh-=^t-c+S&9tY+ zEM;zhTt<FM5RTQAEU3x`XAxz9<ZzGIr*joPsVcSe*!Mu%I|pX!2CoKiiC4-x%R8Yc z?;8K_vgLjGHw$8*4QnvORfK0ujS7w)v@W8B7NlN4xgFU80fzH^JcA)#v05GK^7u&| zNKqq74Ji4R)ox|YKwL|*3E+sxeY6yo@?Spu>d{&V1y)MhRIrV~P2Wg`n~RZ>^=L)m z;vK%^6nSe*8W}aE{7_dO!2VP^X6Z54<E`@rut73_8+gI!gF*ntGaNrLqh6GTLlild z0pU_%h8un)2XyliSpXSwTy6k{M()=2mXCHCn6(ywEmED3w8X;fj84b0E9kfU0IbF1 zSZu#1EYW*vCb>*=WsKEWk*Owd9HAkICX}jCilBx%8~_4<bS%c)`)X&N=wrnW)?=nP z<!gHeo4JXX-n%|dlvyD)Rz3Mt^JkzZse4lTQIFaKY@EalNk}_#H|tBsg(V(YBz$pu zmL9}nU+(V8o5{z(VL2ym!QTi1SQbrp{<sETF69Xcn9m{{5%HLDH3)W}4@in3iQC@< z|M0AY|4(RC9$E|vM9C~}ta}?cC~*PkOS;X2AUc@~EbnxaG43M45VJ)P^3DmfdjDU# z-aokR`@GI1DS?q7LX|w%3WZ&FMS7qDvgnG+mFmiMO$rMK1W5$|<;G<*twb(cz!SC6 zwp!05vkgU2hzyHah`!>=R9u5FM2T)UwRf*O>a>|^6_MG>lMM+nU601wjpa0{nYBBU zdYet!H2XZ~{oV`6?fxSH7vEp^0zB{eoO9my!$S^mwP#<|9J#H_;v=Eu!I^*Y!W_#o zmo&WZ*4OXtKJ;`gy&ifQ>z=byJED1gVGdbsxh$H_qi1+B(likTS*Gwaw6-jB^!gch zKwNtM7gyVZhxFI+CA96S7r?C}P|vTnf7Mi3)-Pw^^Bi!t+BsQK=$y<Wgwa4#%M_Yp zVE98b^Uv4!M3%39cc{$@g!14*gZR`72Or=(sPyV5cQBL2oEef8<Xx@JJ1A{!Gdg?| zVP&K)3dt;(ss-_S<Ka;2SOqO$=Vyttf-U0>h<7od26Ki>T=49Z#JuQ{IcoiwI)<%t z)rkT)@L>P>{Ey9!t~}E2Tw0i(zg7)EN4`i28lNA6*p}AC!syh_SPb|yyvnkO%ir@0 zNq(`IFchrP)cK=%N&w!${R<WcCgZ5_w7>7+q>zAKwv=H1LH7QgoY&pP%hn1a@tRUG zhPBVS&CL|-qqJnQxH&uZ)Q#*eagpgQH=Soe1|P0=70L#*8tz<g=akJc7$X^4im>$^ zb_LXFZoSQi!h)oRYhSuN&(!VOzhd{;O^Qz|UU670M^l25u)upg;BtcUiF}lF6fKUY zs9|OGqe|Jzc^_EI??l8^5IS$Uz+HgE1L=>AjIfG{<AJ+?WEUpi1f;QT+S50<IO0tp zW$A-QLUYZ;lk^xq^W1vg_`A>3Xhap{O^=X(a}C1Wv|20WE?Orp3MdNH3Y$eoHs#w> z7yXomSTk%TIgn8|C99EyMgUXvn&}k-MsDMzaQtS53(cwQIJ28yE*}y~8w;-V(Oj~C zWo<$hniN?M{G+WFjbHxx(+|(CmDjGe)jB?vZvDm`F?fuxfhEso5aRyn#U*y0uS}PH z{(U{HA4;ZG^YJP}e8owrK19x3d{AT3&r&6))&e)Ogn1<jSGMbm^b}Dl<F9F(c_kI1 zX|rsWAC0P1&O8OBGqZm-HNaX@(*$-M?@nuz^qu=GPs|y6jqXAf7du$|szSqjg*Bo& zR_;9}3gg?(u|q_9UD~w0Sbes$lE5lq+4U&DxW4T|<xtaVUc8Ts()r@bWNwVT;1f#Q zP7I7!N7djqPtNsTy=b_&`d|wBBQg;~ero6CLB{|<)3q%WyK0{3%F|)ptQBw&VoPL| zpvCfMe^wuyH4J;9v$j}LI-)|PuSA5e)bMwWiZ!){Wy+Q2;9erwCC)tgv}RhtwWb~n zrZ5etXSuXVAxJWqbwi?B>lG#0FGqb+Q4$Z(AbJ12T}+>*XqBVGTI-(uEQx&Rr%=w) z%!3J1*<%(&i;Xi<k!tt+qhe7&u6?e4M0A-lG`f12Xu{L8S%X}^b8cpT)-2!NQ)`}; zm#0RLEvx5rUzk7DrfZUruuUz@oX$i6n=n~u*uSy*sh;kYB?<=?Tw7_t&Ibqz$MKlA zEk^FXvQ#IKOb*UhU9j?Ovv=j5#qn4ZtVdXe#C%T#Z5ET8@2d?)nm-e@jM(oaON86^ zJ?ecaPi)CxQ0)E0oY_S6U|T2sDK}yO-dSz@<ggQE4(>h&Zl4;t-)Eu5O*<7}4LcuQ ziJ9K5_Tp4VJA=rzWu8jd%EIjv(B{iD$ow{hdX+pEo6bG|#Dia4#NX*Mw0h)z-sA3{ z*m?T3qfffQd)xJjs@gr@Vg3!*w}Zt+LWa+<E<s3ZU&^3Q=CKWZ<jR57`zeiMY~E#K zB&(Y5zP`+i>sI%Zq=Kn_Cl<)~j@)MsI*X#@th5d&8}9)4T)G*WE%0x35&_av2E=6Z zy;{alYDMkLW#Kj;`T<%MUH^<S_KmBUZ(hC%OunFErLd)+%*(`<Ub5$%nksfT{fMp- z7*PP?pLb^HLo}d_)cRtU?TmCYo>v3Q;2YLq$2%uy>Heo?ILO;4p`NfoQFA0qr+DAC z-4LtVLW3n&_py8kTW%aNz#a(RtSp!e8ubAwBo|C0Q@Y&j9dJiTYn<~q@sZ^8QJPwW zy~LL{Vn4Y-(ynF)+nXseH|U-p*!r#xe~JSV7$wtuT4s;>KKS^{ONsi&CP-7YkKpP> z@GPNa&c5OQx-hr;5C7%=@cReAF<tMG4<W`ZDm>lAQP~Eevc;}9+~$rIgv`IO*!_ya zQYFJGKs~@}*7x>u`$$GA9Rc$Dg6C3n8(;KO_D{~UEE&6JPt>d|C;HpG>gr>*55VIe za23(hrEUPD|B?QAUc6WJDPJKW5nQ&D(KSeoiOJf6?iW`CSsTQhS-2$FyQDdnJXRE} z<{DF@?L@U)AaG0!5Z)7pzMJIno|;W#Ej_hnS%^)43H1F-KYhg7;zy{e)o)$#VOVnz z9=4ywGm*18!!A^)F*oD8-?RNPw!_SH+touCC_Frx<;7xF3-yvR7TGFb-0+kDefn}! zM`p?jnV;D5Gz!%9tOg7ePwc!5jYk2pG*CIP%h^nCn7uIuOR-{b4KKzkAwPxKB??b! zfa^Mh+;^B06#Ih<sBWcj%{<b=it&0cv*kk9P+1l`bq*aQ{*ZD}-uvt#<>$=}g@T*9 zfXT9=DHJ^qgNzp8tluPRz*@ndHRX^Y)UnqopN9z*xQyC`*M9Ddw@EU=&qarS^&70! z(5{iH_U+-nHg<k~mpwHsJ$`KvPh|CQN<jC@oXG5;GMYwSb^bJ?nh}Y<Vg~E#DLj)U z26-t`%{?z>*XzIDWVGm3OmF1`z-jd<y91j%{s*EIbbXN@1Pe>v!q)i5s8`>j{iByC zZeP}yxyI_Fe017WC<GJ@iVuqt|9=*_YLaT<K<Br|4?g%MYDtpBw@d4_ziESc@)0#H z5cw1;R5D&z6udn;K+|f^!e^Xj$M$#jAw$_Fzg~DI)n6VhcCVAZHui&;aM0PMr`^d+ z85SrCSJ)!h+q9;DW64{=`oCy%=eL|`b8-4DJ2sJ?h5=gV#YoVP{gf4pb_$y>?^#$_ zJA}!Ag&@#Z^9>6aE`tHCzpeZ)li#VYVL?fMiBo5w6qF0zU3mm7Ww2UUS<KVrJLHn! zNepv?Tq;QbV-iz0+{U6^?;UgA1n?Zi%nMl?7GAn}(k2jRmQnc7Z|cfWeWb4RjZ8hZ zLklLYC~dnFQLns(CV<3Sn*M>efIf7w-C2gEs=4?e@YJ+ZB2cMmQAot}Cw2Sj0%iH7 zjgGdox4-!Cx%c$)xHDWe-67oN3dKmp32}?hg?E<S@><kHR#>dIj8836ZW@0?P0U+v zqH3YErTQA{J-&by&XU3$Gz*f?Z0>dTXAhsL306!%)2}@_N~L1O@(eAKt?A8d9x=+| zhb5OwK5F65eXlk9lmF&NKmO16Vv#QaVWl?x7UzD5$s|Kn7mi1-Vnf^Wzr|JiTGV<D zc=3S1|2G}_oO+YA@7<P|7gT<}wW(>_&jO?X-!e1BNHd^Q9LFX%SnC2M{>O{=0@TU* z@*hR3_0>nd`sP4SQF6jcvnI&mq<^4`hm}`)%Lu+oqhju*Kt}%8HcQtlNdj-n4K=#) zD@guYrM5jzRr_>SDsf8qPshV47cuMkE#a$dy4-X&mJBvr4thM1Hb+`L{=qljSereY z%Fz^-_2@6v=^^$2_#kNQH2$bO#;ew}h$krRwt2Xp_R8Q>(0+}8DNXWT(D(QD0QGwx zp(V0$!&yg&svg66y-;mm_Axk>nJb-aRoBQ(Z#uALt{Jvc1w+GpC4sDKcqI|FFb(cl zuNvuV1hF;c`JlR^cGy$vt`D?afA|dhz;xDhE_W2h#$OBRpGcRbS{MIdT_*L)17--% zP<!feAC^$_=wMX~tY>;Bz&~v?cl^R23Rgw8x+K4n5Vne}@&R3)zs6_4O2oqkc)z=D zWg)eHeAi||KjZtNOW|Xr-{aRG6#4g+XmtC*l#U&$QP>uZJHd_w#Cabyz~ynT(bQN` zEcU}j#<_Q%lxxOkqHdiUaccqNxXL?qnQ^)S8KFY+Atp4<g3STsZ(RypJ$V1ZS)*LT zJ@x6O%VmeVib+ivQidWpMXCEzc3frQBkJoN+t}Y;WN!b}y_541%_^?dd7IQ%wk#k# zG(5H1rjY!^MT*v>m1A<=926o^XW<1(*2zz9%U0g*)yB8X{n7&=z~!mOhT8Es&e!VZ zlUU!c0r?BTFU6%pqkrq$u4yvC<&@?JN{FaVxe$R50yh{FKUj#v4xp)X?Os@9sgz1} z;O}ce^Y!B4@jW+9;2K|LGt?eJEBG@&rk#;zNdr+N8mq#(H134PU9I;&*&RL<RYy6j z03L&6M|O#Eds1tX3y(kZvlbuRVFJh$3Wz`1r?pIqSv7=*8l}RcckSAx>w<(eAA>Fh zW7IFQ!QJ6ZVkRJrHNyF2mRtCqTWxP*%^~Gy&j&Rm(YlsEpoM-*4Ujgo)ksTv`66@X zc2?1#f8_a@14nMBC~PvZi@G%x_rjPmzjn7w@N%qJ)S!$5Qw$#)aide!yryaMX3noc zoD?zRTNF5!5<D==o8#nzu{aEh;nnkB_e`xhGArL{)=G$RS#{j`Z~jha=CA$J|LV8D zsuESJ0Tvh0pBhnVX11TH+SAMCs!}CQ)%fEB0IxHa@w}@zq=wLZ-z-ixl#iyrgu^N_ zWgkVQgDaZrmG|VQY>w8O5k@KK9o>L?trx1qa7tf2Qf#7_74}<fHpG1S7Sn;sF#AnD zuq-x6;ez^@_ou6HO#A%x+GbJ$UdG53Mak9Jxu({%=`b;-n+3>U`swDfvwYjTvsDLY z<MiTCRg}$>^8~Bd1fY_<?!%_D5~_ZB2?GEtdtldHzxT-M;fw$SmM@QrxgJsWg;0&b zVY*6-f|!wUr|K5*z;#&ecYD}7g0AEIFH^9*aaJC#9Tb_mfIpa<0<mH7kuJffg6-c% z(YemD0H`Ky>)lEY1N`lXv@Ts+Sz=%c_5!Evy5(Q;3~8y1a%35BC177iPq%XILSowK znr3({3a(%f)Xd^iMJ#e@1SwA&b&18rvWcuKYf4nFn9Mqy=x>}G*DX3MtfE*VeSR0^ zGcLw1;=l91$S#J92fD2GpP+vHm!tgNXb6G)&!4w3BwD}iga)YQklicG)RT-vOgrXp za^nBj*#LAcDcgj48Ti#KC(Jgv?ugVx2zT+o6Ly?jofzUeJ730`h-_m>*GBo&f-f;J z3wu|`yVAbHU@^j!L%XVlQ6HU<)5?<C4>m>?Lj<a9B4NdW-=N0RsrAS?5d8K>+MO$u z05u)mj9K-fyi@E49g>%>BI^GRixwK;{|FyKgQZpra{74S;5($AeMr+c!btwBfIi)R zEX#~Z4KWslKKkXWj!B-EOj|58T}-A<mr6x|Dk&??6RJt_VY|y6p>VWV{A}-_3C2jj zzB`urlSG*GvGIZTJwkAJclUPmc}mm~{f{g8dZ%g(u;27DQajShc#hu<HShR4^mL%s zNZEf4W4hu|7`n00t7+piw=pkmwOws|m)d+IgYJ;zeU8c$C!II6Ti-(9rARPOOP!yR z!fGhS0v`QVhQCbQr$539<IAn{oCp?w|3^dqfm>V{*D`GTspHKLd8AvdCG`7^sM`VM zB(9+Tx+AcBVfuy$X57PJ%Fy?C8mv8N8a&c$_<3g0sbU!StS_vFZnS{fl=&!;wJ2W{ zjRyBI$;|*zN$?|*I%d^#ppmHD<L&s76vOOd!vQg4c+ATC5_ub-^7{R2=YQm%LYV*k z*MH;pe+pzoaM~B0DI>LFU;MH%Ph_U!^eF`Ymw>r^v9474Ri;e#6e*;ZyFlI~cgHzC zo^-ZH8;<)C_Z&}p43$dCu2h9<(KQMMf+JHIeX>LaeytdB5zcG|mR)YVn9~CJ%|e8$ zWc~?P<$eXgUO8W7{Sfjm<oDMPy{~N2*sjxHiy&2rdY4G=f00xC2vQI3vsy1W0CItm z&`Z}+5Hd++`(>Ka`$JcT-v6>U+)lY}Cb1akEi3#ng10Oz?pj%-ibb_iYuacYH@L5k z0x6~z^v&y77vJ#k{)%H)FM~VEj%Nq147k%7T$^EC%`xS2WGdDNCbpb;MP^TFh#?%W z+QO3fQ8kosTXZBUOSB=Mi^-1fWT<dmT8mrz+N-cK;9t?_9G+q<N*OB{9YZ6cR$1EB zrs%@O87bB_y5o0}gW5+M;zQ<X|1!-SDPyC6`dSLX&qPL=8c=JyI?pm^MhoI|8TCbd zyf*mAHE;cFJ4K?5aB2mSDwZ1E>vzt7j`W!yq2b-t80L38+rA1)=qng(Dr3TJqe((l zRLW$m<wNcdoG)F?ME%!ld*}uJZ<RQEY+L!;j8N&Mx<Jma|4mpqrz7)VXn386ofa7c zV*;eW&QgSO#Es74^`Zkk+87~7OffD#xvl(ja#Aqsov*oo`R?kWGMtBYKhKtFxaQ2k zih6_)HR3X4iQ$aHPfXLor`d8$1u6;=<k;ZT!ZVMsei)rc@uuH>7=nA~;QhaheevJ7 z3l`gq;9^BWVR^DF4m&n(pI}5Y1lkpcN{dYr_JmCGM)9awBOGCx%G^bI;?AKPA-}6( z1-S9nGraMbu~v-l&uE)RQtCk2-*pu70~15bYeaBZp%BVCr;AWqmED8_1YjMdU|=9X z__JsLPAwiRr)tVSj9n@XOSgyOR2y3F;sv{0S)RKyZAx1{p0ehFh#ObpVsxyS1x?-+ zZ-X+x&u#Dsrc)4eEY12XA!ZJ2#cED^sGf~Fm2M3;M&nWI+fK)}jYD74fnVv+b4MU1 z1*kYX&&BVvXJ7DkHc=;#y!H~0^2;N7?=B_cbf|JQ<zc27X|fqfh;7=?qng_Jyj5j& z`SIFVG_xT$(>792pJmf-w`kFVXDt%*fvea0V<jJx_w8&;+=}JJ2BmB3&;3ek=CA#e zFa7o#3>B^cS)0npe&s?9y?=9Y?8hcu6j%zX8?e6Ud(|VmMuPnZfa+!up-}TW*gok? zf^rU6-wQhJ-z6AX0%AWe4Qx$c#VfsSo`GjIrjK5k4Y7Z0gaae&Bs>-H7Og2K%U4AC z5c}q2YDxx@l<)9L!cS@4tH=|A)c9=H2ZiXo$<nwe47=W+UJ4{8qe;&YrwYD%$aZhi zTNzkISR=eK#g3O&jK5?FqfujuJD(^kyshiNL4Wyc=M3QT@C-T`GySxEga7aaz;0qo zwL-+mUKDh<oOya`?EcGG2f!w(iBTgL5S0o-VvnGc6w*Tp6L}nrqn8_6S+yIxTD32H z`G0a|)#9jWqP}}zR<`_y@-0?rX?H%BkQz{b<$HZb@6{q5#Q-k}C)KL))V)(w|0_vG z1&lucf3F;F<ytY}vBJH5?B*<4s4tC6&YGjKP>fLVF3nm+%F0jbfmXFl*4C!S5RI}T zp=PpLX__^dZGyzb4O*@)JQmIE9R)5jR+uwTM9W8rEIB2e0!@f6bX~N+dJt=2u0j3P z>30l9J!*A8I-+d6E%!bcRDXAj2_z~|KUf3ysV~SR)1dvoWk3n>D9$^mzrX+!s>2I4 zS3eFj150!XZg;|BoyHnt1X*S@wPRwI)q$}iS_z*a_WJ1s$*o>E^8GAw7{)YWP8rjv zKCV~(H+N&c$SPs@T$6HQ^O<>)QLc`d>^MB};NP34{f~I-g`w%oKs$!WJt8;;H1_l( zZM2Q62S3`not-nEnNqVS9*aYM=Uzb;CF#OFJO()CG^<5AG``PWX{>;lVi=?a@22w< zHx@T#B`}=CNg1&uc%$!I0{y)VYZG!yh&rzueg))(H<&a_gN3sY{RZiQR;x;NV-Wsz zkQd(a<}P@-wM{Ok&B%MO`jPJ#xhjkK^yeVzS&&%U9I6F%cQhhHeV5dPpz$xA|Iyp< z{*$_ej4STD7|^mO1cU}gvo{(K^#a$xZJn)D@w<l~e{!^4RG&r5yHfKb!%n`ZTJUxR zWZZLgd?rXD0r_<L24l^5#N%F@v}(wC77=>Kv~h84w?YG9?-zNFSnECSIZf^`fBa)R z@h-i)Xj->&wg_X(*-+YzR2Ys0?9_(NX$-%($?d(GTd-n5G`C5ekO#JU+R)!cK%*!y zP1uzPSGR(^@dr4=|M36(iQk`70J@~iu!V$EV4OVC5OPw;e*yg{yM39N9Z8b}D+;uf z4_0xA(iFNMDe8>4&AIy~CWZTNa*AZ1BGE_QOrc*IJUljbAD3Va!IZqe;@EZ)M~xEn zLv>)%8&?yzb>Lp$SC@H}K~-MheP<AY#CUJs*a&vf?YQ6tGeN|!7~T73<6~q}$ouaN z@C)r}n6QPT>HUr;p_QJc!WmZ%zkb4`lD9@X(gb<_qqDdOw0}opV!KF#uB;B2p4iAo z6RjF$g#zV|U3L8W^8@sDU+X-JVXW^u2ai3_74$1R3iU;6G5ND$5uv}_9UK6=b(w$6 zf&uz%p?QL{JPw<79vQwQnNsZyDs{V8{sj^hXge_ad$YQ?d%ZG$W)SYG2k`VoTQHa~ z#X3E#x+m>$of&buR3y}Yahm(}vZ*XVv_xvxudbs)6#grPTPoE=DLgt3-=<DzCWF|< zV{HN#-m_{j^LocG@YmL}N^I8)ivQ=lX|6DMr(sy`$Kqmb@$_XRuUA@k^!@7gA-2)t zz3<;U_cK<aPCW4wm(TNw4^srPLkV4bB_S0_|JI?29o?%T^9%X{z<FSuQNCl)=6&Gt zLEMT*xj_3W>c8=!-##?iL|Jhm;PfOpGoP2F6W4H^!MH*yh5Hm=#b3pM?y{^PcMDwK zeqfHW@Z{=OkerZK>WV)g6H7u=u&ouv7ba<CU_~+gPK@Q3V85&F@)DkyvA-MG=LA&$ ze>@JBL8XnGQZ@im{cFGZB+01Q$qR&gB-X2p*`1r`e|WbO9C16AuyPmGfg>RAqdLI& z0~EY(uDmw)1U;n?Z-P-BBp7{PH{5DpAEV(Lmd&Ji4D?r@YykeHP6vIZfZu?n)~r?L zla~mo0<|D0<2fehe*hb=<WM*2i#iL$+*S(3t8ZodUhB*&%U8D}Q(f|+Hq`y1iU-cL z#&Xjhp&Jk`&r>V|>^v9=9fxDou26XMHuG)IxDVC}3HZSOqduwke0a=mhubrH&`*Mu zgIIY;W1?Cl^d0Q_M*hJGP;k-(&LcPKf3p+S3sg>?_?@vyOA-%5O<)>3G@ZPv3x={9 zZg3um;|q72jlHO`kVL9(N5I;u!%rN8IK`X8H%iladNzQ08b4TMIdLR!ac1J9&l+*H z%UpnGX{WQmkas<6(8qN_nh9A;q$?068gpgSA3QX=^3VRx$N%{oD~TFSjco&`me?NA z_-Rr~;&~YjOXNn=)_`=gZW~nm=yia!zpV%fr>R;PWTeOg%0_pWNFxS|#w8YsnO^J_ zq@u=L*Z}cdBgG>@B31}>X2P+B?P4mZPdUm@CFU<~+jJ#SCE=P=9>6$mY6ePAu3$}Y z)2vz&q)xqgy0a$XXK8Uq<2d)01HEsne-0NKYR_$nCm|q}NBy2=2*!oX6Fjo6<jE@C zx@GA~bKY)HFp!Oe`NEvSi@>|4Uc(ZgHHdgWK?mA0TFe*6+k3|5V#E&EnmzCljCqk5 z3522mx`DwZ^>c+=yMgsRv<YZBkji-o+x41-pwn9plsOUPE+|G4lJOtXrCryhAmL3h z2(Bh{WLF$1sf^(m8({UYiM0UO-u*TOi^DK=Ghd1oED@negH}jE{)j*5raDmTni8NM zM$U?#xSE&%v?*WqEu@*@@Bw-uCa4i=PzCf&1**l-TGSxCW;-90jrd$#R*beB4&oG% zm=x9lZw-;-IZg_=?JI@&4tK(GW!uI(7Bq03K#02TX7mwvI*K|XKDMtZBD9{LXumU; zHH0k%9<}dL0#AX;2tluPofdd?-U%2?<nT(3t9!7`RKkfJ&_(*Hbq&f>;M6aSQ(qL9 zh}$~A3Y?6P|8~8;^QFs;=YTX16=$f&>!>*Gw$;fIx@i;WP4U>?EE-ZnoY66alC=A| z)B-#VmqDmJs#4B*w+tnj>Z-)GiQia!uGRoNJF%72-*>umg}ty+D9(Z3B^2oi0BO~G zO;b1o8Ln)7A|=J=DXTuqLO@7ooNU|m1Z#s+BLjx^Yu=QTn5HHe0Y&Ws7a5+LQUE!I zSyP^<IzwYXS#Y1$=2wZ8T2q8<?Sg=@^xm<$AY(SxrA+MhS-4h7FQw<d!JH5fS)~O} z*1l+-OL-mewWDF_3W?RMR`BnyIYi|3FaHXk9m^HwRW%I=87hbo(D$Clu!HZ*vLLWc z&<7JitfprVy{blyz|+T^tO(*doud{OO;m`_vqm{Nn6Ms%_6R5%Zn85zE?sGGTB9U` zK;Aw5(wi(W*cj4FedkHm@fCU6q&Sr_wS~X;1DO@2r_iaVN(d@ey!(pm-t!y(Ee`A- z|L?#1hkyR@CU3MVqKVYTQ+oms^KI{N7(2+S<TF)qRH$+}0}A$i;$P#?s|VYx&nsU8 z1ot@#DU+o1idR-|q|V&O7j`p@Oj-?619}I2KHPgVcT1Qk)&S?N2JdwN+E9P%f)Dgn zW26)lyQ+E3uR^n7?1)SGHc=*TocQSeqc>O~C<~m%h{8|3`AnrxsXaU}F(m~5T-sXU zGNHL@ww2;Ri49o*T;*5~8q&`%gpg9-EMTlHW<i=7`1>NRx_8e?=h5AtgHF%4KtmFm zE1Mq?e~V(Hew0zmFALyrU1u;LcCGN97KOkoq&-Lu#s}PMQ2G9{89+<omzIQ=9|1MX zdH@f{e*Ey6y10$elp3{>r*f%pL(jQ!uc=KQ&ymO{X--2+`Gvkq(NqJPFA_dg!B>m{ zwo`{J1I6a?G)&Bb_!4i_n87DTOYcu{%l*H9ZB`?EzByO%CM$u{s9rBWvdm)0jF2V4 zQg?0T>_fAQw_pf7NZXqn-_cSt`}QnT+;A9Z7pG{P;M~+P`W__z+~F2JgsH=)Kc7tN zEf22^v(+*!3{EXN#w3i!HKvO=E^_-j3_ag*9-dAJb*PQD5D)p)vyby~H^59l3H+Q| zoo0h~`<d}=Ig0?PXN|NoSjlmNF@;r`eh^>RA73~Rp$A%-U@o!$qbDTc?>bGEHGmtx z-{}v3bBCcGkW)eG_KEw^p&t3**{PK!SU=33y>BTLlrNVAlk>a`BWF)Rppzv5Z%iH! z)R&6Fd~?iS8Xtr(Vz0J8Jj75bWu`#%?fwq|sM*)aWKpVB_Nw|W8z)|kY7^8?%Nsg* zn$Z-PAfWc{xnvN~&NY%fivqX&kWP0-<k8!&qJ@*B)K_qpIle<M785oLheLM1*#%s6 zLRZ(bItx@B-itcZMPM(TW3Cz|*vpU`yVovo7?bw)zP1#i9G;H0auI<XA9@Pu1UsXt z6*o$vKPg0V59fAlMuB3(s<&3#n#K;5dhkTEtPpyqu)GyfZkS^W5dpj;r0Ly5wiw(% zUe3g7i9PBq2s2#V-s+T=^#Xv|&ITMkU8vvjup4aW_m_d^rcn7<)9P$($i`6#p}HF3 z?4BFI=R+tp8`HBS`W9vGCd(S5IUM(7Hi>}j=5#zyjq6VH?;!nd)PlL?KlQih#{Gkj ze(AUW-yVYZ0Dl!wROaa%huk)~AT%P;xrhGLflX*6)s+DLzIfLz<Q-9QsR8uX0!C~S zL?QHhfdARepO{nSv1j@sLW+lGT>3sKf86Hi?iD%}sZ$x6*SOubl3Um+wltux4i5F) zTprhIFocw&Xm2t3Y2HR}{*qq>&=q<<6+%8z>ioq1@_?IS;9=<{*h-GbL$WgX6xX9n zbf!N|<1*4tF3?)&eKpeJ2RHKs_wnAE9=2K?4ABC;a38Sv^$#}iY<RN_-(G%3YHCtH zfGPFGp#=z`?SX!b+RFDJbL)N{Gw83V<B+CV+3!Ga0EH_6=c_i*%WYTmgGI{TB_jD$ z+z4jv1)ZfgAkbPQP|UAWnyN>-2s`TQ+=*X$=<0;CEaD2slcqS}HSj~*$TER_hGdeQ zyqslvBJz%!X-%m2vssAX{|1=5?*RR8;uHG-hKhJlo|lu{uE}>o&WV-BRi;mQ!z6%O zeoi*M$?9VkGq7VB<$rl*Vy8K*r(Nmfzfbor$tvniUfS1rNoxMi?a*sjH%T95cZcIm z+Jp8E!ysrxIN1IMu4`USfmjiGf!tB3G7cZ)ALEyd4w8)y!5u_J;mNPj_>7T2Ls($j z1w=%kHaji-faOJAWl!50yEJik7<|q7v;TlW;w&I+BYy5Y@l@ntlp<@%j<2v4pN-MS zhK#DVFWoQor{I(pga8lLPtG&dbteS2H-Q`=e(wC)qYC0|MeDs=74dY&AF7REC*G3U zytT*1wWLa6^nBMrZogOwP%@lAFOm{#0w6YHD!}cBVUny?6n>_h^V;nY+OfrL*e%?7 z%8?yz%IaevhTD0}3M0vWsrlni4tcS+dEG8(Y8JSUI5s)QfTnEaN8zF^TJViT)JW~| zkWu!pUKpc$j8db7kI2!v&cG?I`&bAqWWBKjAjEU8wDnnqZs>f-ISgADHLC`*M9TL< z@5HVh>nj4E{m2(TLDQEd?Rdw@-n>EPI6bkIza;XZ+bMx<S`)Uj!0_x0meQ5JflC7a zE(@5MVL&J=fSV__QxGU%ZW_xG@j)z=aC=&4-kTyqPAdMNTQzHrYKMpz)kKOk?K=)w zq8+VfTxE?Q`t#X+l&4hcd42W#=1-7Te~#N8|Ht3!PS1bn4?gsze+76KIfr_Ov<IKj zxh3QheMaPE+@93+E^sg!jU0XTn}DC~$wTY3KTCxVol=`ms{j`rx!bmbSilnZ7mXN+ z&7QA$EN$MuiM?23$-bc6qS;Vsp~&%KZqsEDMaU(|5LZqFX-A<uyngc21?R?o!o@dH z!b=0<r{U*ykLprRolx>g{wJFZ=BvOrW5t_@5Fy|~^WNfM(N<;6=uEE|h$qbZD5d|+ zrM0zK!4!b0!{hkFIsrX>Kf1%=0XcsC*B`7!&Ox>q*ae8+!t7TN{m_LjBe=IDjd^S9 z)@~ZgmS@1>6JJb{e+9W8_6}jL3K8~PjzNJUd3!>lrKKb}R0KT9Pqxcw>|rt1zBk>5 zLTo1>6@GWGtJ;_k%8a9gZ?5sKP-rr)!U1}XFAYjxTX{KELJ#AwQ+IsIkAUXQSn#Bg zIx8piD;k40a?+Z-f1=P_*`}xQlvYKJ3b#Kzh10R(4zsFaa)17v&&<wNCjp-v#VdN5 zm5hs>Sc+TDdZ~Nm5ta`-mS@jS$fTco5RSev@RKO!6Epz>sIh8Gd;fYFybE8LL$4tt zs<vVpXvl17{qT2aAf7Xeg0e0GGW<w!W$lxizZ^SPIt-FL+x;<wf*aV?#!}#s_OQzh zGCQ5rgPpG(g*;v=q25;BbQ%-$+4l&yya{*V6n$p2g*`RGJSLwYRQ!>42eN*Z+)ePl z4Ya>Y!|$I%F;K;!yUd3}S|Yeawx{I+2C!n8LlDQJGSVi3(~*%+eB|on`DuEj&ty_J z9s;^gwRsVfqz3I4p-4qSype+TvLQ=Aj1@@Iq7rE6GK~O=Jm78<<;Mar?4G^@Uz(gh z=wNb3775iDpyD_9oO$CK1Y4O2#l4oL<ww4#EPs}tH>SXF6n#+KmS{9{+>M^vo^30v zX}03(oF+14%P;)b|J?AtrM0su6-R8ig4LH&)F?s+-1EV?+`h{8KeJ<{{;#rD;7Q2Q zXeV@ZDiZfpwNEbdA|(6>bf34wFhNY#jX9xos$prP%HOR19u=rMj^nyo6DsX_#LbCZ zZe%P56DQEaWa*KRV$=E@wH|=kYZK7u{29iz;p~<>e5m%fh!?D#O9kvs|H#*`kor9J z8^3=NVr|+#Z2c}UauSy}InYq^B{5dk{*#-&H&L^|KLIeK`m9Eap#+SSrlZb1jumjB zhvT*&Gh?E7H-~TU0>DC~9>C!#mkm+zpPBt8AHt(w6XAp2+zti~(DD)~AQb<eBs5h5 zPyzpqY<@~(*YtdabUr1<%KGKgJaBX4M}E*v5GP7dPyZQH=@-8nk-yY-m7un-HOqs? z>|C(jSp8lhXKN$xZ>>Io?SXqfGWRJ;F<_6phcns2x3*=&puEKySnT1!lDK8DCUqJ% zY_eXCULznRxM&u^N7M2>(yyA{Fz~VfDu-VxjRDR$!|{DLEC)srj+oM_m~=nHd*iKI zE2<!|jwu0PdNV1nd6vK?N(_Obl9Yn6y28l!r7sETjlqy|;3&U16e?7a*xy6<F@!%d zJ>~;nN7_S$+BY?7>q5AE-W{ip&E@{P_RaA}MjNr493k0Iui_{`sb)X0Ct0BmZ@QKQ z@b_!{J(hOmx?r@m*q9o;JwDHjLppYs5I35=9?-8>r?F*Atk-{?)9Xc7Aqa}EiH2`c zu*ukttrjA_7``|)x4I73j_h7Br|IGMU7o-6vN@orGpz*-!h+$ZbAW^3xa?AtkrV(o zqDfSqxvCW`E}kIbGkg@K9est{9&$cK(<X2((4VqEh9;2D5AXhSt=Pd-0K5veJmov^ zlc3JX?&sTZYlRu$sNI&+_gc14*=IkA%)*Moijt_l62j%R(KrynKU5sA!m&(HRg!iL zQRF6Ukj10h=P)#in=c>14m!k|1aPG|z$te-la1Roy#v8UA)J@6W)WyE)})}mvQo)X z3A9qW<$^^5FwXCXg+ovho=yCR3tLCb|EsefdD<e<d0RYuY)4CUHzs5Yfn$%FYenc_ z7YRfX7au*V_Voo2eNVQXpyz674V#pus`2}tMw1S(8cJaf$fu8x;}i%A2RK33+gl)K z77v?b(mXUDKx7oO02Uts`V0?3gzrf{v`Ij^?`!7(-t?vg-oQ~uNsx!N(O7wZla5IW zi%=iMNe4H<(Icq=RTe%x!j=%3Sj19;H?Wn}3J)-P{zpId6~+;L>%%|a+1mg&vmS_< z1iiuEC8hdp09A$fMc%vk*$yyQ<X=_adDMuc3coUodJS6&iHAx1+YaFCIqjfQ$kcCb zrCLa;4?W3c0`^I9e%|nnYJQZJKza%Mf-uz}+RNd4K4l%)?V0O)4P`t~DgqyMbQMUv zkSoMC(tYQAwf)}vxHc<G2*W;=yWhX5&A|=rUwOuJyDw&u5UbaNAGr6%<tux86YA9J z|8%E`XioF4HVQZQ`n){gtht_;z}mAP6l^5g(X0m#3vq)pdt~5Oh;TM=9;8*iPMjYe zoY9~Sp7!*d8X#Asbsa)MzrLPt^gj-2+J@t?ek06WCA}M!Xv*0=>igicfzY%HaEWOB zA>%nNuBXE+z}X_ny|>U^q3MeurS|3~610UvvFol^r@!&=TDUz2DA`Ajsm8IAV_Ygw zV=M}79=|uyl)s$_@l7GAl}W?gF=3wt;*&3>TtLvBL$rrVkT+CM4aGUez>K~I##@~o zJUm#kJ@@1kURq%7gT4aEy#F%bo;lmd$uQ?tEl_RSljcvNvj~+745K4IIU7lxIE<|U z90Uheg*Qlo<D1@L88!0v0}d)eBeE0AjY4xJ`8uFE`RN6xzCoBP_6XdUOk`eWc+MCM ze4DA(W;c=iuR!9D+OowQ)6X~7u&JAjh>)P)ZPOQeeOkl1cE(1pze!1ASkc860(fV0 zE`kJ?UsyZzPmq~D^S-n5*Iv|}K(P76cZX3ocGvPjNk>&id}n^@;-OL?s0fPZ*{$tu z(AqJezJf@7k^iEBpfTMHBENM0hJ&dcN7>HdiTi&UZJkg)(Ho}jSVrDzJ1K~1I8(|q zjWA-**X-G;qgt9a^G1h<h2D@ZGbuTQoqO04tHQ&w=bC;&I?bBVYs6z*to+-3k9^yW z8o>G?pYQuTK*;{E37rV}6c5ufW2fRCzy8jU(#;X$Gk~MRq}4-wN6FJL`G<P7-2lx+ zdbYd`Rb{v?#ueEWl!{p<06be=3B?G`4<`><A8I4x*fu;njM3_=y2a#a)Rm&gq&rMX zzk9c0*ru1<GLM?VhCVwqV$(C`tKfR3n&vIT)kheB)9inJ<hW&ygb`JuB%?olWuo<y z-}{4)zb)Ghg%{12JnSds+Rm2?bwAL2@t>f5bIeck^9-U3C9h7dEe)<u4z#!singp@ zvF7w@VYaUCNGSTSpxyz-8#TTp9UqDk^UQmvU9+F)>l&b`8@nhT=p$eLdLz-F;T*X9 zs(d?j0Sr%S(_R6UB?b0I!%3K@Sow*j=1>x7=uPJ@s|S=97a|w};Pibrz~4*!;l&+U z2K1%_F|E2+Opt}*#G)?g(Q?;B@}HW#JZOIw+6crK6jcYQG-ZQp_w3*Mh@=!oYJ>0o zJ(754LIGhR`)DT^j6Ha5FmfLKy19yFp%>2qLz}#d_+9B7W&Zb|pFjHR&t>WZl)v;N z77YY9^Ke@uw9rP|nKc!UuI_&cN~V*_r3hJ49|+4divB=PFJc|xyUg<=2bGkhqcG1& zA0WGLNs+TBonzUmcb1sZVJg4!&a9(<pzis!)}BF`pXJoi)*ZhvE%Q$$OhK3!sJ(tr z=6mm9B1@Rg>==cM$w664aC=sni?x-{v2)Pq3!`Q*N$6j=<G!o-p%C@+FWUv1#3aru zQ5-av;kk3?Uq+pW)~~T$w2o*xXdgwlIrQt=w}LVXKX&cy0p};!>GRRhW{lE<gyhe^ zb}qU_yY0xhIKDB0y^yCcHuTcVHDA=or}>$y+kX||1gKX7dFd;o-V(%xeX8Y0eVGf- zr!aZZk?BkCzMPoN5a@8}q+aoPl@qgwL#=nm0RJdAI~uwUl&If;sOQd`mRVh9^fisW zQs@OXlc5+*FiZl<4XUvh9DN0kuTbz#=~hprU#ZbfY7ugEyHjaQ^c3O#+QIW5eQus- zhw~PFX8SjUadbF(2G$NCEp2^a0^HxuJh^rw?@Ti<f@q?Xs6YBVt!6}Q!kT+Epp!R| z8J<;girpfcL?t<dyx(D`&+VPzpAv0(Ke(!@ORNKQW^<!x{_<p+$5cd20!>le)&rKq z87y>CBb4QYKkIYy-F72$#Vx3iiPX3a8p{1>l>=zAk7CQ2iVg;aVveFe385LJ6|$zO zY41L-+D~2{oS&R?08sAXg5z~2;_>fi`N;IVA4YTh;-&+ZfFl%-sv9IdGyzEE=)UqM zp2Z|iopG}uVE$u&Z*lBH|L)&^>0jLihV^H>MQC{eevH;W+sF4NgxN6mjEYVmM+zS3 z-a}dNto}Dku;WB^g6cs0>@1``5KDs=sE&$4dcVi-@6|8`<B8`;y8A`oA6X<eaUy9= zdzh>~DFO=(18-6_pnN&B()ie;QFkmDC8T)m%0F@|P=16JKttJ?JJ)CRuN}Q%A8AdO z97BLJlzlyNgW#aI>IFx?{Ppq8c2@a7XBZ~!#?qDoXnsFdX>eqW<At+5jOqcD>c6Y4 z>l4e!%MB%NtWv}iL3tt}d~lpCmr2#1c^b4TRpr*!-~ioP!WBmWS9p?}nsU*r9sP|E zsw(Jy_H~}7s?hd?fy(3HQSxXC`A9|C2AW4?b2sz%A?zQR7-5-#Y93#>tjv09n_Z>r zHRDvPv)4V#i4?5zelvy#m4(H^u4IY^XZE^M!E+`jxwd%chS5CLPy6k?oO<xpN6#Eb zYQNm97<RDe`Og)BRsO84l`eNM6<9B<jYS>encqX*U*5lW@@JNf2;G#?oNZ$B!fy0< zGVi;FkXe}N69EQ5hsvXjuvNf8qUOxXQ7?I7c2u5^I+Lzj+P5<KW=9LS$CZ_CXIZe@ z0d9uvZHCgJ9AgtVN3kJloPI6a2aGgvNv>R?y-w_T0FsG7q-CfR6c>$HV>}gsR2gZ# zbL^*dJ+B@($03J4z2Jy4Hg03O^<N}c12ab3c^^$j;^*y9<LO`B+ZeMPchpd$3|Poc zs#Cgdl<55v+b&uFwuCveP9T?AGRxK^By+TQd~`D8TN5C<_%-wQTCVlUsNu+~CF^D} zV~etMm>8*)jH#C}-;rc$s1mFYu(Ne4MNk-fHelo4HPs-LIQYhnGDs^N+-{AGIKRIO z)NQ>Y#9|9%UIR#M2FEPRl=Rw7L619LNTp<4a0Out96Lltk4Kuh1VLBP-@n&RBqVyz z<t$or`yx$m^uiGrI5$vlm?wQ7;zuvA$)i2}*#@=glwyIQksGdGEwE06V_g!deoIs% zK8M+{(M|n)WZ^N-X-z<f3A$4aKFXt{EHRG9;>pKSwP442JAXHz`}vG-yYv5sPX66* z{e0(tooHp>vtrgT?~O^y%-f8)TG>hG*6aac!>PxGJCW=zUipy1h}W0}t7j$6LVTo^ z&u^Y@Qk1I_S;IO;AV+p3$dc7SpGfBlYBwdhh^;YVYyX+P68|7Kc`@pTsLe>WM*2ZS zfmnZ&3KITbxyj)i0{AXiAW}UNw^0&%aho1)w3mBtlZqF?&q6?W7WPvtw!hVeey3s} z{1ByVRs<#7?|zm$-ZwZ!5Qjy>!1(5CK;_QMkXq(D^Izrg(IV?X-=+=f%p%eW97}o| zs@fN2X4n3DI5VjJ#Y!bM7X;Pao^lO68^Qk5`{BEL=@wEv>CJrW<zlP^fPYb8$E_)Z zY=MwRfDf@<N@6Ek%o<NwQ`tBS6lL*(PCt<01*qYnzL57w^VtVxK<pN-5zza5J&Ow8 zx`9Yt*_X-51l!H&cx=@tFOAgl8Z4mrH_+Vsn3f^imF(f)iv`hXoi1ReX7<?-)fv2n z9i5r)kTlTpDjyn&n&uRU```p3QUapPDP_(A!O%HaI!$$}Wqp>|4l!nq!OOyNm)Hy6 zRvRh|J9v8kl7l|k8(>EX*(7F&l&i4sC-H6|rL=Um<-S^|R+ndc8KUkc42x;g@p{&) zkB%RVC0a0j!DL}f)U)%Yo$y0?Smoc``2a;l$+~lSzH|Q~cz%@aD!VEu3lt;g^FXa5 z={U1S%XRm27`RAHCz%mS6VKIsY{_;1$#w-#3Z*5Rv-+hGt@|Q+(__W0Upv3M<M6ZS z>@j8y-3KJy5C-*I>-*5K_?DrYyoCdYM(ts3JHYbviIZuA0@*-N>FE6PPu%T{<&UDN z===hCXets^;oR^0P^()I6u$rD#XRr(tZK~^wH?vn3;RnnXG{aQYuIwmsWW!7`jvA0 zLra$t-W`4LEn|d`@ehyU@bWbwNZw7&POvaky2Zy}Qyl^)d_~#eDH=hA*S_cZyC`oj zWM@o75r#MHR@BylwM>j1*HhSvEN*y5P2RpQ;rPaOr#swiF|eD{k#=@h5R+{+nSsC! z)lMMU&%4x6abdtUI?NBx>d7z$mJslL0iPK=m8AcXCw07+|I|?+>5pIklTBl&5^5}R z@YAafL=df2%#}$3%LU&6CZxRkVxYU9a?g~Vv_A=Sdw|RXJ*_3zxRF<5c8b^g1ZOe0 zKlw(jy;D?K%%o&Qs40}KF#6s0qaGKKkHhVPte<+bNjPp0!=rdqUzO!(8+QTFF>{6I zLUo_8$-v01r&0#kHhH@>2wA;1`M}a}%3afh>|r$>;w~10cENw772Zi&pN7&%yRGyV zlknRf7l|etVmo$C$rn>G9YhVDt6T6FZCD%yOiTlHm!ZvH+;`>#{JY%LARiHxaA<W3 z;EssO?BdwOz;gCQo*Uq)+z5v2%E;M^tPhP*W15`hy1=2@Gq8oIObkT|LUe6a@`}v_ zAa`x^8y;lW;Am^mR19Lx^x-?6p0M>c1CVpeXg<zbpq>b`7?mqnn~`2-w1$^F5u7ap zw>MZ*b_kfL}zON;s&JQ)3RK{j-3)ZL*lHqh{nsa8nNtjO-fNaV>|=&#&;g+`1ws z??r(8fn1)Ctvk(GJfas$bM4X!BNEnj-E0#qS#ne9Lhd9&@)I*KY=ESD<>5o*8yT7= zCq6rmoe5&SpF=9&=vcGx?tO?fl?P|m8P;m@=t;*2+Rv!ee<sA3jb$eOg6*+&Pzfs* z4E8vg8BZ>To>laWhlwXv{eYu8D0<<3qbaLo40(CNr`~(soK6gYloscpWlCn`ac1^3 zId{APV|xT*4xAf1|4Vc2x9{Bh3Uw#>j2eK`z7&5ndW(2i!#3Nf?3q6^eC%cjD}^Ks z+VTFeUD+StB*7k4;)`H0@~+7nIkZAK+EujdQs2$)#JW{r*{ss7R4k+uC|o-t;;WC) zIs2HtE}_egJ00AA64rU#ETszrz&fJ^(0Z!8<P=!F>xkW9!c5I!8jOUt-Pz{aB_T~8 z*smEN1C2lW<OEgAeX<H^9nF)>p@Ij={o^n7XERr%rqN+?6b~0Yol(y!EJA9}<)nBZ zH}Q{{kPNr^Fh6SOHTQn0*~9AyEL$C)lX@8#0yuK}w8N$v%&^RO6Z-ua%M12|Nfti6 zt<*mQJ`7LZ!e!Enl{9CctVf`qJO5+f1O)#0fBxM+<R49XSF>GYFYp*iL?g6z@7m<3 zf?M`A!AMa&@tD^^Kol8}7$WRfA?CytLDAYbOiYY+qGBCg9vVLq?(HdtB@a&>5Ol@( zyGDYj#Nnf0aQjEU_SyX#M3l<5kVV{8!iocF-hZ#f!bxaTXLiqv_dQ9(i8>8E=NU?R zzjw<LVHpJzxco=!%QktNk;GV*uYHYA&L6Knux*RiJ|bYN%^<lPYSNOKg0`g@wohR~ zo9TsRCbss}^UHKG9iP2Cy83p2Zi9vnkdbSj>1n(h_+%p+D8oc<2Xn(l<+{a;p{X|b zkfTZRJ*>Mm7;bODh_e|;FE(2_@ik$x(W#vXhNw=>tU<$#gwgMy!aMak5$$_rfYB5C zsUmw#twgwSh0*Zjkm_ZgNtyn{Wk(o9K#EJsyP$B4woIYV`Ve^+vuH&W4%za=w%!;6 zA>Vg){_1NKuK8|vQGLA@4ezkD;kRp)(drj)zV<oZ$DY;MY!lfe<8QIl4eXmd{M3Wi z9sa>iO4)g!+>tqG`<SSFi>#Wkx^Cv%5z7H&K@#0tM)#Wuva4Z$q8HBF+D~HS(ZjU= zkM+8NY%r>QjU9vxKla-q>0;=d*~0l28V#}o?L@gcQ(dMA){GL>vmj`)qN_MMY#1jq zdHdUp-Yg!yjcL#)8`RA;IPRcC^_)sgk}d)zef_}i5cVd|iKp8K^Tbs^_MLc=?>yCd z`%Xpq^<7iK_kGMG=CqF8t;C+Yk=v2r?>Ijl!U&q40<x(Jpy%Qf(M#Zkk-MuH92tIs z`I1&B!Y$GIGv%>{dxdzHD8ff4Q<hb>gKG({SNP=UJfGhNwPiOd{+Gz7G<!5!<``xm zBqQ{&cZ&O13DgUX0b09{G$Sd&RdkI~VSIZu`A{&hWizSR?okHWn4&3Frh+ah0h`i9 ztDU<HrO(j&rL`-2ZsyOfnEYn>uXpYhid)~+?F4{(Ewc%`yZ>bG49iJwWWe!VyxNOB z;*LDfGJc;exC~QfxPoNgCBSy~HlB&}4)-U_uIDG~H$(sB2v(@)%(MB}-zDhs&Tstw zYoObb@O+$Cm%ujB*%adF18GCr)F>tez<iUL_a69SdU*D5TGSELAL5EUTwQ2NcQnxz z0*YN=KHuF8xIfl|dSUy6qUrHr27f`)w~~?Rpo|0F!)GFDlw%33G9tRk!9;hl05GLs zos&0G`k6*NA)k_1i`C())(IZCJzUa?uiZB|o@K#E0J`6u)EvC9p}SQKzp-8V3c87* zmq_hz@V;xNC2tI+WwIGbFndX&`t=c~_sXCNvz&<8SUkDRxy4)dI;?&_sT7!X@HKMr zz^-kpQC+U^v9O8M9cLB?;FiUO`}hs<7BQVlW>BwTv;p>L9VLTQqC`lIs-hC(52EJO zv4zxC9a_lKsx>lYHxX`t+-Q61305oF74`ZP%%5cTfZBTr@fH+NzXbFL*VB#7KEGCi zP-CH-Un1pzqB3YvK!LeF>d9WIQAjw1lEedYH2+0KVOHkKsz1$K8rDPR6!%WteOTh} zH(c(A)bbT7)!s>X4)2D~iv3fR*8O!rjL%<Qe0X@C2{Df@_C^n6uvmP~_c)u7N_<8- zO0femEzeFJ%Kv~z123o91pcMVh6VX<72<$#I#l|4Y*a`;v>t()CMNt*Mjn@z0uD25 zo?yu@5k?;!M^t~OaW)@C`SIU<^^h`OvH*UfsRRfoZ3e^hOz7caEsWW844Yno$e$^; z-%OlTh;CnEu$quuN%BAnZ-Sxxuw6G?JjtXQ!ywf~#QTZNj0iOKu#5OKE-5CvooptV zc|-X4!AxNk)22HMssUl{QFQyV37r2Kie(c8w2N~0fjKo8aga}?K}!pSi0;gTs3(dV z3rS-_n;l7$C&6*tqKJVof{1hqFhq=x@yP}F_t=eV$uRz@LQqUxV<tT6c0d{EV~#St zI^3MU1KdgU6C0T#Qb4MCD;MFtHO0l1!`#K1f5Vwh9&?_}QC0~>gl{uqgc3u}{;F~Z zxANV6xR2&q7l5uA8;U^Ehp+c<Z3q(bogY746B+D<Dq&@lgX<%&utN+o4Ua*r(Rl*# zK-qAS&*WqOoj&LP@*n>G9ZkRJU9I7u?bte4HxhP6%&f{XL%P*Fa?A$6Uky%Y$6VF% zo(z*&lL`&3<K&<tvltGq79a(V&&!&v0}9)(T;P{bLi#Ju+tez^?^j?q8N*=7bu!;v z!&pkU$TI-loS;s>ElB@n<DR~^QM8+Z1l4_-JM^XoG%3i>76JE>hMF!Sgd1ZijuML; z?gF3$bYD!$1qyy@06pY|&oM<{)*N6XeKb*N5NhliuKM9YsO?}V`Rw7rr`nFeBDe^u zfQ}JR)RY?mqUVo-V*}|2Li2^uHeel)W9ArKcGs2$@PeWZZ6(3C2PEj46bVf7I{?X4 zAJ%zvl^67trggIkIl`|K3|!Z-H#HdE3!>LfQ@QR8Te_<Q`D|*}1(bQK5oq#JL~V(K z*;DG_(V#9X15V5{mKu|l2md0Z;oN=+8NInmFDywQvC731(uw0}D30`(&dz3J8EYHm z8zlG<H5Hap2G?8N`<D=zr|0j8B0}a6d4Wx?ih7$IJP)GIWLy`vAn+36EL`%l%o30T zANuqQ<Vf28_8{tlY5_UKi|$y6kPV+lwT=%6Pd3v|Hl|dM2;i9-cChs}JH7wXMC<Zp zyH`&;8wSxk#Mc!-8kVX>h|LjCrc<cX=HGw&HzO4+Fly!rH^>5`(j*F$R$EhIGJu=n zG*^Wh?s?13rq0`T2gw7`>7%B5v%uguYR%vOZ0gJRBgZ3$Uqt(e#&L|K2Y}KMtUsf+ zq@h@yo&iyV-O}ceeFJxes$z=;i1kA!Zf5|tiKtf(X-Fw4@p;s(VfBO4UwGKL$%6VE z`gWTcT$gB^njb>dCf3)8CSKXfu*p)>L|<}7kMXLv@W*ml-NCP{4;PJABFMjVehW~Z z{GLWCmnt{aqi!+_DgNT-io&7n6ol|<Irf3<JR8NEg7I#2m=?SGMnz{p@#bW8)cL6j z6Sn`X4YLtS?#D5KZ}6HPi0%BSVlPemlEQda5V^%0jofZIgc^QkGq-4F7qq75?)<&K zgOT}v{O$kn4*<+kxuHUP6hlCs*~fN~1q3L=onJsum=y`{0z>7((Z7SsO1?cH&)F|Z zL-8=tP1MoHy}Ad*zT5<Dy<25k{kt!cm@=QOk&$8I;$z|=c#cCQjWn1kaEsm%GWcmV z`zNX%(ME;3nJdOq_OP7!F}lf(2u?+@i1Z|v-n}ATtG0m3E)2@*Y??q(#`D$9eKeoq zqPUkR=+=>b#&Bk~tx(&WZ9BkLA>z=+)E_bm$VvF(JvxTs^RAXgA;`D#`8avttKUSx z;Ky6EA`8cw)*&Q_%2yj&nR{y2h``^o1I1!sve<L?y2lz3v10Vj1BAUgqg4n6PPFU- zg3|(@RFA}85;S33330Wg2b=z(vE{9HPmmw{NK|T{v`(ZP^nA};gePqI(?RYU*<2CB z2lXBT?icsYjd2EDQ4V!%;gmj6>jgiJ4EF`K!Qf*GF1*jkLg4Qp`nDWA>|0u0T6Z3& ztkb3LY!ff{<8uOK=`fSs9j5Xg9;4gdG&n*;$EN;})AvK9NnL}D5NWiHC=vL7BHL@L z_o;rsUkw3rL=BXTZCMh_DLPQc58_Zhx_hX`MslcP%t61KzU+yFQZjsTd*UmC_8Mce zc!)ELG>*<*hS-~L(Tt=Dj3?|iYx1M*Fh-`mAG?X^4?2vIF-8s0xQqbvEF(0P-VAy? zFfMYEBaD~X8HwHlKI+#Nq`FWjz8t;@y+)7G9vr3`^u!sG<qY}Kx2#<TA;mzo@TA&Z zffF)<WIg2l87?D^p1;AHt8x#ML6I?9N<gQniPqb%y8-wOd0$(A$aIc|-Cw5@r_sf` zhqlwOT0SL>n+eWDgbBAD!#m^%XfdoFX-)2GsoB8F0dSuZt{i~2lNPetS&R-HZZBbv zx`HWbrU$VG7Ji(dd9UdxO!|mIjq924_ZxY>+WU!Z*WWw%#ZJwT@~25%k}G6Fi=9Qb zj3RYMye3;n_{7SDEWYmmu?sYkC{`q57RZL9i}Tq;d};SvJ#YQpe{h91&zb-DlZXtF zJ&gA;oEO+kNaVM`<sG1r3UnsAJgQ8+hb8MZp{bCX^f2~jDJq<qLn5zmtzhv7J^76u zSIz`pH0N;WzM)yOb`7g|ejlcBPXT-BI2t$q`D(FnXnHpF_|(9k`PswlG03xog7<hY zBg>VfL2`OEd2ggw#(r-0(XTB7z$D0V?zaWx`CO{!v#uaK`_Q|e?%(v;*6eVudLI-G zq<3z+LU(a;l8i~HAZHJc4aGj){>GsT1H1N34(!@ONG^!hI{wtF0LH{}GkUiRY9M-) zz>Sd?6zU7y*n)0aF@k})x02#bTPTQB2BYX!0&<V$hK&wvfq~!BOnv0^emGi!dKoSS z?o$co?>LbOD?PAX3Hswjf^<b$>!Eu!0@<R;Eppo`LHdsH-fp*=b50N<X+~x(K7}t? z24T-Im80`iJ$2hGhycqk#Rqh{mU{HgrRyxT{19ZqronM;SE^X7yfFFHmL)QUh}CLA zJn`k(l6v6#@gbX4Nw-@i;q+1$u#dUP<p%L(48?4rE?f(8uMH23xx*~~HhPWy=OPey zfl#%JgDoNFJi&04jhFHJy3M@ZRu=FNX3j2-;<Y9`h(40<9PlDAUlEGkBYepJ&8T4C z4v<Cf$iOc*p{f|*xl=pIrmvw*Cv0-kHly}s5#9YX98vY+_&Dlu)94TEg$!RZS4if> zH&M|*s4pV`pxQfDcMAC{FxPWH1{%aw-)pC}gV8y_QG1qW{7wQB^c|rOX}P9NW+ytT z;TfdvwJ|zcEe7_i9L+GBV=T&-&~gh{(vCke@=+SAkhQ1hnN?Y4BoV`RgY45+DK2nY zpxB*_9PwC<LZbYZVX`2Jwg}E)nCS^pCwZTJN6iQqskt4Ho2DG52rB!oA6D|%N;m|B z=8qPol>gMWNl$FIG`tU8+L$5bfQ(1OxqD%~pW^LFeBtlWrdvlE4I`a438EJiZ<(GC z9mc*;xyXwppBPO9(w%<zX8%^eiOU0v<BEj*%l2N{%(J=MquG?9VP|N0Sqgyt|5Y>m zl)}6ZF=h}+9RxSAcyK#-Khc6FrdlvN?C*WezMdcd!@mkPPu|QwEY*oUJzD+Ca?FNp zM~OxSVeQ{z+#+db!7~f-$C4je6<?J^GDA_hVzw_wD;@MX`s4t66NT?WO}m}AmjqDQ z9Gn6Wl>TZXK|}qe;|-OLDjmMQcxLw~@Ou~cXfRkrx0qD;<Sib5(<q&ol_24=jg)PW z&?SJvbn_KYtw_^v$4@^FZ`LAVa{M4%9C)a9p6#%Y@%7la(HNe<VFn9Z_%lKdV2%oS zGtsJ`vs<E)7FitZH)%=*GfSoZdxD=5kWkl-6oQT{<`*Asa&-`23TvY*k3XB(M=8&? zU&441A_n?G3YSV7zVHfXRjz3DhpDWq-!f@zJyYCr=eJ?wQtzLe6-G0CtIzMNaxCMb zY9}^|3h6}N?<^Y)k{-LW(X$Z?`^gZ>fHo;af_sRzYh$;zEMUAF$hhxg16lX75kc;r zZDsL6nd_iqtW=emxQph@WhH4ja>Kx9_D;&S@0k+&M-j{OS;PX(?QX#!B}lmI!C!K6 zO^;twB!&US<wyz4MA?=Wm{pP?g~ABlXOHcW9y2~&7P#}Z@)(mwp?m$F7lQ6jD3*w) z66Flv0(jZimAHtSZ-U)BmynW$SIPlsaaHQ=z!byf3_jUKC{Pxi%pbv)qk5A|zd6Ju zs1FM0MQj0Dqb4D%-phy}5;@+df_KDl&=>RcRrUg8s4!AB8+S|=2fnfN1NN*FojDbT z{L*Edx_(n9JK+M*;OPAeSCpU;eV7QTSh93=yfWRwkrQ6PBSh)LW6^11_{nqgn9S>E zY5;P3RA<_Sj#4a~<ie5yyoIO}tT1Q6MfO~J0n&}Jse~Re#UusVt*Z!C66J2^av85H zo!no9uR66#b}vg+V$M93tPp@yegXl<ima<vP(-~R{>}+-R-PSl4qf(KF6CW+{AZbF za^wg^9EApU?Lj=%;oUHDDp~a{<+1ISgt7A}z=IiaWiU{hj{F4S->lmi4jny6EH1z| ztDR@(y|8BB+<kQF=Tnag#7|Q*YMZ3hi`kGw_-1U&o!5VW5_0+H&mc@FcSNcXY8yE1 zG&>!k8Qg`w4TipwuKL-{V{`Er1D~D{SwtT0R;(LmCT;|BAsBrm?Uu9sTg*B|E3p34 zTN+8C_0m8S_&_{{Nq>q`5MT_24vO#YXGhX=A890b{<uWk)72<s)nKdw&c?t9A5TB^ zS0tbLC>%1!vaY%=Eek*7Eym82SwC>^+}OGX;^QSOcpu1n&nJSsqNq@&gzbM}btORr zuWyOdSUZc3HgX3L@+#tV=>tl<4J0qpN8Zzp0q!}yKroz^n3@=Fn#1+KV#y@(H@Mrt zeIxC9C1i#5W}cGA*=o;rmY-YWF$dtxRShgI5j$GbA{}*rpg4)`(f5zAkLu~CgUbd2 zx%fglFex2dHddK}RQ~!VBGi=5;pKt;Dl;X{Jn_)y$GERcfD$;OhD^Rk4H1z)$0oDu z>Fx;9iY&<4bnt`GZUc+2iztJ70;nteJmF9C_R()<#{Gnwc`DS0xl{%nQUHE@4;7_2 zHZbg<^0|UNUp;SZdKA1OG~!(J-#Huf>Iua=zA}1D)I2tnBNkpl5g|mkB1E$NMKR!r z9;n%fEz4KOwzW-tAZlmCF1K(X3*Yv#Aavxkjc(I}(?yIUKXULdTy+Z#bAaP~_ZN8t z!~|&e%?z9Z;F%qJdH(rhTXipoBNWU4-|7KZvk!$1B?<3^CINEj!t3YTY3$kB1Vr4q zAq|S~R@H2%cOzF{=bf!|kh)2+`~Vd?WS`VWBZ`26MmVrF?Z#(c>r|B;-v#s<&6qkv z6#?o9PgAH=&U=~(C^wnIGEz#@k&aYf;C{fH(dfcy3Y(IFI0&`PSM{Hplp@rSiN-`3 zZ{&}g!fyLS+aZm@XNDFU+V&>BEZ`0JiF%Mo!v+bF(2ERnP5z9Xfk+jhs%)CNDcpbm z<eWlsCBAhm3*$-nRZU>b)leRrvy&02n1`U<d1F1S!cIl=Hcc*Hb*+H_10@f&=CyjB zCgRs9BAEp6{Qon>#ualP|Hf@lX#r4T+qA=%QTXLw31POKWy8L9;8`Xba)t~$(r;-Y zywU+?n=FW;N)%|3Q!3tL;IoD}kVlFit4+6Fl1>MbVY`(X2h}T}SK_q~u`&9`&A-}j zVBb&I43IoMSBb(xURk)Ge~<pc)$il?26;Zic1JwxLK8ov)Vw#)C)e*yO7XLid{<oC z_x!cz<|O1$cFRPCPLj|@p;J_b{zj-^0bZ$xUfZPEJqX@trK&@Pdw!wZb76LKUkL`1 zlipA~i9#_rwhl%~VpP66a0Z)<lPQ<wrU7q$&@&^c0}9iP@}X5IC)FMNHanl1B;V*g zS~E6*{oOA}R>kT)%W26;Uc1;Wuk7oPr1m@+bR>;p^t}g1@OaQd)n6#6Lady2p`f1K z<ou-at)3~UT%sy{7jJ{2#`|`_ZNtTnMZ-WfS?hfgA=d8yfsB1(>H5sUW=jyiN$7-P zfWDIdcB6mr?~ZyALEIZK&1H$s8<;h~r40S6lk>mB*44r+a2THb=(HGx;A|V_*g01G zv%|@KTw5FKoNT|t+!XX*NO19JTXKA{<&bd?1tr11h%C*{Z{PYPdc@hMww@hMzObh| zbk<<3_QAWU(0Iw?N26;~E+o=D*@h=zVyu*MTIuD*$+;&+KC(6qt!7uEbEhtX)R)_r z1n24R_p>C5*}#AGx{sqV$bc7%>IN3;6(O;D88I#w)eBw%iAl)8nC-ok*MDX`&0!`( z5JpCSYP%hp#3n*74{YUaGr`<iwl&f4Bg4sc1jYOeqf}@fYU>U2FgGwMgza@MBA1{; zud{4^Jx4)BaW*7&-=3QSv6{dr)Ua4(Yg-%3g1mdw)^n-4q!&h8jv*|*^3Y2}4bAvD zVkC6>zBKq)UsOZ*iJu3dJg;13L#UPW_lfjAH-H;So}?#;G~E7XelI07qj=O9^GV_$ z{NX9s5OG1j(S}Um;{$KG*=s}~&s)ARpN`LAKAp2hm;c5EmFhqLAOA8~+C2_jzi4Vs zEx9L7?6p&JJ=-VLmRKFJV>VjFCyFrFHwqVHn`WApaXIN~UvyBvb|BRlJh#RU-o>f= zm1e|jDReq3)gRW)!VLx>2+sYX$CCJUK+lA!=}&*^4c-lGx7k1xNxG3$VriZ`9{83= zOX|t!t&1y8Bk8m5rVodq<y@;C<F&`Oo@Sy+PXd{5MCmtE0k#s~Yx_Pn2bV$FJ#_6+ zbr%QS8^|Pve3+%Xn((GqmWx#82iIKlD{usP*a{+x{aYSpf6zy5PkE)1Z*oM0)`XA^ zHYDUwl83bY7y0={kiLT{e=_W#_u`E9-wC#n5TvKXEBopZ9w7KN*cP22>P17~@9>&# zf!FOcQNcclQ%2zIflaC$r!^Psa_AR$BVcR5nzx9vsy$dU1o;4PS@~O-<qc+;v5X*; z+{q+`15V8@*-?4Iic1zT__vCrPbJ~{*sScYO*}bsswVDUhxp}L(0gWLfSQoT{S~#9 z#1*6B@GNl?F(GBx5_Uhs<`Wp8LuX>EXV|pTYqf#D(nLd&A+rcGo4eiV>LE_fUt<%v z+jtXNh|jPC0bP<t@qTmXN#k(A*xw&Jk9b@m4=Ac8-wxMlh{VIho+F7cSzHVu$A=ep z3Pyh2n--q09-99Fd)DbO&YkNfC~(%q#u1bn=3qr{DWN;fm0aP|3mIIs^Q@#-&oU@h zqf5ql=8o|aExnW?ff$zT%?1)R-|hOJW_XC_`Ned`6KE5&+^CL|@dU9HjUk);OE#N7 zXGfUOfZf0(%JtCh=jOYAl=X$NI*=|AhR6|&v}I`Fku=Jb9MO1eJKPxKToe_S2oPs> zVH#GwZU=lfZ1`MaiO$~H2oj_(B-$K5Q(Ajp3%S<W1h|^L<|8CQPLaKcoYHj4R}9Wx z(-Z>*V#N5~C@Q&sCfCZ}clVH3IL>ep1eH2^`Eubc5~xp;ZQiEmmTzPcq1OIW873=v zU)NF0gkv3o_xxFtCoHw5sSEs5*~EhsV&e%|FL>ZBGZ5~NJq)M(<6rudP4`{|wlXpb zzpyWLL<m`G&{Iqvnk3r{3|9yw&5ma7IHYj*gB!kS(0wXx?!n+{jR`?M-fd={cse-R zgs5TBOV@<Mb+M!7lthy#*rbv1F)$z!`2KSCcpj1)y&$&DJJRunfJ1#PN|0lidn0?> z3-h>C+*>8LG5nti`}wXYDO7-)y@<y$^}I&X>OJm?WZjN1{q*b`e4qvs;K{^%Ct5M+ z3|!MSPPk!Cn4AEeZFCHig(IS3qm2k0fpJVTS{nCBZRgU>CqyZ?&M8myNT}_HoY14p zEx@N?-SA(vkKkyAh7j}!>sHnPrU2kw?f@-R2WBfC4UDz);uwE8BF|;E6X5=4p|e;E zI`iy3AoY!%fET~XsJ<SP&X8{26=h(cmq%eI&dJqGiACT+Og`7)#L^{f*g2uv!MjXN zAq;Kynm4JW@=hZ;Q*4%-tsZ#u^6(r(;u|c!Eap>g65TuDSwC}u+v8WRQusJkgzph) zTuv0~1V_p~u<d<pkR^mjCERwvNW**d_ObL<UVeA%>*F|6XQ$?ROuH25xhELYq=pei zyCjUSxE&`l#7P>+lL;v@UV_N<JI*9I>mirU&ciRsYQXf|bPjCpb}j>t-Q+=3HRR3o zEG9V8G?Ndpx#iS3<Or0IhldmQj&u=rebV82#-^9-_u#@Nu^q3<d=mGAfTiy4f*o^5 zV=i*9>*IUJkw$2Ke=s9Epqpcv9WG_=kyu4)D?@4H!5$<@kv#c~KDSM8NQR)=JZ`un z3NuCNIUxQd3x%zm7N*!kxaw#(+AM!`*xvemD=SS`<GXlm#{;wQ{U-YX9@gB|C>}5D zJAg{MsLyFOqg%$}8!1ar{ERx``nhZVbE6Qtm5*PQSk*+B-x9KIw3^51w=Tluz}m*J z4DHPnE5g*R?m}M=k))$XcWuLbYvuVFQhlf;sv0#c@J87>K#iw3da>2Gl;ZAsTu@5h zXXEF8?CQU!gYl(5*|ZC)mNdm47@%TuVW;0^e8>T@&>V!Rjz|&5iJ%#;Gd4XGtFg)I zRga=Ti7GNXTY#IZH#9c0|4=h3j~7qS`#{%s_1hO~-<+T)N#!1JQn9kj+j>(uG<{<V z<k|i#L6n)MJ-kP-FERG2lo8unDx*P(0iyS=)THi4-PXnQ@g?;3IZpl6Yhm*JScjeF z0du+ajqMzXwm=HcfgQx#LPQ5zA!)VGX5?1ba1scG$#C5(jr9iD&}`aJT{<}`O;@h~ zu_sVmwfzQ4qi%j2jGg70MViA@0oqwl7JK@j%U?$i*CnZb19`0>OqH`hjJd0YnMe(J zh0TNl%A?Db{VT*Y;T^d<;5?~E7&>Zw;m=kQo|v55>s<au^U@r|olr_iE&O|-eZ~KZ zoguIl%%iq0rn!aJYe6tk0!O_*Xs0JI-UItuoVat3?6)^S#2(ShquB}~thv;Y$V@tp z{3Zt2Pa4@6%bseuwuTa9(J>{+Ls4|XqsQ1IrhR2{inbWKSP1A{R;j4Tu1v`@qY){X zGzL-#dn`opg<NM;)BQ^e=p+v?UMfQIP*(8rReIW&<g+hM>;M_bbPdm&6sfC_=8%m; zPO;Qp99NolpG-x8IVJHVL!h|mt7zk(>%xMB7b_4p_!R|Sq+r04hhw!)F?efdX}qiO zLax(7DM_dgs1|<D0h>@>b9il=Q!q7|c)j(+!rAiss1x!)qsZpVLG!Rv9$dz+@^PE+ zU!`Je)dk9yF%T#r_lQg_d+&W+q5uTe2wuqzi8X-2+_FMxh01K>RvHHEu~7OTxIO^} zmM{#&lUIRWU+a*)KEoz$*0TgW<ebeTXbjp!7(`ZgRzN7vugUH?xEAQ7X%IBL4PB<? zXA||IN&~?L5+Dv)xq%f(;&C$I(@#IG=a>9Nq>@UNtb>0~oM-~pRtep|2K76omscDd zaarle8(FQe0(h8B;JtzhB8VT=-*^?6{P$!3@vm%<GJxQz!&7@8BkpNa!8-=`l_b3c zJd3YA-J?VhV9sfMh0H(QoD|=%uTX!rp{$_kN-=KJ(xqSo3{@et8#CHZ;E($2(a|9` z$k3ezdhhk1$3{w7R+KJWWurE)LdDbjY@pP;7v?VX@^cQ~Mw9OJ=W`3W9M{0`?DU*+ zMv-u~S6C!sS7u}E!>x<s0eiMbTYdG>Q!eSxoyos-ZMy*CU?Jh)Q+G!W9tB@l&Hzy} zHfhH{6mSt)pAOH4kivWAy7IjNzz4LVN4i7?ViYwlBd?<_usm;4c8wkoIYK+Keh?L< zhv<@ReM-)dW{;Yg82j`Tm0&O5<T2vbA*R%gsuF;Bq2dC*uOMYN{Wd)J+o89&#GwnW zOVvx-r9dU@U17opOMou5+4X^+&%lnkm2l$|i-VwZPh}Rs8^|97<>y{~v~vPpJ^hWn zkF;zr%wxm|1z91)12r}zsSg(+)}}3<P%};ZFj}n!h;ukvj_=8Ic#?j+jk8mS$M;UA z=R1<a!3V}4RzP?MF~X=_d)lyte3sdNUoQYf)X>|z2M5oHU3+(RBtAUsj8;&CCH-s8 z^)uOV6S#FX%rj1&TQ~R`Y?;Gp*=D<*HrTg=sUGva{bm+srY3gS#~rLBTC#Go*+4$v z`i@x&U>agfo~{xg1VJ2v%|c&2L@I3?bYRtFHSqo`-wl91Lj>XI!?T1*&b2BM7!ihp zHzGG!Zy&R{47Z_2az4WRC&#XKgEFC>3bhb_`Yb<Ncg{o*O6OLLH=iq^2k>7aeL2rY z%0<B$)D$4!lEQLSqqe5Irr7nxB9&x2Kx`If)QsfT7Th*DeA56n@<qgngFS$yGWM7* zzXJf6Ng!04zHBTUO0aVY18_I>2z6=H2{MEJj2L-$@$o0YR(|e!!p-LuH@0SDhv{e< zN9}iaP-~+`WZpMyn!z5PbG(Bzk`RY)m{dt4Yd`%h_X1L}a1P<RAkDWFjMlIH?W=I# ze|GHS-#Fet<y}zAN&c)sG`P#_2pCh}aed!|QUYxoG>$%T{_?Lh!8%TuWC<A{9S6aI z*Qwq&wN;K%FAzJkZ#@h*(APjH2jS-esDer35b`&;J^-qiuT&Q|uOZ^{_}G%1Kv2Jl z?(y3ArsXTrUw~YEPajOwjcr?&)}kM;Px;s&oy7Yi!q)`!Wa)7HKE_+NupAwxeL{@p zF<R0(^A6(O+}I{xfzGb6%qCB)3OiWjQtwSUSAm(8=EPn9rk`<>&iT@E&td~h?|P*L zkg+(IBZBh-ydZ9wz#wndk`NXa7Ey)|1HjbZ;*`B8$5L17h$XnMA<!oxkI;qP8XVPw z`!heQ2+m(YVb~qdHjl;cGf-GDYaaRv1Dpgq20ZQBB9}*pu#j+I1@(w5pH_2l5>uMI zjdSzKjPc2+agf}OwW&0c_Z0!hg@e5;5LtB`RgdTnRvuMqiW5)r(9@IjBBCTicb&hw zHijrOUvEi;gHP`aRc?<94YZffJA4*VX-|{kP%&wN@=E3i9%?!4nIL86N;gSYr=6j< zYwLv;xi^~N(wt2Y<4*L48jT8W%BI&2O@M$0M`ns)Bg*!;u7f$wqkW)Hlw1KDZRR@} zZu7WLnx7*AqS9>hwHzB$Q9rN<_j+dwg2WB(UO9}2QR+s{an^=i-Q%j=H}6ZJm?D7| zp>=4*h#3Ztj9GZd%`!p1ssgZEF)p3kU2tQ10q6y^H=M*}u<Q)CHR>?*k4DIb$<j1J z!O>_F{`>j6PH}KR>^Zav=xh<tX5WSEsjyA!GORE^8@dn0`!$XQuig%TyY5fQyJmF= z*uE3$0ogbn0?FWr_jIPz^0`dm(5EU7PndR#&BmK6?05Ug&ETeTGKGhKs=XEw33F8n zb!F_K@*E+)i;1F)tq<g@DN@4fMq@A=S4zC^>j@r5GT*5YH-;z+1<?}VBj)k8@^9BL z3b1db;JnfP)3mnz;46UffAjHgED6T^Nv1g^%7kFt8*U1|mQc{(E4<m*8Ly`AyB~_) zc#cH1e}OoA#~T<<)GjA;2sFI6Re?E>oVA@!^l;-?eP08)1>g;xE2_iyeCjRG^}hzy zXD_KRqYjtyu;<M%=Uw=NkIi{j7b?v8=A*IvyeG2BMu{2Om?P2^2<UFB6v&tXIi9G& z<sssK+jHe8)<fKp)28qF#6v(ZAQ}vuTggU<K_S73-#iq!b|p|eut8+$&;@bi)^5*M z>v>Uv2Ov)94s7gUDbUg1@Z|)`!=Yz)vP3VQ*@zdQ{m%vT3z|zZsFisWs#5{6M|!%q zkJ$ipSv8nn`o>^H3JEXs_c}XvtBNd$&4x7Y9<V$u$bz3iF_hXLp=v}tj=BNvrXnF| zAS3{<r{TX2V_IJQv!6!RCh`qX0+)VHz%Jb`y%@>ztWj`qRM>AI9q7Jwd73^Qwlc^k z$lxTwyvvAiNi?~UfqX=&%ykTBmLNgh+YIWCj<F1>6+<MFn3gKuy!Q<(nPa#)?Q<;G zv%4d-nC%KOEQug=jIr})i_-3nPiL@={blA)h58<B?P$G2gCF}H#DR;jV3tEFTd|GB zIrkuT5YtJ_!5|4!jNZn<ZnvG4ry&Q~y?<$K6b0fn*4_#YC@0^g^@XGyf`&n4=p&K7 z$~Q-oSiOjf9NB@iL51pooa8wgfnub6^|dw}R^2r~TDpax!mB9+e44Gu5a+T&SLChz zB0*<D>_`nVO}O8#tzTf$pj7wl*pqNM6_B^ndV&nC&_FQ>9P^;^-ZHe>m*)?<0VFRR z%fg>Ic_=5<=i;lf)b*epmp7~M^eJ{KI}w?q^of9N8GBo>+BDEy3X~$iSdVGhx4T79 zWOh%OR#r&w^IPuURe7<1<V=3jE_R)9emnzhG<;0Ke$<Uc9+`SpLdpmDesnV?AeZEi zyrOsCqN#H6!$p+w@Q(9I@T;|SY!F8VZSdK8Wr`6T5j<jss#KT)E+a7|0!*6zu{F@+ zkC*;r(}zzi8lGs<$QoH_5*y=i!ZeHZo@J+;A$8>}501JZcSd`S%#hRHpSBQH37o;x zXJVtd;>YUq+70r?ri)0OSsRVa{DFUcq2IIeJlpy$d2}{j1as|1*&m^#*)&qzlyIX@ zkpEDrD9CLj5^(!w5cq4)l9-5O%rghK_v-o81BY6V+j(9LTA<%<R=Fo>H^VoIRo{q& zp848m?vtCYHUKE$WjWqV<H!~Rt=Y?OYxW6JL6v+7I_>LZQeFiw?wlKYlO-7x4MdKW zrXUf#%=+CtN31X`!Pa#^4Y(KC30HiZS3sw%)q{=zja1qGj?m-TLb(zkuI#DBx{2PB zc}x5DYu5j|VvS%t5FH$rIzSE>iFpT1SDj^w54%xcxq*xy=FT9ap3u<1owSn@AQ<Lt zP?f$nJImsr`f++Xy8SqMic;nsb5Sh@n;Y;+)*?d;=KX=z3hq#gd_AC2F>6|6Hq!Xj ziHG>eR43LYag_>|FMQIJuV6V7Mky(s*$hj8Zezq+GU=HZh)wvyB<|3q(<dvF%$B@~ zE$`?KqmhEPiWd;b&e|t;E;YmK!ieMC+4sFT_SPZB&dHh6mhu+-GL*N(iydsw2qLHj zix%(sMoJD~!yQ4S%cYP&^+wv{HMnncO7)BHJ~ws~s4&}Pyp(;BLO=qw5<&58Tb0L7 zZCmySNlU~x<Y@#2RT+4)4@Sx@+5ti|O@bDK6DK1_Pa`kPGtx+e$~y>3HhDFqTErAp zaJo^hOwA8fhX=DS#@OAx5*>hlE$Yt!lBZ}%0nd|9%R=1=OHjjsV0yIN#5TCe#q@4a zq26k5&_yf)+z5=Ey|R}()M`I19NBuHKs?WAB>0(X!v^Vgz9*eb8SxzNZnAjy#8?Xf zhJTqQYR8_V9?6lXCi=b`>xdy9e%t()L(Mme5I+R6n<59JG7a7LI!{`e3d#!u_N)vy zS`jyUyT_Gxgz`OfoY3_$qbbUbkALh>J0xlUm;Ti^`)~^yD-wus!Y*K01M6N2guc^2 z_Xh#S&&!^d0^i`JOZQ3OH*MRH-!b!V)pc?g*ST9-`ZfOjz)b~w5f;iDFxN>-#!fmq zyCJg1t&iSO4^u~~VPx*~3r`D~9KO%q!))e0-Q1yJx{;7s$AraSV1Jk9t7_iM6px-D z3^0>BDjuARe0J~3Gc||$hee7&`2w?&PVg>>g)l!F^GIakpSs>sX|{kDOXR+k+&Fu^ zZf21NSPKA3hj*}iKYUBUZhj_<4u)t{K`aL#;ETyo@Y`ghG!PRIy#B}!K-htg9Gd5H z5jX}*hmI_=j>s7TT|FCx$dX5~6^87>y>wxSeoYnyy+*6wkYf;OC*t~vzsd)QB~1@u zpp58;JsYSCP6nNkm?~e0@Dkr_<|W(q8~HT4LpGR!v(qO+Iu2IMg|1#`=8x>C`?Pql z)o$zC2OYm**`v-x&sOzNteE2=`7F>u?1OX#z&H+NY1l6D=4Mag;4lUry7-0kn=G$B zBn(HR;W}Ktz`o@MVk{w?pwwCjY%U2oCl8G?9qBvRXKAk9>1YgXueMfS6L6mV^pXUZ zFz~~U%wxLJ{E*NjS~to?b~uDYqN|=oOMrNSh;y%?O9OX=a3ebmO*_yC_6UvcW`2fd z*=)x6BW@gQGg8AO^r?2n4W+*@sxbme#W4V7o>bY_klOiV?!2Qpjew}6Rsd8F)&Yab z^4^|*Vryqjv<~!xd`_3+8q?wJppG*ySQC)Z09UteNVo0&?7{Z+v5xT(HjPywIX6bv zIi%LY!s%>71r}8-4x26{J(LuMS{wvr#b#3>&2|MOAx3xhvK>KI6z70(2{3%nJ<+!m zh=dyA))nb*+`&!{&`D#gtJKxx=RN5P@yUeBoljSD&3_^<|NoF?3Yw|A8B}5DPz*+Q zf1SPof#$tA4sw0c;r?;8`QsZtkzwX!;nuqn@B7#=sg{3s^yA-n19;oRldZZ5davaJ zmEt`raIt8i7(6BNh7Q06=wZk|{3CFX<I18F(>^%Jzy1(tAys<3FWPY+5yIK;?Jgfs zTqZOfb8dL4m@Wn2Ha@Uf-hOR^%M_&sMM=W+rWJWow23~fTLgwfbbZzkb@oE6hiGJs zXc2YKw3;;ChfP%Zwkv(!%?+!QFxzn5J5Y2I49pr_yyBHF?&}0k?Z_BJ91fby!QNzn z;mruPp^oYSCcIXFUlI^}PO`;y>3PxoTCL#&#PVRVZvgJgRAdmEXx%kO6Gh-a32{9i zxisQ(Wi(jZ$7t(m0U}(Q!y6Tq-(|>X9z;dL%aa5~olqfZsH(iU+sxYoLV2I)##Rr_ zIeuNe7WB2nG)|X5i_%@Pula@vs|uBZ$^#?rMYp*b5PgTUqYG6r<0uT?o=SBMR^5y{ z1x6JudKkJU){EK!>e7l|a9QC_jBfFwZjEwsz0bHCjy&B}M(0SxX|Z{hB;D0{;N5d~ zUUq)NV6wpBkeBE!xou5`Z2G}z8*toAIKt(-%7h~Z7oO(`K@S<jjRQ0QLA}0kfhNov zKU1Z-E>x7=Zg;xJVfy{fo$CsT9jUW9v;}QFbz<@jpcg1<&o}|-6(KV>I`<shcHu-q z99+8c5313RI*b{qLrqnEmwd)@8n#JZw7M^jn=N1?#V})rAwdLRXpR)-KdT1K91K>| z&%xFW$O*Hi0D)tMZ=m4P!5yJG7*BDqUj)&WC$(uL@&@|L7YhDwU>*N7Z-rdJN&e;9 z%oySLI-PXbLC^C{ooXAT6#S1Q#JYxl^D1z@6jmu-9#pYCjDA8Ud3Jc~4u}kRYI_Wb zRoHyvY8$DVK*uNgQifYATJ~&x5j{&FZsg+|tGTiFJYXX{UhYaGNQt`UFRUqVZEO=v zgLURfpH*2tIC29_4#?e?p>>7s>cSCpCKQF5y?Q4oYRMkwif2wU<|s2ce0;?4O|kfX z><T3Kj~9RU4}TUYNUmbM&~+48ZoSw5ujbrn1cc_Ng}svAkY}ZeZCpsEyb3V-O~0SJ znRvwH8i^;!>?Q$#8sCwPLoN`Wo8&^1bynkmMCWIqqfZf?AXECAE|o&_ac(_zfUdp` zF^Z!;MF2kd+KWhpjK5;@$T?GubwO^lP+##5vy1tKex~9-$zJe44{W=!T~9lDVK}*n z(gtK@w;)Nhx>B!o<$-_T^X{#p&R|-?ECm!aQDW)wK(F~(Z_FP6R)a!TgabI<QWvzw za4NDah+XC^e5SmVaIw8@xlJeg0k|ALwqu@GHU=)7DWvMaZJgX(Y6SHGOk70U;PvqE zU?R5zhnqVDEZ=^3?cd2?f$t97l;)Ey$tYMV6hi!gs3@-UQ$S7Ua2l9f%eZJD)pr#Q z`3x~MAT^#^HM3AFpwiS311hZ(4F)G?jAcnv^+P9Q;NjazCo@}R*R9Lx6qz5;R}_Lb zRS~KXoHOzo8VvJZyBs5s;iA}qHf~2q9&PdK;Ay-!GrLgBeb?P#mm+jH0D$8#Kj8O4 zeL32R$*c|Czr@VX)vqL;HhvIC4)7dXNg7VuZ|&?oi`(h2bG5DN3+@^&hFLNQNX>%O z95@Z|k|Zk`pe7@w-Gt1rT-YfaV{Eg<nE(9{Z+8M*y8O{oc9vAvVMUwK8br%6Q*T^! zhd*!Bit(NjK@@>f67C7`0LghWBX~!_TbA-FEA9dtXgeSKPl)aJTKBM9eYq6tc0-UQ ztnyl;72u9Lgpt%!t7&B2QHJ7QGAqGS{PlM{P>hE%BZP?Ri3(c<0O>1>1U>@A*0ZfO z*+T4wz+SW4Iw+2GZmxLGTRT-G5F^?$Q{NJQvB(rYJ~e-v(3Zyx8a5=@3T2NV6QG|( zd=Mw$^SLl;H22A4Cz=*bqZu97D;r0YLHg=2<-nUP--x!eh~0=GrvZqoi9I+-r8$mV z-Q<ts_r0~kUjy6o+S2|1vGx8jdfiug-*Bj5q!GE5-FID?fl-YXBg`nvl$2k)iw)2n zikQuCB)Y?)w{_WIBT>+1#;wvd8fVcI$dZ&evB%biqF%Ey4I{(ZA#E9LV;8e+ieeLm zl~hz|w!<Nv6h_c?H)uBznx?>RQ)IF6_Vanp_ud)W`9mYlJNL);-uK?;`<&-I=X|>v z#IcS=K$j;U{{5dNk9Xnc{?7l-8wt+-lW<m$ceck?IPlq|;fgL#rxLr@F%}*HQDwKd zF_w3=t5q9**vQkLdlYd%9DP&3ES!e&P%PJa#r^y2I6ZZR;|HaC=fecI>aBNgZ3Qn6 z1y-XBr!#)9E+~`e!1#9lk+wk|=DSTWE{s>+u7bOWAPN^hHMh!)7KK=)L&V)K%iT*S z7gibe1jQhab6t^Csz#+{@Ic`MGrU8g*(a`mLR-UNk)%!d1STg$23H+4p9LUolhQ}{ zl|#w~RdR{y<7ndx0Bh3l0c2_Gs_3KGbTQYNTmKZK`@}y|T2OdE+nfY8!o~S(K5m`n zgVq7V=)nM^h#9knGeFQ2w30HjhAsn{0h)D06ec1OID?ppyS0%y!xc^VH?A?~0MM0b z0vtnX5X_Z@`L^@9ON4jWYZIi*L**!8W&-T^#;fOrCl;i+17QEkpmjh+MIbKXeo^&3 zF?FX6#N||+1t|6q>w}gA6ZbhSt8{VSnH_ckcsMp4n(Po-1pE|;%8;|K<hn!JN#u*W zGXK5fzs%%=Ou;wT&RYzbU-$yq^k^J#^3iiCb6)*Uir%*G3emrZYT$AwRQ1JvJU>O0 zo(gMl?o8`A_dx^;IxnAk?j)XJ9T1zZQ6wi&^AoHGYga>awbfaa{ZjnM^G7tl9WvDh zeb#^R5+QIzjo-&KCupHYNLTx;9jH{T<Um)~I*AIwe2s8SLwoe&QEVI?sL_XdR$N5Z zv{)NR-ySn_B_wtfHkaEZkUuFuMWMJ6O`+iy6VwICu~ENb1vxB$_oN9n!i0z>{^`g; zlXskucF98^Q1u1*c15lVJQZ!lY(Ry}x$pV0BaO<M)laCc;4ApVyTfcPy#=0`hSq5` zga_l-nFSs%Lj)PbO&eK6`(?Vr+;Fz5aJFaEf$cWfay`WH%fWC2f(rwh)m1;|<=+8v z(P@&qi@go^gTHs=I_?V&9IBhRz|#uwA}cq=qXk~^$33-gY1*7-n(d&@$lyH8IN{#I zsqy=8us`w7{?$KxM;ZyHNn6wK?G4Z|L|BjmpiAN%KZ_{LW}&g@18A_2%4oguRNUcD z52(nB41Jdjx#zUmI(tDE@`X(Io%DrK`Vg&b370=TwyP4Xb|G4-Hwfk8;>y0p`>G#B zp_PP1{mK<)$2(VdR+=$m+Il(<_HK7X#x|ejzxN9oo#auOyDzgki|Z2Z)#IUHpA?}7 zO19TZD}@z{VkDrzLlB`P$Z`kJDq<d<+`0?dmwE8&Z>qdfY77pPr=awLXLee)ZO?Dq zF=%0UYNgd+8}bWo8A35lsx#oEboyc4@22LqqL6k-kPCp_mJ|bkm5GzL3etsZV3r~Y z&%;@$qntR}1gb2G_RSD>870<-U@f(C*d6?2GKoX}&3FnVZC%fU8ICN^cQ=&u5+WRV zN$Zc!cNOH)@d&qw4yCU|O_wGQpsEAT(Tfxk?upWTRA}ZD85Z+RpnS-mnd|J^T#h{M zlnj^3LHi(4mbbLTHHUONk1zu8`QGaMlUE*K#atq~=PcDB&z@TV9anBfOR%kFbc5mT zYu_&NN<(MmW7ApCza2^%)PPykeb<(5aM@}EN9#A~tIC7KHKH?WZ8{o(nQ28)GR6Ar z8N|~gtQx<HbRj?9^2Ke1chPrg@m6q%<)Z8o0d_=DL0p5}ANwy*P4H@TeyzZ@D-QPJ zLUW`E#XEK*PCd#!q*m}B1clxGjdDrMce4ZPE||*|3<EWybtVV6xNJETaNG7iwYw)s zSq4q=>TeBn8Ra}CLbU}!83jQuEAs8aM{igvCz`(Xu(bYgwH&qRn5nDWa=_t*`uqEP z8b%4fstbK#pX^lASxW6BqFG>3yF=J%hw9@OkP1o_8BnzDnpcIrec@b5Acq{<!3TNq z#Zj9U)~dK9YZOAeyDl2eOyCU!86yAwT`X?n2r*S8lG)_I|8|#>k4Jv^LL;NS0Zo+c z*ZVH23N-cDYjJd0*?2wY0NJcG1zEio+6<63ay%-BTB*X*ktEQc`7|Of+l}6`I6H8c z)Z62z&QT9C9W<%8*mb4eI(**>J{JW)S~~W1?bW?iqt+P=c*m;-aEIi!b4#i}rK|4S zFI;BYFs$fdJ)MNAMQ57<7<%sy*_x2R@>b8JIT}D50I3=XC|J=n=q)Tz=t<Av&`$`Y zYnQBt!+qS0f6(a7-_+eD$ljD5hV+>{63`)aAO(OTx%)T%Qh-=QthAQQ^=(KW^(G@A zME&*v2(>D7>1Qr$1lYpilm|v|PV;G;8kmY-Ln2x1`f^A*7GWm<mQt1W-kdj~2G?gD zZB~hjn4rGmuBq>HU&h`bdWn;u&Fl)Kf+`4oNz(`)?7o~CM6%6bHiOS+Z7quXB9JJ- zM%yJpL4_WdIK{(3n82<(SOQ^;seCSEPV@T-wwTmbq5V#-UX}^?e96Wp^2Al+k;w2J z2i{%(cxmRy+z2PNW)>`cd-Jl}Goo3BJ{-IT)VyMyolC*04==N9Y}Z-HEm&|Qb$V+m z$e)E-0@?Pd=Y>wsIPJN%p0JRtYnu6*rm%0X0OiZ)W*=Et1(X#A1_%{otc2Dt&=;S4 z8L*DXaZkfV^`A(OoM+b0Ev$~L1XFdEm9DK3<GZS=5^1a#NELe3Y}GImH}8S;v?wk2 z{k>)uGENTWN#wHDsTG!%XBZrM{k=iy94r{<j06KzPEiq+bP8m2vuH{If9kCg0oKx^ zQ4wy0DvRA0%)~`au2}_q#5-XPBFu0m%hz7er!jxr-bt}PlvR$p<cJ+oaIFW10BXoQ zPU^%EW93{ovQq@vxC|^J0i3ibD))zFU?WHTnX_|8o@~HdDYhI09?M3M*=EOM$3vag zK^pTw+{~PFs0hpo0GSwKz#D?F$V_zUTRcL=2Sin}U*ZN$G`ixH5vkUy2Z@Q};NRR_ z{}cc0;2++B<~&eIm+lkr#mEtMtxzf`qT7Kiys(;8O!JDq2%{xXu69C-1`z1IUpT<_ zH$QA2kGjLu8YU3f>LJAO%3-D$yd^tbxNJG|9loP3zt)v)EUj#9iOtgVS|8-AB-x^M zG_9A}A{Y;6-njqW2egS!e{M^l=pSDA{M^j2wW9d09GX@X`#N+2%$@!1#1+e)StU9- zws}QWUhWB8u8IT(;Oi$pBW(i^68i7u`uREx_PK519oQn1Txq}zm7Wl&VmMPgAWwyy zV8t2Q#!bmDl(tE(schJjSr2%emys_Zv(QY3l*2m${@pdy<Op^0VDra*?e}ZMS~9MG z<1^+Kt%fGq*8FWKr;u1KbzJ!Y6~)XKV4aTv-|7mdTyYG<?)r>QwCtl&2lE0p1(4VV zcP@~)QE<3P*cMcG-vP<Jj>~825Zp6etY0hHMxvYfBBIVJ*UCVeRqw3X&~R-SHi+Cs z6%b<;qKXwl?kW2gT%)9j)bq@Pcl`polph|sRJQPy%=kSLk>8k664<6^+flSD#7hZj z=VcSro?a6$LEZ9$Nlb_L=1Ws}d5UiVWdYovOj_~FrKg7ll0Sfr8kP@(XE8U-KXWxD zcDfhXXkoR<!UXnul{GLU+J2TgJQ72Q9i?ZW6I;1)>g2P_AMt%>&??IjcHIl{)zvN< zGX}Hnk#P(1OnvLZ)qC;RE>W+|SV|&b*O{Y&H;~375q=weL<TIBIuV8NTA;yQA?_dQ zg%~1&W}rD`!)U9K#q1z(cqVx?JZ*4OS$2?V&m0^ukJfuwpzXBaz+qPva)7@SCC!Eo zvP9zpJY!`=%UXXpp&QR`#ce!wuI)rGYX%DpLzWe^JD&Uk2jVZ-)a<9(5_!SUhc-t| zFp#j*OfF)JpkI1I*lqes+rffzJq&5N{DU8TmA-DL_MgF_-d!L6-T#Ev_5ar&`{#1e z&SqBL-cBF@C9w=W)Pbx*!Z;KW!ikZX2V3>QaQ}e@6X~s)=EW+shW>%h^rZ+fU6>H8 znLQUCA&eJ$8Nqg35qmw4u{4}r(9Rb-a0$qLq1_Rvs2eyTWIqjT*ID)>p61FNdU7h4 z)pu)R=#-2*l3Wt3Plpzx0PAk!88WrkKAYNnwaXBK{*O;g-5NHP7&iGF$lFP{3bAUv zj1z0s_;tu394hz(X;oqE6LFIimqB{PR;Z&mC{XtfEm&MQFNn+vt#3Dg<0;cCAUowt zP-Bi3EH+h&&K7XbS58a^8R+o<>)o_7kz{=E^#$%TGXgNZ%5m(Rvn@c+Nx*}El&wh) zMa<?vCYEpQ<OV3UKw_^#gp1m#ja_-#z^S`2CU+tU=p7Nm?T}wGFw7KOwMs#VGC;W^ z!ZGS5Kf~2s1Ut$~{g9PXw*kx#V*03PB1dt|-9Y((LAab2o_LmqZ~0J$#rYTE`b?2i zH|M#h^7S*{TKa&Ka;q+1w-V%vdCDiO&zq1yTmO8D?|2q$O#3w!@S~iWSpjOJQQ<Y~ z;>^Oi{wdrMi6HXoZRl!)=g;boz|@P+O^&*w>kUnSY!sh?#r2C|Qo4iQHPvDKXaK^w zli!(<8pnAIDGnqW=d;kp1>ki4#6NfiS%HpieLEo34+)z%&-o;wLgM1eZ~(EjN4_O+ zhr+9GB-Sq>xx^GcxbAX#=`pdfOV^zX(04-oT4>I++n=8qe)x(YORXV%5GU=Rmu>-I zwlKYx!OMw@-~!N9IDxiNuISFI2EUAfBvOG3y|!9lkWE?nBcF+<f;^@J31F|ibwIcr z$f?_kC%RbZ_2WF?X(YrI--DO7z-QU)@uOKS1tdiV$tZcD6cIr63qk%rIm>l&4wr+9 zRFSil@A<+}DKyi|fcdBO&j+9}`!YRYV?)fgZlkRl623hm2?ubalx(`hAL#r)e1Z4; zwn2IFd57Hp&;1Ix`3L{}hZiPzR-r8h^^4)L0n-B@>lVlsXuJqry4sV`>~QV+)!mBu z8*1*sH8O%wd6n&2GvnqdmZXM@#z$6y03>?rMKU1n-UG8DhIoB!`YA<Mw!~iiF%84K z0ZIMkP$0j(kqco*4pQNvweb;1O`<KobW#fJr5v6a3bWkgPEKBKwI8SWt918f+{Gu3 zv~i|Y1^P2hCzAD>sBqgbAISL-5P6~*ybRR0&o0iWZZ@|9x<tvra@Zz71O>sV`EkoD z%3?O4y~E}u9cE&7W6r^B*(AxJ5+`g&A)o=S#S6E$Sp{3x7_XMi>`Pb;SFK~EYXpvE z>&{aAk$HjYj2H^c{O^=5%&qG{+lt_v$oi1e)W0d`?krChs&+{;rW@E1q%vp25hKCm z-?X^|=wZAww|7I9CEn+*d|LWU#xNHx`)-ZZT3t2(oFKt#RdkT9GS4#)=peo_(PZJf zGF4`St~`2bo|po_opXDn@XiA)4quir+c}@GM^iA(Bq-#M27PvJ=R?NgY=O*>ajqzH zgxPycW)eG1j9Bm^4Q-&NuYda6ETKfWiPCTn6@r3gn^3Tp6HANWkB~Qh>eNSR1cdHT zX5ms+CCcSxL(LVx+b(Cxy#Z>Y*S1s(e(=0tiG>TeNrMWdUyn?o9X0x{oTpWH#Q_Xq zZYmy3(7M6~?w+JrDm<7ZVmH`5_dOH^$}#}bqm?t;5-?7M(H)WgipLlVQhOqPM!KLu zQB}^p+bO`r@`@*xcu1l{72_)S0zaQLftPfYfXyROb<TFDghCG0R+}zS#c#!u8GhN~ zeh1rD!%GH<omLmJDZ%0U11F2<Cy;HT`R6(M>_xGy$S}AVm>i9X!I@9y;H&~8qC~-F zOXS@e(h4&{hKu8cka{NM2!Pwey>YUTJJ<5=&~rrIfHR2xS;KmJ^k=%Xnrk;9T+h^n zvvNo%deLAz#{tJ<f8JlKrCWwy$lPTEe`UxrAb;~$-?|Cz(9S2$vd#`XN-yI+38%~| z+MPDRh54*!zhuxF7?PH=?D%@G`S#^-*0_m%hf?!Fmxx*%wIl-xe`v6--o`^?*B$M3 zNd`b$;fLFRway7&8v{V5u1xRYC~3Ljs9Y3?7EPx3-j^Gy-a?Z&ixfkGZXDig5j5yd zEk>>ARGGU4oDaRrA*8&C6{HElU5k<fQUSlb+)&POn24&SA^~FqGy)OgZVK9p%?4c{ zoLU?Tu@;(r0pHmJCfTv*7C0iv_(K)dU7HXr#K4}bqp{gD*d7JMUqm?ObIxa;t=BCY zas%jqtw}GwstH{S$(7L!86-p!E>?)ddtIU~a#l{PgIj|8)D1Hf{#qC{W8X}#a(6ch zwfpc?P>XjK3{?;T_vW?c6~lF20)v@QlNPgBIn@`=LODw06XvZNMwj_B#(+Q<W;@Xp zsN#GU#glL2g7H!F5FMMa%^DNP=K4%>Y0p<&A+2Uggb*(uHUIXN^zW4Mj*be)z3t(E z+s!C$Jhik9D4j$kfSxX_nj|}e$?DcH#TS(Fo;m{_N+pp7kQb(B2jWa;X23m+6^p(; zXryGmz`|pPzI}6hWcSOIFxzL1MXz5Qjy_zCTnRBAS)1{}sWXSJU%P?iNHuJ$-SG6l zAx8|iRB44C3#%2!<EntexdW;KadJG$Ip^0G%5)YaoAN3OykpYB?%+J3I0}6iydK-t z3#K%I)F3eNDLsVKiSy_@cRru~#P39I_0|;X7WCqDQ$uiVBgz+n^*D>A$%q5RT=$v9 znhsKZHy`3Q^a5*{F)X@JbqSMC;juD9yH%dhPLs8?QY4#)o6r#A{y<3tngEcFNx>*( znw35t`FU7LWy+d-ySaYoDVQm<0oOP->N0T$B5Et-{@>h)2qw*{#yc?f<6^~#_*uw4 z0flD=SKo#-A87b|dhWM=XMN_c|NX!EdxII$VrIDj%yK#ChX`*3)qW)9Ch(1_E9U+t z5Uhf_vd`uVc7;q<Q+O$4fV)`hbdgHx>CBsL7eF?i8d^*1%b#Xa2`r*xG@5#mZ*8&X z%J6P}`^sqs%Ih8STP(L%3Sz%l@s9%Z+ZPywdd1cI4yRP$3upiIUwV3sw`CtW{@lC6 zrIo(>4@o+h$kz@RK%1^Q@@SPHkFOV;fRy(MUZJUC1-1u}q;Re+k~CPR!_2Y;Y;kSD zN6o6oU4{lx?zD=Mw?U~L;ac-V)<6Y3VA7$_X5u=sOO#G(sq~D`F9Pw&t^tRY+-vl+ zvFZmBeX#J({1)WhT%TZPF&#yOFFSTPh5+<b<c|y@FfEtg3!WJ#+m(MhpCf6z73n$% z?{!<8VGOWk*4%dhd&C)*F|+9FN|QFy37F7cnUzOt<g}1xoF?cJ_Y2ufY0+&hDF)D$ z9IjpE88s{bclGchy2Q%R;D0b$`k)B&<oU%V4h|W{99-fx^HNmd(wGr0J~79`U&NQX zJ?;d*H{u(Br*c``V6D+rn3`ypwrldob!#=qltp$hgG9njp_Xiw9LdI!<zg`NRVlGg z<4sd})tLqEXqwogx5y2I*08w6mmiKMQN7=VJ|qN81G>V}>oHsv$fWY_2wLwA86}5f z>1*w3d@E`KRdGjIAIPQF96(mm09@g{RY!LSi^91xG<a)VGj0ddR%#-$=%ly|%n?(X z2cn(exsy$5HQNPs_9RFa{<FAX@ZUCP%~1jUJG`%mLjwZd1ECOrr%>!~l(33i!G|5K zMl*N}JZI*DVOEWAC9fdAAZ?hfm@W^lz7R(c8Ms%+->U>!Q<80ydF?GE!^#uF%1zX* zK;y^oOgP4xWN5OZzH$UeKa`2bA7jCO%^0R3k0Nz+%QQX0%|7_iuhy|P`*lFTUVxd+ z_{TOgivPmf0309uQ=iA)`-?yKKmBq;-G~Cl?V>Jz1?|3-9{YKIiH6WhDb}xk^!oau zo8Wq|2##$Z;l=G>4_&sZnOWJo1YnT2I!W}k4O=J3Wmc($jUd|j&Mr&cw`B8gP1rg( z%EF(*fYFy)s1J04F;8fhbpuzAkN{KNh=<M1=s!8iWu%f0qZ(0Sr_-jYIG)|U1%x$q z+|Opa5b|kAVHdWOA<JiZZij<S;I&I&1$hR`_w7H>Wx61@2Jf<9(mtxPpb&CEma5~0 zE>D8IxWQSUPa_<LN%o6)lw>NOlQ8F)r0<g1f<E34TMah_vzGo&+ygL0IPVAi8%kc@ z<MiMqy_Qi+Vhh;q<{(tNuSg9F{Y(q$nXe^>Vq8fF$g-!cgGfCvDaA?8b^rQhBn5@- ztIQh^1u(i*{1&ma?WGEcP^nZQm`C-E5hQ?VFmIs0^I<4%$sJKAqFAF7e8|j+ffqP* zPT2nKlM6z21cj}o&aP{6kB3_BE6MIU!{1xw-y3{IOmHmffmED}$4G{->_tYBj^2w7 zl|fH*!(HeOI5AlI;A2;J?_xDeW$z<h0Y*u=QF)ahx+V_GV6ZAJq_Dx3m2o!e35R?V zhl45m8xTR+F;*%=d+?fFUSpECuLFm+H$y;v`G#G4=zpDZ3UEb@*iH$?`{<%sJz5Hj z^J1tgI0o8?3d02GQAV1Y+OHYvgs`aw3&%|1h2Ap3`b!d6StNgJ8*D#FXt~sby1-&B z(53)HahQfK!fsq*WZ+(TsK6KAoSwXWS2cwQ9R#)7G_tF|>u8I`0(3-MNbZj>HS9A# zWUM{*4n3bx$9RGAG<}E$QJOC%2XE0y+A*l$<ZS$C$^js)iGnrfn*5CB`%tc<-9pYY z4xD#JkF)c-%nCW*!L*B3J>Z+bx7@FJ2d~xbaojpPf&*?{-yuHpfoHxy8gqq?JHPuM z%uoO1AN=DVzRc5xxLZ;C6FtI$lVhOY8Xp9I53E8S3xF4Aw#JD@df~Rqss*sGI>w-= zN<v{du%)4^91tGx&b9UP_#FPCMRCnp;F-ye!GcBapC2e0L#76p<)p|UY)^Mx^fTvr z<IB%=Z7Mn0J~I1+$+GtcXMeD-uUeGo{pqxAAo$g8e{KRhtZ|U<UC}1NR1gLF@rPHG zjHTkd`LbFgdES3CvgJuMfG(T0x!$MLM$3S(YUTH*Hy~ojvnzlCV{W44Q+mAwp@~7M znu5i8TKj@2pK!a-PpKd{3m@GnZCG55axC=h$J}+J@3L_5MYbvk1Zdp}zxeyQCvvEZ z(PN8IS7F|+i$Axz+ztHhrHEu2VT$0vC}V(ZI|MTd2PeC^B8oW%==)vi@iAsr>|L-= zFEw6SJpv7{1DAa<F?ikUA>Pq)EY#G(e9{~ajClq}gm|qEVd=CQiV%A_;?BI()LFn` zM%d;^oyHKQgb_w`VA5Dx`p~<{rN!>X2f5P`9R`B^?#teE&Zo@*k>?i5hoEruv0YpO zls*ja{at(C*vNeWEAI_nPrLWrA2q-2O;_)*=dcKN^R@`s9KR<5+7P(&N6s#wR7fXz z1(9jhj$0cD;Q^e1k11eO&Mjnf8*GHu?X0psbSi!uWwjk~%Y6l<ztmh4!0_DrI}9S| zo%%C4wZ!lYX(>ka(39Wbw492rUN0ZnY@vL&<Ob}1NDp-lbi(MX?peY9-jYRU)J=M4 z!Gm=7RmIv4*mD#sE2<;S%wkr}K&rt=W~<?VyFc9LU{Ko$;J6@y%d;iU9Edf^(nV*C zSE;Ee=)F-}wM}_6P)yP|etzK8SJOvl3Pap~S7_yE)KaIi0|6j5h?qW#ZFjB+ww`EG zbEU*yq77Q45S(?+H+9&D7<~`2O@i>tZJeE(^b;Q_E&SWRH&gVo3VZ=M;jqNj7sFY} z%*#&sRIkEbX03-{_DO6Hx|UxnqV5X~vWe$6_OCK0Z+xG3y&PoR_!tzj?*UfbEKHk# zS$lv=b_un@Up&2mZh&t;vz=v$<%^w0d%zS}Yze|6%_?I>=<{a$ZQ4We);%5NSWHEh z=-_mMKLX^3lF`#<hF^opZofd=(X6s0l;V0Fm?>odOj2a9R!u0K>;z50w$g8af?MoD z+jzIJisA_quM{=;@s*Z+bF+!SXMj0$u>qecBiGlIIFqd}C$4xpKal4^%Yc|`iI357 z!Pjm0+<H*x@^v8H(;7UB<53PIffEX%jXmZBssR=0cYtfHhoEW|g5I`(DnmrQwiz$a zoGJ^C&C8V!^8lS`H|aj?$ef}x6?g2Pi|3tUuISZ-ME2Yc^N>*!gmu8avC?1OOcsv8 z5JQw45NvmIpcpSO`0MOb9tjTfihc<d16_Dr=<wXz&-f)x92BS<3r{J_Or(X6KfA*h z_N;oAwti6Vc+ji>)Z7`~TEGU#8K!s)kFU#iV$9l=-KqQ9W{jQz1pPL#xtf$c7Tu31 zxSGmEi4ejc=4+U}2}~-E7Ji$AQuih5)w`8~4HS%{9^CQ3fvYW=#sOF^nsNDRUsq8m zZMTG56-wyJAnRr%Arx(-X{pVBYxSBjb|wI9y025gT#a>vE8}fsi<QSmugNLPv{r;r zO?4QeN%>dTymA1OR0Am5DsGNVBT#?+*(DyhuTo@ecB!lZ$_HFLQ_vTbd@r>4e&3&S zpCXdLa7$2alrg7}hl<fDD3fyrHj#CRs`6vslAe?7UmY2G7_anKsIt4hunK*xlQ%xh zSE6!o;>$m;^Wkm|8u%x7Nh(be{GQo3Fr9u4GX>HQ(GTL>$Nv|i@;~_PAHIAAEZYZ> zC<Tkva<L<!qlTpVwcwwk({T(`wkL}@tE2@86tGl!Ygb4X!L}S&1>*Ay?{WyZZYve; zQ)3jm{jY`65d^+>WxA6irb&ezC9b|-k}HM8F)qx}8O6hER+|d<&9S2NzH|N*b3uw7 z!j8rN9)e$F)X9~-5SV3L_M-gSPj9qY!t=9%{Q7mV_MITY@EC>x^F6%2;~*52a@;IX z5DKR0iz}&GpAp}>w;V;0n4c7pXe$Nd2MhekgXP2&N+i2ghnB~gQ<onKToW_w&>_r3 z7;GJeGdJ2QGt8oF1+yIT>h_X=ik_j*G;G<%IkG>{w~yhkiS9e+|Fz$csxp@kw!@b( z!!iIZ23yiN2&z-WI3JrvOM4$a2DrQx@m@6M7!G}a!=qaaMwrRM13jO!!XCE`if%wF zxv;y<bum+Ay^?gUee##7bO<_+qaS!TneDx<P1-zEFNmp|+-hm|2+cy1!6}CXEOI(> z2)RgJS_=h<{hnRt$n4JzSZB0z8#nJm%wBGqEMIQ<bk{J7pfz}|J<;c~w+Rt>IAYDP zn`HJ`{7sX>?HjmXmnlCp7k22|1n&YN9F#(c_#1xk(ql|4M_UiEy?TnF<-Td>@V=H_ zby!;Byzm-mg?)@<(6X5-)+}1#P)8oga&vLIK4Sqy^;MUX9#!BaVoqH}iK-MW_f@$p zJt`;%Z*H%ditl7wKxqlbgSE#I5i1?1MFEhbv;%b%Lk2vpTV1Vl+rq&+<Cj83@$FhX zh{&0Km$P(6H~2>%=J$RjHf~F2B3_I(N)(->m5DQ0<+HOF@k;DT2IaWu^jM(V(Ed_t zG5m2*^?BGhs)ID9ErFupuTEqM@u8+#@W`1JFVVt;TOGR{mgPSa`sYV;E`XJskkfQX zYnur0I%`!ZqBCUG2;zx4sv*eIIM%%%*{<9RpZqRl@L&A$AB}wyxcdKuswe~(U9|!* z5_^l%K6<*-4Zu7>^-ca1?I2~qPk?2CT2T1M*e=v}vFQhZmhRi~Wx+ags0NiMdwLwM z+-i)awPH8)xsqB>0F4hgc<b<rvw`#geSZ#t*(<5`457u<ob1qk68!oEu3N>0Mw%zM z$b|!28+VuLvs)Wlp+eu_N2A2@nmy-_Jy~%zH11o=vrtFg^!dT|SHedLc5NrgBejz3 z65z?)(u`FHh)K~1I0o;3kHd6msFmcz?k;36+Zh<KuRS^#vubw-&L$#(*s$Gz8T}jJ zi2R5vqGgbD#760L?2EI3eL$8?gvEgDzO21yMc(dmsj%x(!Ky0=imJSVoIEgHL*LCy zWw7AjOboYB6*|j>eS#1x@VElHx@H5TakG`>;-86ZP)hzjWF9b9pC2I0Hp!rFd-Zy( z6k5C5Ok3P+O|wfMVuRK|$KG?HsmyjH$1tsO374wt1?%;Zu+wb8d{QXNsmuIeWdy@M z0?IRXhT(Y8q%UX2K^Ngj0_f5@+Q69s32><A=2h}hXCSbk+3Ib&>F&CcgmCsUJsGOQ zVj_N!>pL@PZuacsIsm>S6E*UGV_`M=q>aVm?xNldL}2Y9m{eEr8v-lKEjUd-9f<19 zFu2!**@Ni^K_g3afVp>(U2!;Q^jaq-?uA%0ZY3D(YZC?;7ADFEJlmbZB$Pxskg<I9 z&zyBVPwJWNd>)*I-HKnWB22sSFr-u}N_0Q9=~<(J28w{S%4_wU)=uJQ;Ds&+L_?o% zEnkQ~)$wM~abkG<LhH_<Tfx7O`}$@Cjt6sP+LKr9b|pX#<(`9m?HP0ML$RMRwyr=| z*2z6Q5h<lsW+O@TFOv`UI^;C8p4q@|){xh0DGP6x1ml{=Iq<_9f9}ufxBcxO{t~bH zGW1PIZCWZ|kPo)X>9ruQ3xx4$vto_5;~Nm%V7#Naa$&qx?rV77jIuCNvCUOAr=L2p z($=0(GVT0h5or77IyNqQT2fjk4M1{^Ta*C*>CZp!uNOIWbOC|4?=VJt-sRo;SPJVL z5c5IRI!Jl*5k#7!GnUdII8TWRJ;Kf{?p39E+HyjTp>Cc6GhsGjsoJBG<N+W-9D{M5 z#G9~`ND~>7sm8Ze1{ZB0^lp#4m3^V0Ya=3PXEy~np^c#T#MC^upzsgy%z2AmHXgan zUx7OUWzVC;DHy_b=r>lbfnx*Yf^}IObc|uUd&WITrmLfvo$D70cXg95z6Ioj`0I~C zMWd>A)>)<n_%>9X`sU`9V4Pg0lSA-34Tw3B7n@sC1-Owim}`-8Lqe%hXu1NazB6re zg$aOALb`yNIco?B=)5-#4l^w*KD}56Zy%eG<LbE;TzHc%tZGAKb;|Q5a2;PI24Uu6 zlDuT=F=(xgayTy00bS7;ZE;y|6Ujt=H;7pI*3uH(Z}!NfI5#mRdbujw?Qfpe1?EBp ze|%xyrGfAw99{iRM1dI>s{ocZ*LEA%EGH{Tng5>DI7uxMCa++-4J5-k5ffq`V{g!7 zMjtK>*>f&Q(z)5g7_WL7o7IC%;<z@3t-YwgU`;oWn6P$-o;n?<rL%5j<Ci)YnUOCn zhx8i2nOJ`H_VK6_Abdk<r3j`BlmnNrui@cmyZjo6e=5w<6rL@|O}TBz=J5}}|HRf! zhA?}EQi!&nED*Q}G|6hW&8)p=n$RBXW8gBfO2>86X0j{?O%%}j8=4DzaR#+dAT3@B zRGI<nuUWuGYHF`Cj5+4PUkf&wzg`g0V-1LeyQkxJPA`|3P`BM|slbaovY9(_igZUP zX*nK?aWJ+diSai%Ba_q4O1`gRwul(@*Pr;Wk!1hg|NMJDquc)g0hm?;)YM{y2TuQh z%+(zMio4fmx7G%Dp?X9P9+KfW{xQ(;=fTsIgv|w5c}0N5JxzgM(kKULPI{|@)~e7A zJO12d3b;HB$+ms{c;(6=%|&TP9qGJ7;;NG?(naTujR%!luIKvr(Ym0{P5U6TRpWSQ z*k*;t0gKOmck)P+6jWokm>LqDJ{VcgQ#zZBy7aYh0knH#fdJI#lsxx3Z?S|FuN4x* zC6S}&tU_G#ElkLxh?BoKU7>hM0l<VHvXeL+G#4Q*+rKdxu-2#`iKGtzgJj}@8Nd0D zgR|=)eg&M_Q$?frnUVyqC!W?O_5zpdw)28my-nyI)uMAV?2y6(8{Lx#AAqMkjmu); z&2=csY)b`}+X8igE;yIEd520h8MgK+t`?Rkh(?^{b~b9O(@QU_vINqA2L;IGmHo8C z#wOVYYnQ(X8uQ00$E{ln9sj_TUgCjNm|?T^LTbaM50XTjfI(wPAPBL1WPRo+w;t;q zPl^+wDuK8688CXZB%vlsVP3jFx;#3%NY)a0VduokkS`Z?_6u7#kv1){lAX3TW58TI z1@|Ze8zf6*$?r>D2L*s-r{ldOrRZdnb!5_K0i{!|_B9@X;opA5Al1$b^5wghJjiW> z4X%<#oUTj(&(x>I9~;|@eL!+og0HNbs5`+wSb7hBXDh{<+}o$uWZtC3ZiFqH1Zyg6 zxw@E14weV(%V}J&z5F}$x&i3RJjO7M&>4c9cC=oE*JM)Pv?0WmA2w2qx_cjJRne72 zs@+nakoD(5?+dnM>}xedKoeYLrE=mS2tV;KoOu0(s?7k@8URArIXCx4mm0mo1l*h^ zRsibF!gmWQiyhMdeLEm87|PV$8O$G%m+2J*mDNwLn>PzWs`WyMYa}vL09U5$i>-`Y zwpqGw_Kgx47Ic~ErrckCd0zyp{_^&(e*L%ip)0hs;C5|LK!*_9JOZSUq6KKLDp_GB z7TV5Bz#C#>Ogx;r;!$AAPYfWKLNuAJwsMaFeZS54uXM7*6ZyxeNOkyUn5rC<-@sd% z-<lq4Yf>P^T;z)55#wl;Y<uGh9948KUzXHAH4@QzT~cVz%Me-Cl`SgEHYXUDpzE{P zNHBnN6-@FS7Ht6>UskX*<)INd7lBx&4zkhYQp6Gvmazc_`;qxpc~%?Fy>Y=jS#wTF zb(LXhT2r*D0EjXP`I}iSiJF~aaUvPQDp(wQbk4(r{_*G&ijRlIRbd%8(w3;?AYywQ zPio7A?BjbLfJ_2c23%ICoYYOSInO5H=a9e=cSyC=c_So{GjxLRfzO02ig6Q}D3*Gg zmHaUSs#8dRSD?)E6Fn+(*nI_Gd{IUN914sjhqVL!<bDSXC!5ItX`m{@8hd|ZVJ7+v z*}5roRxScG-)rKCyS9ra_--dHT=;rjU;ut4H4$}XkXiGS#ANRYxkY9jz><q)t~|cI zO`C;BL7m}X2)dEJ8tp<GDVjCx&C(90w<sylXVn@TEGXZuUBC8r?4w`~UaoIftA&Fp z<^8rb4n;@dp6Mu)Rs<@!&vM_aDU&ImRPPmXn*h6%YPPXhqF|`oG$t$KZ55Y+?5<a_ zh!k0bG#?bhN?|H$apVB}{08{@h@>?dLQxUEs1|E?Wotst&FzompRm#cG#-x?7hGrZ zIDPV2vsEvop>G}1GTeiId|fAQM?1O3J?xzsig=*W#TsMsXm_Bthq{BL<bdA;&`vck zJ;qQ9V|xS(B+Hb)$6sX80^T8)m=`w#ia(;pGESA@y*{@M%TF-i<4IceyJ<BI7XL_M z3@uXCcjRh4z-vqd7e~qQarCi0Q`(2$rak!zS}fsn>pK%jO$w~|<wwEmF;F->5ehoG z$m^B1FNMPd9Sb0!t-&hCZ(-{k0NbmypxyHF<J$n>0bmHEEpwK5rla;)>w>_Tb#6rw zkiRaidbK9B#NsMOdr9j10&M6vg77B<(**n;EcFW^$8DcIsRB|85U1oeV(pj@*gmhV z>9EeSfE`#spX!B%@o$Dcn(|rlJ(PX&GA88}9TZT6npI3H_hJ3p9xP(dR9D~zcib!~ z83OBq6GK&)*iv<)NlILjNIe%I*^04v9EuhnhKMEe)<JC9QhT*vdG}X<ZK7P#X<~f3 zW(A{_Z|6M<CnGagOS`MZioJ{k5@*6^K(ycZIG=ho)M@SYg0aXV!0F)_<lu6FdS|5F z&Dy?I>;PVoU~=Lxdap@j@{4d7K$Cv5PA*(~=`eh+ilnaMLx*y36;oK!{N8#){({>+ zes7c=CQU#Oh=Q%kE}w>daypa%CxL4WZnSh9&TAIZ#ubyu3H)usZo5hdCy=qhTyI7@ z5R=&(oO5>m;7KJ0Z-7*GnK(sqf9WP~09^hk=_;sfC}5<@n_sp_;3G85<$pKPN(C^} z|0cyK1PjQxgoM7&W&Q$_t2~+Q#m#&nC7P#_x~)ZPBs6c!F07f*mxyXyO0ZtO1`Pss z0~7I0M<w_s^{?D}_p?h@OaMALq$E^K2h-xetxf_WG`#|HT-wG+XF>8Q;&{DOQ0T9H z;RpcoPOd6I_W@M{0`gNi)b#A;MV+G>udImU9i9-{P+#rKs6DG=mh!p+K;H3QXHA@4 z7eQ13C4eky?@7B{O~Pef?0q?xO;XRx%h#if7-5p1i%-(r_e9I2)~8<~QMiQ^uO z!dzafg;npx^v~>m#7@3-N;FlTi8vm*4l>R?TjteD5}4nY6yt`kzc6jZLfvBYBsM## z@(lCsj(PBBZ!Dq`eEo+j5Y8YaDEL`K%^QnK1?U1@ZES(4-mDm2&;2rgPE?O{nSab4 z?viAW0g4Z#xYEa94q#L%oqj5($Tm2@#zCade)UM5J<Ci0lEN&{Hh@|L)fE5wDUt60 z-Ed1&y~BvcR`(ce$|Ar?Mw~MUs%E-KmmTd6lQh^nF3}#KWo9s|c6#}PgFp-a64})V zTEPNM%V&P_35q1(o%HjXdHD(Jy5?cp2AAvS=YynW)r#q00-<paO)B<{YpVx0$)H^m zsuvY+ykyWe<7Z)wf&}C$X>o9TJPi{HZ^C6OH%8^Fk#c#nCX2)-W0W|U(}$UfDDOpm zNXwebOq69CD0F2b(_(dgK*Q_dqB`{${a~uF1Ozj<SNA<O9@9jDu-sah7pW#E)lf5o zD7^kiQ3Awu(Z97JPtR<Tddl%w5dJ}KP2iCfTo96}Y`__oYHQ{JR_^O{f?Bbm!0_-! zJGLMS;paY9welu<KzWEK_^M|d$1^3Nr@0LW1}*ml+2XJ$74YH{mMwfef^3%SQOTH} z`bs$LYbclSGLd9SY1Q-+Kf%p=Z{HS1Htw;8<veO*(p*XH2e<-X0}BvH|4XFyQPVH2 zYT^Qp*^M4!Is*C%Dm8|*R5;ZTFn?{yb&7!(UI8hLltmYNzof#TMf+c(csiLbF?}<s zD1-5?24My90A2a{3rj1*H0Iu>ETX^`{Av{gN&r!vBY`@77+)*u#(qYW9Xa-W#E%b^ zOgmf+T$Ta0$5nx;W7a3gl+o_I%W`>QTi))4;QM8U!$DwwR7xKp3$yMU&EWdw`u4=y zJ(p|yLke#t+|b~4ZdG?8%fjZ4cyGWvWdf6cX6Yo{2J58=AdNFi?44qMPaD8e0HJyR zFZ@1&z<>3tH%<a4W9&ybKP`x4tp$HOwt(nhE84D(fIo#Cg0=pIolr<e`?6ej&`jlz z&+`Pw0<iGzt%6|nf%JXJ$4@|oKmR$dtJ!Bu2uOm=I6pam(YIsDB(wltLGsPVm%vof zugEHo5yu!VtvcZ(w^jYbS$e2cg6j`69;AYObUA*m<D1uh)HDElrkWOpOuEg*Z_rzd z6UND8F;T>U?TDWwAN4mWnBp#-F>JQNN(4Ij+}z&Brj%rn1KwR;^s>??>W7&XT<Y0u z{>|b{0jax;z%AIjW0;<%j#mY`d<Ug`Rz%*8XVHFQ-^rYoYNi^E=CBnYZxT6l9N;ZD zWq8u#37IX6rAb9s_8A_~QEe?_W(bva#=yNDb-prXgw45%ZlGxbTN??}Id1hW6pEcU zm^5xdG<%l;*?!d&;d7ZYGrx2NSf0}h{>f?gNlTbnyOY!Jab*TnE;EDQLL`w9_JS3^ zkpqSWbVJj?#hsVb>Z42BMQ>*O2HS7lDS8_#7}pmDzF&AH%}9_^F0!2=Tms=$jG28H zx;{%o!z0+Xq>@DcP(jOvXg~Y?^b6Q<1)VQWeaH2INhrNbbkEC<0pTa-s}OAGU9>~j z>aigK<}AbA;qtC6!en5qzd*_#sg&fE^syF!ghE-*+gw%DDx_&b=%DpX8ldca@P3A6 zlFQ13NR#Lc71u|wyaswmt4i)gvnXS3>rg8$OOG><QAvq~G!pT9Z!-#9t#+6Jbd8{0 z*GD3{uFbS$fR1^Vi-ER;Vavm+v~pOSM2>1sto#Eg6@We;rgIik7LnQ*z|D^NL0WM~ zj0@0lUQlq41Q%=zipT}lVPOJOVd&M?+?>9>fL*?v3SmpO3~$7`(0b{|)dZd}khR2w zATA}iXu^)6Tm<6mTc7yU;Ow9M&;Q#0`4&`)#62@`bWvVX1NAM5WEar)4QfGILh@0u z+2b2`E3gl|1$ROHK%_MD>bumFcNT-dRN(Q2m5tryv0JzX5|neAeZqjV?BRylkwYuD zb!UC?d~eJW%Y&RjK7k#jbYDyl8e2ZQIMZE1SHne~O|W-t)w9OgA!Q7%C&B4n%`KqC zE&g^A8ckX?aK2k2Vz5mXhI{{Vh5q2E8}#BpL&kA6gQ9>6p+!EsrDkd$IB!MB@T!o{ z<c{b{!0*1hut@rFbE>dD075Mj*lTd!36N5()iBH^8<;&}Gmpm9z>s$X3Si2vngR#r zM?ZRPU2_g_mB@D@SjU7A5IQ^Wn!EwETx1BXX(<`xNfzz07AnzsLh8xMqJv|>H{Jo9 zX$h~Tuehut7PH6ho^k5X6*=*nmLZd?Z<uKqZdZb$&FtvSsdOGApeDfk$-Q%e!%+a? z&DxM`b{eL<1QkU=TJm&nD9&z3k+o+y7tmhf2c0z_%E1$|+sonSTDBhNi#-2)8UVxk z(G;MnxDbvVg5gqV4~iznjScAsF||$)hfQ{^K3>Uj-2{tJ0e}dtuRsnUX`(CGI1g6v z#+@0^vqcwd7n+lMA`kW6^fPN!osYzsEk(AY_5p|b9jX-~HGdZAO>;!IYhJOef|f*< zq_P$^Si6j8mhy)}qitb4qN$mtp+YC(L9C}-$m{)Pbpb8SZ;@+1noYs9Bd6&|gU;9l ziZ1fEkJ$y&R@{Ix@q=!?URsDfR;yG9oY6>7MK1)jz;)3c(DN_;_>w8XUOI@c_0<Na zOy}swq_x<3YQtF8f9(|qL_;kh6#%>u91jEK(n)tUGnn%ZYop!ATgHspRD}xbOQ_fv z{pZ@Hq)}HxUk~1*wfFz~<{#b{_X0@*B@+Q@`yuI}3dk$u@6ztVQ(#ft#Tr%Uq%r_# zK9H?iE~Y7VHC=S@8n1Rr2<DI>YCQ(Av+x-OHX-<n1(YV8wnwDQPA`wM%#G&<dxsA! zq^lwje(d2IYu>mILSHKcp5SBZ7aH9Zfn~QQxDe5}x@4?8z~}NehpE7@#hJ|!)zVu< znLxB9D33Jl{Mpc$5oe!iD%}KtRSd8K&XF%IM080%|KKw4SX2-S%Hc`&uao1d8ht=& zqLv-tRVFB|W-k)ZuM|V8*c~)5Ytuk8T7%tW^c-;$jBka*6>4AiBS&`xQ3q&qkY2!q z=qxY;oyG8ky^y$yoB2{8g$#`~e)ri8f`g@2a0#;ma&r)LN1@Lj814<V)`<nuJBKdc z0s;R&iM|>t%T&{JXD+6x2Fo*Q9!dwDf8kPaQ@8*2x>c>g$*^ng1fQxi^i8?hn=!l} zT)eVL+9?WaCO%|V&U%8ka<EPY?(9kBiE=tjp5jj$Z`n6``COD}Kz_tm#kaqH=&$gN zuPBn=;(Lainl=X`sE*Y+WwJ=-_9~KFvQe`)flAa-P}jn&waBU@PhJlsoH3@q{nw26 zE2<vKzK{!8woG<*In}kq>wJQ=3EEMqWqgi^d!CgRZiGid?gYeSjhZwd?8t*<z_QY7 ztQ_{i<RW<<r3JjH%d^$(Aeo(L6k>Z9T#GT*)^bb@ucV{uINM>$hRFH|xC8(=s5~?* zPT0@*!<a{-?Y44D@cJPLYcy0VUi$?a;i7w(7@2d-ir@luqUm9{Fd)aSs2b4@OrkYN zg!+=PKU?x<RyCV1wEZ$~=y(L?1nHS9__4EkabypHQlu+)r6Lg>bl8=}qLhU5-se*I z;>(A%X4KC$RVfydF=qnd$J}>k#BE`(w!>lf|KzWWr>}yi-1H`vO8WLPPExtPI{@<H zXd4>Yn!>`Q_x_ZO5a$U93sW>~X(4$>YeNe)qE3RZb-r6);<e<XY3Q!X<@B-X(Bn`> z)>S|D)QOql(Wm1(1zsh@M}DL>K>buMTAlzoa_^rFcuI|_ST$Y7)15I?$=3$?v^TCa z9Bx%uP}349?hv@HshXY&EPl|MXbS{`<tk)X0_Dz&QQ>i&Ckc6!0xNtuVVlLOM7<^R z{Z)h?EaI&PQw6mrMZ_>XdIAJ%M#u-m<$d##P7?s(Cr>7Obd1R>bo3eC`(QsWxQtmY z8<8_~EFROSsSPc8Jv%`l7y`V6&PDRXA8H)jR8ip+ymgNlydv3d>!>I96=ZDyv&;JB z;*k`6($fb1_F{Q1-j9i!fyqg3fm&+dnCGcf)vG&FLjE@Ylhd5Q!;PbxevsSo2~d)I zjrSnSn018!TzF%d+}2DJoW$F+ICC`TlQ^$WCb?F%Y247%RE)M`S%vRH!lBvBQb#74 z!M2vH3?Ag(?&qn@RAZLn9@IWYHj9bUg4My3Yj;m>e)}dht*;O7Jrsvf8W5N)O2<EO zY$Xt@s2WTJt&+GRn;yV>FybeJ1l)pH#XG^6*TAI9SG7*vrsRjb6)so)JrscbDI)ev zb`WFho8*(g^Od8MudrCzK;HncU`?y|8*7+JFz&)zX-s(N)9YWjePfS6RvlNFTY)Cb zqUBNDB%DQc0C#}cB@|;jybghzm>@(f&rp)4hE7G%P-qLA8Y8SmU_oT|hugKk(EnP@ zZ=GrRJ{nhr`N*BQB(`jlrm88dI*W>fX&MQ_5tD(>qBkARsjf5%eIJZG3m%ps!8DZn z?eWm;(o;=F3qd79@2UzI9J5lYen&Vm1TcGm?P&)o9bWq6uk#fB^}qM8{NCqy$LD~< z1;|EXVU4QcqCY(WfbyqG_`{?NL`m<@9*5AmO{WO-JqRMGcF6lrDpfzm4ieFy`Y2~; zd^T3t5*6T#hZ4gZ{}YV+DY^W|j{=u!%rO^m(jyB{$scPjFrC;Rg?CuAH++*rW?jb7 zTR^eRu2@OY(aKTj!Iee^rNGV}pIoHZ))+B!+_KM&Nz?FA^_aK~a>_FSRNqx0BLOea zfc+j|WKb^?EgNJ54asYiBoHRJ@8fVowidw@GXV?4R*Dfqp@iIdj{y|$7YI>7PjN0? z1eH>PiWaf#NnRs@tE&uA!evQ8gTm+ohRb_$Z{c<fM|%=x9I0Sd=vn|9tR5}3VuyV^ zy)yWb80;e>F|PPuqzsFTEYZ-oj(2QYj$Q@;sXe!B+#QM7Z?<dUuGtyDgk2Z;Z(AOF z)vVgah7er$!FjB|51^eGe-Pkg&BPUqQ+q6&J}h7}cVd8}ftQGQ0exFXz`_N1?S$R4 z=s}QtzS~mB#mVdTAG)0Tz_{skK2Bci6M<vS4fh5NrZ&iLL#sY`mgT%$*Z_fvAQPA) zc~9A@=2BjKxGTM5jZ~$Al2eizSMMDyi|g!>O)&BRhht@$p^Xh~X4uE#u@aP5mDhQ{ zx$_)=1(93XGOQl~pr0AK?4tO(6C|^kzN^AY$o!@G>7V_^+&dEMl2I9-ad>H=$O5lf ziC|KGp9*VAEm6L3*;x)0D#T_}a=fI0Lc?o*Re>mw)Rq<2c4Av7FRlvuHXw%Wc??95 zgRt^SD+P_`j=aa7C6|_~3qW`&7Troh_3G(Cx-2X$X=po+(Q1JkB4wOGqbB%7iKgpo zu)k7g9FnWM*kp%qmW}{|Dc^F!v3yzROGlYrF!E}dvZZTSdtD-&_9zpRszQgSd$^nV za_N&iq%zdM55$0GRi|2>f8h^W*JvTQ$xVy_DiUd=#yvFMBdWkAkhC0aHI{s#v*V$I zul>{{Aw#bnyt4?h@u)%yM`urWN-BWItR+~to~ukOPhiTYdls(dw>d*o2u6UX>aBD( z$uC*5Mu4mL#mvO~q{`xVJ$lvSIXV+jr?K)53s_$SVT}kD9_CeS?O=|LU%#~BdIflS z!XHsilLMmrl8FnWd~k!8^vBasi+Le+v`#$1dM>0`c=-WL9s@MJ>8>6<2(b@(K%}lo zbs@IrGx=h|1-S4XpX@{ajUMPDDW;v@0tNwL8rVp|Y@+EsIywO|b3W$-yi#QWdr(UF z{9+_iup_8gM3qQhT89)nsjZ%SFYy$iyCB_pV1jv|%Z~ATd8)YLJ&_dT+~BsW#HJ7o zCldF2eo6)nBhEc?_>)Zf59auss$OdPFuqmbQav_01UEOmSBMbSYJJ5}=C6mtZ+PQ5 zI$A=(YW)tD-+$ekq>F1_t%YH@;Mi7-R{K=cZ5~5ZRKMl}vfjtJ1vgPqFU?Q6Sj&U< zsdOY<nV*8UB5&TnxkO1m(cs}&k2bH4MuNn&E_e|17j(J4uG2hbq(fk8NS>*oje7@z zKv<*<>5o!{dIpHXC>2til7S?DjF1VlEif8>ZT=CB2P&Ar)LAPOs_Sc^u;$N8UqYj` ziFX)fjt7i0*g`h)W()^Jg5il!MS2?(-3PPG2p#8(bDs2(c*M1FXAFl;VNo~mE(<3% zuc<g#+NGqnayc)_N6Rs#>gt8JtPmi!--#M?66~?r^t~T~T7qy+LzG<I1`2E|<F8^- zQZJAuX3A{2B_8FFmn&LoIO|4$x^eK2Q(M~>0N;d(lPBjqL1+?DfJzkExLV7MMcB_} z|3`#WfAHV_@IRd3H_~9FfdYV`pFLAdDu1pa(J~ydN3nr505OmTz{Ix0P`mS8=4UVC z#9KLg_&mMfg1<A3bSi}c(aZg5gVztWG4RW%`%Az(kQZty^uDP%KOe>8|5IS5<*bDA zjUxv$RVC75rF{N2C;U`4Ra~eDe{p7Gm)S;fmErITPtfST*UuW*l;2dCJ5pNX6<}>@ z<5mDb4%#s}mLLh0OiVf=J58~aVw+s@n{XyydSPj`G&o*Q-uKTyN~;SuN1cG~nt%ye z?HHbMeLEYd?e@&M$z1_MGU0Bo2JxWpxT0h^LMs!EstLO4?JReKXlgJWrItitL$cI9 z0g>V)&r%>uX!e9lc7Me}%8}&G^}{jZmbt=((KLpGCWXGPp&+WNw^I;q?*C|+Fz0pz zGgdq7B+oYxU=(}}?*Y&dNML)tF<LNAZtT+Cz|4hp?(9=R!5Jv6U>vN=>fW@eGT$cM zT+TjPYbzgh_0A;(878LFqY%|KiMEpfr)QK#9MnXlTp(W~O#&L(o<KeB{xr!wLIb+O z)5NN^#_lQN#|@g&Cv23#un^W$ZQ&KD18t~eJE8z@p<Y$|sSj)51W!Nhq6815_w$lh z4b$3dwYs-epwV4fOZ&Cq58`I^<(7W}sGt}{2d2}3OCUoR=D`wXCAXksTcZjRn+!gL z&hXzg#YFQXteXh7urrP)O#E^$2K*2UFBE`GJZ!3reamSH@CO|&I)%wa#8nsuNly+O zPWqd|Odoc5(Ll;QmF&N#={p5LRROr6;>5iB+aX(newb~!4fw)h9#9Ub;)HWaLy^>i zmN%h6_QiFxE&zvX`8NLL>=0pKFR!&<HR!i6`eh<0+t>Xy80?HW|0MpmlF|1%XFC<v z=}Hj-Fg@^_7XAaKS0Y9B%XNocqD@xt9^Yp}+0#~-E<Z*Ee&S$=Wsj`rm^8X*_?TW- z5hqm!h|<B>9&k@wv1>MixCo%RkX2cxJVoT$J4H~-aaDkaqSYTQvT7(T#Q>bO(Or0N zTSZpU6pL5aar@|ExwNX#|IXFBF;%%Ng59Y&aLKVG9n43~&QDzd|Bjk!TH_s`00kH- z?wVwh1gM!t(9Xg*v!?9j>#{WFubI#-0Jg)24pwHwQul4vCJ9rk2*AK9m=K)u;sYtZ zsGb!1`NatkL=55EjApq4f(R-`qV;1?ELE&++|_q~Zy3hPBH?_cbtb!p1v%5R>qYDq z&l}4&Yk<-PJg%50zz3`fY01~n2Y_kdhz!v~Vw<lsRZ71jx|b;>sug7+(gyYCLAFd% zr>iR$j22$m?#=GKRT4$3^Zk}TG2lKFu)dM|lyDtre&yJ~0&v9aN<ncyOw`dsg)iVT zEO>2+iEVc9vkDhPSj4Y^Nmy_0${C~-4{?Oqt+2TifkWJ2A`E#p-!t!l>geHMw0G`M zCO}uBT|Ep&rR-tp1Kt^aPv6ofUjuHWU@pKFShALs*HB3`75vAhY{LTA#D7{ZzKoF& zPj3_=!TW0r>-|KQ#{WR5u<4Rn@V9W++e?-@nG^bgD9duEdn-o?h0zlB2xn@kl8DiK zHNON!Miia==&Qm!>rb1T*Blhi4EQLczL%W7z$rL`Kj+?ldQC`7Gn7z9!r00wZR|jU z+y0EZ2;ftN-vPryM5F$L=(cG$$l-g4>(Fi3V);@t8;X@V=|rk!H!k4VXYO&d<7YLH zZN~k1Ccded&N{N&!{<16L;JsfI18=RVERBOEY)Y;>PGW{p+ixgjmQrgyT9P#FMXD4 z9`x3_@8sakgyGKQ?f|MhVu$|x-TCRi{9pd+H%{_iz!s;U@cjhWk_BqPcT)2L-4Q+= zrBXjkF^Ko*zHQ&MX}?&78~|H1NPiZL(=9qGz^t>>VH96gL*I6X!)$w%z#aR5%enw) z)T)*;@REnXEzsxsivycz3K!K+n(=&Yf^rX!1}yS~$DV(nh3ti(e0=(=r}*f5B53zF zdQnw4&#<*Mt>{An2I@_f?5QJSuo?O4!b*ia9(=HRVv5&u;bw`W6s5L2R5DdSL5rSk z|FIq%A@eNYG-w0%Ra3K>$R*8uZtfj%k-AUda$|*emSi<h6@s|~axRt!6l*|`G<co& zxx+omO@mld8^wdcmaJ&lAzpu`O1HQhVu4qi>h^%q8{xxEQ-FsFr9x{af|=^pPb48X z4SWk_wWF5+clLKdX-XtAE3Y=;R=Gw2e-hXuz~13Dp-m!Qwou;N%GuiQGWJDYjv1MD zj{Ty)=G*C}tV^I`_igbfadm6SyZm^cbvj%elRs@(2!&9Z*{7iT(v=YA(xv&LqJ}1a zMy@s!C=knBFu~l~^XG}Fo2xLWK~@a>>f*D|pQU>c(IY1yS{h1=FA5@*Cz?*D8FJiD zE(7rH){qxmoJ>-Fn8dqKaS}l=>3co>ucnm;*{OBhP|_?gDnUEN*D;+QnRtZB7*=N& zfrp-yr;WOHs<l+WRV<kl0eqh<IHf(RpjYn|i~K?L-d`ptuY+nbX!I3$l;38c<Xx!4 z!b2dCR6fe)B#o@`U4#h_u*Ih2wnkY)U995%z~BjR9)?-*eHd)!lnS<G&iIYG^L@EW z>7nQ3mcj!|_I&=KtoMC4^8i#@tbi{LBPr}z188A@Bs-KXN6!@S5OfXhwH%zyNREt6 z4}KHI8=X6pvQJzsS(-^lnwS~*iVjY4IZc=-I{-I(6XtpaRDI_M%A&vYtKWE$H|THN z5j`8)fo(tHe=;8S&tZ^j1Dc~m%#=?ikMlmS)UJiD!eTZQLZP82_vF!#&;61r3h2yM zf@#nVeRGRgomX`&Zqmf>p7DEE4y_lBm12s9i_%-y6$m@+HBk{h+HGK0bs!w`DG#Dj zy0tR1SM*=Aglg#v+}GCPZ}6d+TzJm<sgvB3nJ-FU;GIT$yy}uafdw);17Yz^W+Byy z1o$y9`6}mi4{z&`Nz$pq=UTj}QR1e+-VW3XRc+#lO1E+L2c09{<30(Q64iAhA$-DG zlay|iSCzAGSPh8|8-4%^fjbaMODv|KCrVF*sa*zGFLP+nyw1yT0JaWG1U3t3g<C1O zWtdP<@Tme{LvXoVrVJ0->|bJxtGalgMxqr>dvtezm-_jDbD)ttx4?bPlG>;Pxatup zoxA|TjhoU_(tS27F?;Wqz~Bk%Tj2fiplUJjaW6?!hT+D3Kz#tTvqV(Bts&*9RkgZt zlc#)pjRc`tLOfA-=WcDh*uJ@{ta_$M=_UciaXIVKHm5$t)VYWgi#df?1$2Lmw|Qp% z;Yzk+*ax0|5NoAb`<EYH-TsHC&%kvE;cp^!R^8}FPHVhhJ#ze6lPr+CVO4x~dLwjo z$dcL%>=reTecjw;U!|mX)jf}@YWjf=)6OE_nN1;VtcHj_P?pP-hw9sB4aAj2Lw)0B zLS|z2^jQIy7Y*OFadG5xr=RT%l{fgbEeSv|k|z>viv?RmaPRFCbIP%@S-^W>LsU3( z0cFEnC51Vq*RJ}KjViGBdZ6(oP^v>-zq%vQ45w~vGwLl`CuN%Jkr?<f$q*1R;p959 zHUzVjA|=yvftsg5`ICMm2@l>f@7xd)#nLWS#BKiv%mdZPh12iJrKP@dCvVGA^{CcL zt_1y@TtJ>V_)9dF`u<=2y}uyRu}O%c&{P;jwzR2|OEG&U@HVi<-E_L;?Rk*Mo-bbg z*tO0Db-GnViNL77*S6%Eg?DTWeLiF=Nre5{6P#*_<0UgRH{DPSqf`q2Zw1((l0}H4 zm_kLPAUxNQno}g|KRSD44<$oB-{G2=DfYSWR|txx!;mGsU5k_bpIrqQExzA{14f~1 z$S`@HFOo!)G9&<6l(P{iroj)WX#zwH?<XGZR&ZLlz_)b%<H2HIeK{GId%EZ;hcTq= zyW<lQ$~6O5Fmg8C?%hli!nIgRxVtJO?1sbwcq=?^=K9_Diu0F%o?>z@z@x$V<~@;{ zH4OlSkplMs$Hh5EtQ5<dRAb!-lpU*<2ucl6J}=2Iw<LLGB>-H`&OsnE?!?0UsBTRX zZnI(X(v|a^wf7nY2iui~+eRwp4ic-+m47p;D7P@ddnjX*8_s&Sxpd?Kt^<JmkoULp z_LE$VaXjD19q{zcqRZnwv_5}<c-c*>AK3iD&TsSO)HJ|#A+F}DN>YF5VVFadO)K7j zym~XqVs+mSx&D-rrfM=#cBrVeM~|h?-d?5&0{IFoi&A^+NaX2l4FMy9KP7yZq2Ur` zd4Vp|6MK9~lVN}9UP56&V%h80z8!u>Q9aR+_9)ock?HEmmqsYDII7%t8Fg#~IqA#r z*7W?G21P+TYPHl4Nn?qZM7$jMNzza&w}zwlF}DO@Pd)!4NV)NnqG+t_;lM@VDkeut zxIrFF2)el~e0v(Ad5uzhKS|Pr1S@!$7Xr4TT5epp;PrJyM?zxGsi3PEqST<FHtzX` zl>kd**x(>tSgaoa(Q=ES-Evd07#Qx*^<lxb<&zXa*aY%CNZ-F+Db>2m)Ea@7lK&NK zPr*v=N~a$vgK#zRM16x7+5mnNev-ggn2WgS`ct!GM}@#rCF2O~0hCTsdm(k!oi221 z6{7uN=)iv~{rw9mr>le?_(gLZBc<d*Bt>5jaI>HI=&LE$w~-1GK(>Mwlurq~)!x+V zK3yunvv^t!{UsW>hi8(R&W<f%Ts5FaYDmI;7BOYN)oDDCKTWEiVWJYWs?a2hCufdM zGPJxb60intdwKW}Lqre-Ok!aLMe!4a`IlwndCv!vy(ntpq-l!@VZlUEb-7Tj(bES2 zE@&uUogc4^)cy#5C_I4lf{1jgiIbP}DPN=flWBo)TLww0g$AODi*r8zh)XpfRX;2X z%4U$mxt?RX2PnOX77>ETaavZZ8ak6i;)U>UUHd!kA5MMnNT}^x0^pne(9Szb?Cqq( zcl!YJ^Myi8PeYpT6o&0JLv>a#6?DBa=uKa+V?VgY+(O3`@sa3zJKdt&fR~owH$?Rr zl=^|qQr2U^ze(Nf-X9KA^we&L)LG%v+lqLx<BUP~DMG?^ZXM#M2q<#lbt)M9^!kxK zHM4r+$!IoqNx!Ta$O}D`lHx=HNE3;pPi`fj-ffq_KD5-f&O#dfN`TEII!=Tjna1~U zx2sGOt<vJo8)0jFOVnLa-BZ95;f^Ays#Qw800(`cHTMS`Pytj0LuoaH${W)hucK>9 zubBJIVq=QhO=?D9MGZh75ChqZcsV}^<5xOh1ZfzIxXEpTRl9OGRCl&T!yT_vMGg4X zY=S{FM*I2JpFbjN9Wv)p;(Y(^bL-WfALQiRl`tA^ztu~ZtR{t?Cx(WrVsHh2FMWxL zVwm&25VFjfk07uB#nW>6cX?L!Qt{3N$D`whuR`i7QT54RTwgr@FFyB2WB=ym7XJ!F zlD<77QzsuvKbt(cSoQS*Eh;p7LGlUah=l6~$dxGv#s=o=0k_fe0gdtFKT0@7Ln&m^ zMB~7>hpCkP{`lS;mN<F{CR;%04yL%?&U#XkOcF?><42Nagpa)p{2Nz<>pN`fMT`lp zGF%97C7-ga{UHEh0?=z2XaYcq;m6j=5J=Y`CcLR>vDa5I0hPY0hbx7WH(6__jJ4>? zKa~<1@_$gT^!kj)L6(eXy^J)fp9+D^Vk%robsFh}J*Ffn@@PvhoeXr=pvDU@QEGc5 zWMbRCTatv2L74LZj?1s!#p@GcvMapy$zCDg&QCWDvBl_Wi1jxkV`qngw}x>k{EUiF z#4^LSkV%Hj*}Se43N7FNs`nu`kx$L;l%N^lo&vW5_GG7DW*V$M(Qxel6zy9DU~uFo zHbHB3OCZ^p{nrM|u-OBd0ThE}o97RKsI9FN)BV2Gk+jw>C)fo%Oziw@`x`%HMrfsd zVB->d`Hz^rEKm8+S;F5t%2^36j=UoP8=Nf7p7@Gf?50Vco%eTEhD%HLsB6Fa{c-SR z_vlBSja#W2C}XcN)D|^oQ3(+~>yu=tDNV9IpJpN=Vsi4yje~b4Liid!b&7+5Co6R{ zv_l9OaIDqyLP?S=3D{t5XaNrWm}oIV3A_#_B*3JE<c{BY{DZyVRUABY7eCS3U0K>t zI{?A^dDbOK(#5=#0~p$_WIH}os2O+zz<~Wg&8tb?W87L?JpXUWp#{Nc0BWfSn!Vbv zuX7UvYOyeABbahHJ60tem+Fnd2$LIfL(EtS%K7_A*eB$<{G=sJ&|t4C9gR9$KWf<l zp8Sig3h8#20LmGeZcVwvJQ?2@6=pf&&T6vku7ld0c9V-_7MdR8`S7cOlZNC@GUkKl z`5OM#zw>i{_x}M{jt73YT@-ch+1Vp7R<awU1ArEhHBm$ZUbJpT0*u+ci?#EovW+qk zb;f%TbUJ$nzHn?JNCIdLZb{pVe;^{q;&q8c3E!P9#wf&wJ}!#Oyq)2i3CpdSzkXnW z{9MBET!M3*JO0}Dg~>pyd*cg5PKCv0xEvx)oqpWLWVjBm(F+<Bi;xD22_=#6E?>tF zcyq;s$hr`^ZsunL^o_9C;A>8fva3QyzJr(4>TY7_d4F_})?QD7UWg%YHYMRHbZY&g z0z!&wVgm!H49sN8egF>+s|@R_T;)VvR(yapM}}1?6mTX{`D&qo*30yRuEPO6pgk8H z`u8Mz5sE_sIRxY3I3<n>W8>@R`HM3NpqN}3%rIN_CmZCBy;0UpwOnqI1hZ|IBX&Rf z)Qt)zf-Lt<I1EZ^xaV<D9pG%^>oYGuIzLYFyuJjx+$oB-&aj2a2%WpT%r#z04IPb> zTW6E~(ejMU5&DRoRXnd%PX-)9+>WOSE9gck4Ys2Z^N|j&zDGUO*;9UV%Y2c8rB43@ znF%)LCj@nD8kz5SWL#j%#!JN23#&IxkOv8EuW!EQXoaP0GhpRYy7H4bLNZERtLTQK z^I<-|cgF0^jao>q9QXJwK|!rfg037;M7+H|83#S7=G}8g(E`mNvBgZoU_I>#vLT*j z&4D0xUaBvWD7VmlABHsGE6O>HnIMT5bx-@`Ev#rBEP4qGB$8Hb*e7NdU40)c?s}S3 zh1Bwm<|~3B!fAom5-X+#D8Vbas*b4YXBFMbUkZR;4CAu`Kt5<_&iG0fZK8n6fOD8Q z{{TR8oQte7UH02b21z|z;k-HlM2+2=O52+8d-;!;xO!{rTW2HJnj~UdcGxqoqPo&Y z@KZDNBK`ON+V8^15|3lythUWlSD<IwiY~H6<C$Px`#}7JUM9XDmJJDD>zE}uo@wmQ zY$L`lPa&uElyQz1bx-OP7Q;L*$qG4MV6j4QB<&8S8A#{jZ`%YCD>*+Zd`#FKC1HtB z{RJ3r;Piyo@y>&-M(Y}xIUR6#Zk2VKdO2BaQ9zqe{n~o}@~D$KQS~l0m`sq#%Pfx! z;H?^RkKK|)`KfPdaVSiQfXMSv&Y(5&y&M-#mwqG3F(*CU_@}|YN9c%>G5~`i<3lC; z$p9~RHKfc#aX;l$sHD8gJ#`)J!{`dx0dhdVln#qEnFS{e1ytEzlM_N0+i7qWbjRY$ zne{^Va?QCWad~n^Xu^Utsp$aDY96Ogc3Yd}NQ-<XUtI^{TgjHq)j;0du$=vwIEuV) z^MaNksZBCGV?f)tCMhQsQIn}6plS9^d3`1?l7UWU+~6m#p1bmC7^67Z*zz2KiS!@w z1vt#8=60Ntu;tIrRzK4&9^fj5kgQB}OP%ToslCMXnEN|def|J^x~ht_)I$v?<xaQP zKXM8XM4!8TgE+h?gNT@4ua7HSucXotBzPIHBvPEp64SPI78@z<p@X!%&Jy_dqihaG z1NJ2oED@3j$};bn!6~HaOBzAuctAn6>`-|gEmEEMSBQT5>OCDYIs}NRb$}vM7B&GC z5Ipr$)?g`uNCQ=#^Mi$3XHO~+erEWVp?YHRJ|*81$Ak7{4#Y)1O>d=cs^Bq3$%LOO zx0)0?6GLVrp!-Tenf*2%8aB8tXnQOR5OUFbE>D7Vg8MQaq53h%4(VDp3VAbGbZ^@d z%0#GcE2<isekgcO)fIa>D1TVP`6IUb9JYCv_~WH-%@6+F55M)#@9;cJ8q<0soDA43 zTRY?}!Eomn3XU2bgE_G=S@Toj{2RW`k~*vC`;gjS=BR~Az<k_*TtIzuObv3DF&IN@ zII=Z#Z4~EHCjeY*A$Gr-$v!lsQRrzocEFZ|ebtWQ0BDwZP&uUcjW6-S?ZaU8(9zM( z^qH5o<54rvi8*<rxnp=FZz1qzY);Lf+)tq5PqYezq1_dd0ExMs?FN5Ol1ff^+yqnX zO+1>ulQUaOu&~At72~QBvX9jl6$%MUZ`GnF0p>?};h}By!q=*Fpw(r0+n^mxGEnXz zUh5e$@(gKPrp2+?xdckimd?&*pvBn3aN*06&(KOvA+*m23$?2^a_yyrTo>Cbj1HQ` zj+6*|1gKted?NQTW)N;b;05egCFGKT`_4N*4n0kgfALUJIm|lP!)U#zh>q*eqL{!Q zbC<m3A{a0S7^~Alb%#H5Rw`dNR<Kn&fFUvi4AxUre}U(7{wZ(zuB;QvguwJnisiX0 z&<*Zub<8(~-sQI7qWJ<C3trU2Zp1C=B+nUUnX5Y-XadIBl4j`Ce#Hl$mA(Z1XhL!% zVI~pq;);Z=_#j|LE@x@^F@{8&XTI>8Ec02qB~3?ncD#(1GU<IqF3&d#1w<qu4=+j; zKmil+gu+{8Nm@ANY-Hh=MxzR^hlah;EUQP|XSRl}gsMEbrnRZS^)7~i1DKkE$;n5H z8%2n*{=BrXDO?A__Tu=5xo8fc`3IS_#pV^T3qa4F6{{I-nX(MQx%~WqK({8K@aGXe zs_jY}G3wim*ma~6>0u8z1@kt_Zn07mNKK*SR=+U)iGNgjCLX3u4y7-^TveCLvbR5Q zyw4H;E2s<m1<f8e5eZ8yxh?93n^*Gb?>;@V`L}-I=YH!k4L=0PEty{6)5XqExoa(M z2ZU;qX*SlB1m!E>d?Kg|lF}ojcfA|>({=go>7bh1Ch%^En^e0>qh_Yo`uRmru9Gx- z?pqa{k85`aX-iMg`t-cx3SIQ$!vL^{Prv21FXKs0of)7Eo!<ouZvnF>w=^5HmV3{U z5vLNnC>A`cB0T8dSBS7z2jd2-Vw|2G@Wh1B!pa^y^OdF-MSJh(;e-UUQlBKM+ft&w z?a?pK;^5rLQA}n~>S$cqVrVUli?P2b7J>^g&@gu6_?GOMpn?Y%*Bio|10q~sNpdPM z2wnkrHCC)NvkG;UPg)7t<Hxu;k%^$(1n?R`m3e8pvg%{T#@L{WWhUm;nRG^Cnd|gM z+<#plY?VaJ788mHQ4;up31MfuN(w9+0<!Gr57MQ`er`t$V;B&~+{v<;9+puOlhb3a z=q>0ExdgE?U*UQ8OR@fk2LF87VYW$=hcj~%(2rvr<9FWH3K<56q0^ig+zS(D!6vjt zE;`hmZ*5J#zN5hke+3L=9^q@>kTpBF`Gbk+$=w0D#xm)S8cBJJY|{;T<2zwIlWAyi z@!b5wm@$`U$vFcC%`Tsq6T4<oL(Rju#oEhcCGFD$VY~>yEtz8Z1zO-iBab8ktvEjm z+*x0kFdgK)LvQ9MQ+nAIfWz2uhJu51Vuk{W%Lt45Jm-M5_gT1aCCpK{svNbN9z9J` z)!s$LCS}wNc$!+GCvm>adB4r45>S*$>H54NVO2Zu0+0*(0!~gPc5}RfXTW}(FD1=3 z^P^JLu58!ZiDb<FNH!}~08s=WhunK?{T)GVgb;z?k=Q^vwD9;+l*t#S5vaxK>X6(l zqx_mp+?6dH8^^o|7(+sbb?bAobEHQM>w8B$mjDAL!Ozq8-ti$1`M+5Dqp_cPjjtm? zbj8Hw5L#d&FIAF30ClB7esvMI#~ALq&&xfDvnwt(NqG^xBD~%uyFKI(Jle}$&O5Yl zY-F07<GjP3DJEJ2bStj!GC&OA={bNbqY<2w^Eq&G^VJ0?cxB2tuza&h)A#=p8vw`| zOtwGBGEDnO`0HoI$v3$j3ECGvUygYX(j<P3@Ee;Hnek?mWN_W&0Ne(**Um$}-R4p8 zrC*Z7!N-${<?qO86XWY$EIJN8QH{g_pdz~jhhH2_LW)Y-48xPR1yU2Oe|B_v9jcT{ zqRS>BJWbBEMT9s>Fer3ERAswjkL;J!c~pdcT!|Jzo_KtC+k+&=xZ!u^st#dKEHhQR zkdSI~E+UCwhAw!BoUsWH?*`@F$cys>neAYEiDvMZL>-bcp55EUKfxF755lXOhD<jB zF87C*#|tSt!jVVIqBSlJ<%|$W?y`1Su9h>_IE%uTI4jj2gw3Kb_H5N#@$#5pcD$RS zR3%wLq+5!Rc`Hh0l4J~?>v=EenlzGpd;Y14*_rNUHeSpeCh^^sn~q=lH8Ar{jJjv% zvRg9lhiWF|_T6#rdDifM>IzfV<*OgU5<_j7K4+UdUiT$gBBaY%`W|0Cm`cnoqw*bO zN0w)fHK#4xoYg;Weo40Wda~M8iTS=McKK9!iOxTr(ogK~!p}I7G=c59n^<BAn#>F( zY217*H`TdG<Dw3G_Skso%z#c&pql>hYgtWtU~n!N&%RFY(iUN}$<oU0gO<cs-;H-e zE0GE8iKiUd@P6pQ#L3>j*@*-+-Do00G=K=3V1p<q&Gt+pmfeqnf;Oll)_)f={;cXo zW1FdlKkO1!wG%LRo80{ocEumnQ`C7UhE9q6gwCVJU1Jc)d66C(t8_u7>Z61v(Pf@8 z5+zdv+ai@kidXd1S4%#mRS**)m#PJ5-SHt`{onfR&;6EQX*8_ZIJ(F`62uB{y^shP zxrv;vsw(&Xq^$TPuX4I5_kBekX5)}J#n5Dm_Cj?jEuRKL$)EQvM?l4+RY56r1YL(D zY(5s(CZS1>qz3jD5LKVKSU10SWl%Y(IH}T6i4BVFKE8$+;P{mQh{)AxpG#5cXD`}N zZjH7{3oi&u)&IlLv~uTr&6c21mGkCxV&uRA8FWy#)fj?j3D5ai{HG&OJR5LTaZe(X z7<;`qkEAIH<pP>wYzfyVd)S2N%#UAcoruK0%e=OV0(xx%pbv7)D?tpQ(hCsIf)k96 zxEn;2oDpod*m<te;Pfzw<%dg>V}j;f4}6h-`vLGJ+)UkE`SsrrV>4~kO_&2$fx*@h zIj1}jW*$-wJ~0LoD`C>zT)^`Mk(Q}*0}Do7jzd4db<610Cux7g1Hk^1%>e4<ES<P- zaS{KD%jx_f^G#s9qJlKn_?qU^+-)eTCQkTp^<kpCme~RHs}`U}IgwokYsUywI!nZv zB)XuU9ydsC7QcZy-I*CUjiax{xU{uoQ~yK9cuq|eE%T6J9-o0}D&&#%zP(n?Oikr3 zcpQIx7VM-O97UGeEi1wvo|xHaF<>k6(S@Yecz;CoI^#)#sZuQIc4_TVgG4r&o+7eM zNs<^@k*-wJIGerC9Zj)%_~R*ZMsmH>;Yb)+cX<yChdGRBR?Z=SB>LhZ%uOMnC$SBv zKN2>ty>$n!`s2oUk%whV_At8h_h`izoo*D-%lJSc%R#w0HB>JSX;qpBK#PcsZlA`u zH!ilbcy#y=JF>}y034sC;1b~?|GID%n*B(m*|^_vVU>~!0vFK~PJ8^9=s)bhO-wxy z$cwh#rC+pO=+qznL!s`@dSYt=?T>f5WqlH2XYTyX$4A?v%3<@|%rUm*13a11OP3c( zLc3JV{R(Bp>O|9GTmha~CFuIlcIs$MK>aWMPT{VL(M%i1<<wo5k<imMUdT1U^;1tU zBDt{0Sc&oux<fk4{eB8w3AExr4Uwv7mMd8LKx=q;Q%vF{S6p)66>csxYGObm2_X6_ z6<c=+nLyD_au;u)t2N`Md@1E9u66EPX5q@4v-M9dJv}EHX(S`tfRnJf$QT!rl<~g$ z8_!eF0akAYH4~4suTg2e{)YCQnL7di_eR|6aayam+j0kld=N;+#mTx7^AyfUAy_9Z z&_JV$V!IimJ0Hj~|ENGJ)(_r#PxiMwi5d-Bafy=<MHB4|g30VJ*5Ayy@F47PD+Pao zcK?+k%L}`hdBn5@*df!B;WAJpu)zXDuGx>ma){}*OLIF-hP^5uruMkOIQbp3KB_Dm zVjhR%_P}NtSa+xV?oUEpXWp)Mb5L4}G4DI1OAsRV))Dc_%+0UnpLh9Iz+0MNNmWbq zWQFB$a_Xa2xY+Q&Raz#W+_-!4l-~3ou^(;Ht4_nCajWP+ia98HZ1A@qIi2pA(7UCz z8yJ^*A0*4zDG}nmBw!D8;aSI#TJ4aQfI6{R5z$~;I1Ok_AN$F9!g{cR5WUwiL+VJP zQv#`}ewS|b#F`s1U}6Oiog+>c>{%+g(kRHKQ*c_0KEPzlYhMhOmu+W?kd_*qoSO?g z_qYbCm4{k@-DJ^A;C`s0(eqG}$O~1z%$uJ7p>EXE$BEp)YVM}?fqfDF-fHw^$;1%J z)$$g!)Vee?-gZ1f)p<k`+o<EwPIf450WK~~Hj_K&>0L|(mG8?_2k_@kNO<`N=$7Yx z?zfgCT$S+-kR{Mf$s;h>W6|g$$46u26CPjTGA!+<cp38PS9v}B2f3c%HgPgtl^)nQ zIUH~zE7yOO`-335{&dB}CymWdwzlxb_$ieH{SCUS1U*`$yfoO{l?7=yV!?QDkpp$K zGQUyJaM+fe*~Q?WL(b-O%ZirSkr4CpH&0T!V-F-oUJ>tvZ`K9ENI01q*h$vqsJ8^F z#hWIp*{0&<E^oJ_w02E`-0hQtU3f9ExA9(u)yAb8ysoB)lNp}xNFw0MV?^2lNs;{* z3BE)3R^o6RPjG$-1dm0$+I$cz0szFMgBk~PuPKL^7CBtfF7~E`2(I#_2`eDwt|Ja8 zp};2Dv7VLE`e@%RZN6@w&Fm@wf^}OEHvsIfoVAW=TcnT}b9eGP&o-P6Tnlb30ba)1 z!D6OWml9?#o){Bdt$opRb33_x!93tAR`=()Y25CG1j*W%mXF^8V!_S)FskM&j<bAA zEi`!b9HBbc?>a{nj~l7uM)$_27?LHDL5#0*k5hNWH)#-U$M{vB$S`<2dNz-HG?Ev2 z7WhJ*sC;>=>9l-+S!Lk-xQaYaU8Z<m>v?3oCJ*U4j}s3kw4NB=V~LK0pD&pa-hTh$ z?ok>Ftt6E(wR!#8<=2L5*ROsbsgi`mOR9wFD0GgZp{{ZKD<>{-|4Grz4}O8Xi0SYE z8ZUc_a?F=sW74?EwQM}bw8jXDkLmf@0?FX<0~#hWoY1$gW$}9eamfdcVT_CpW>L^8 zkcHoe*!Qh>p9~gx*d48<*4W5T`SH-uqR~jShdoSj!6d<DXoj)%gQY<iWr?b)?`~$^ zSoilXKt5j1$WO0h4jMs+BZ;0ku`u7a#XDPFHDhX*MXKdqGq2BW9}|9iRZ^U*iq3t# zI9uYp)fAPvT}&VA&c<F=pED}JryVUEd;I@kU8C>(>%V)vVPBXRJa1zcAgrds4G{@a zN8+EMbO()mInM%pSs;kcvH4T;6mb`WXxW>c5@`dR<lIeK^C&hG5?{DcF?cJ4x)_oF z5Dz&-=waH&8B41R*gBIW5BJ**-{kOmItu~eh?OGGZZEOX(?36j(>6xZ5KW%BQVo3G zO{Vi-avUHa6wkWzNncy)mIiS^p7Pz!yW7fCCcw9Y2BWLb6y}7Qgd)AiF`;?@V&N7o z@)i2#<WW4F{vdS3;(3G<t7S&^1CDdb1E5Y=)<o;kx#7{ac`b!-;ihePGGLrW%Ozy8 zO^}inN_W0NXCL3<NP~%qyYssL1G^Hw2`V+%iL^_CHi33I@AhSpRWU(4=&~lF&1HqV zBt4>t)~SP5vbfOIOWXqk-KIrsUiu1eMokz5t)pdJM1V@&2LHM8GMLn;XzQTCZ7o5- z!cUl7<|qcobE<cs>_`@sms$X^#TZGNZ?*3Jsl@R4;>I-sXc-R894xUKN6RBErF81D zAa1Wtb4<J(_=avV?c^jZ$DNh#x3^DxMeuBf%&<*G*S3;9iZFLYVo4r$BEsUDYa7vm z2Yv|1Kpo0WgST=NE6*ARM~GWkBF&Ook&p|&<NsS+eR>_NB*AcMC8%b;9VxIH#z#qm zCr&A&UA|hXWpT>t>W(gG_WayYAv6~7208ZnP%>@NCD4q(39iCmx6ays<VqLvzTg3> zj!@PrZXStI>B!HlzY-uxMCuQVCQokSaIDfx7fKF&R2W1$>;hRhDc9Rpw+#17E~b(% z#Ru2po-fF4HH;-ATBG09SK7YQkR3*7Hl~0QMfKdmN+@985WWmSUSks5`z@G2>mks1 zvDSn4el&qHssWP?*b}j%Q&|5Ss=fc<>p%RDuNa6nB!YpBwl6L=w33RQ`Y7{lWJO}n zRjKC`J9IGkr@HnWDXJ8PTqyY1wCGg*Foia;FwwOBA=|vW@^MOU3JdMClpPp_Id%(j zfM(E)snpoM5C7>8-&5H>Y(Lb0>PZ$*P<H#Bf`>(3r@Nq=zC<yJfP<P)0PE83Quruk zG#2&El8DF{yE-43$}wffB{-Jk#<hrKS8F;l;ieKhF1}eSyKsE9&QTz9$yW}H8Lz75 zR-%2;#T~2;G+q{}`29ndhnU-<I}i9&l3Z*{VlhdkYdqk*$c3hbG>(U$8Z6Q(*<A#) zK1X$jH<Shd0<O>mFTyO>=3uxg(LF&iSeIN)F2-0Jm}Ea0Y>S=e-J$GMU7wHiA?C$D z%A-^vzvL5gSz3mt0cOC_v-9Mgli^W~h4krN<hHRzb;x|vq_c7FBHVg$cAKc33y$y@ z36i|c1e6uOB-N4CheNT}yLQl$dj6#+Q$Zo6rKPvBS`p7Rp8C=9OKI&s!OZFO!?4JR z#ZaXQVkv`x3Yb7j{)T6Dhwp*W@LU4b{4LwGMK>}pazEFkh}zcCBWK0R;rqwe)e;F= z@2}kuv|f#>XA`#BX5$%ta4KRXIqHpjurE4tER8@I63s{LwDDvkOKO$?Zi4kL84~bd zyzX`4iYS^e8q(G<Lv&0w$AkFh8vuh_X__n-1HbwEDRVgl&-&U~QNhk?B#jI^Q;q#j z8adHV={y5U$tQnO1TaMBC9Sm0LGY;W?MBo}+DK8*sP>^D+z|b?H6A%$$>qLDn^-Cx z#?+`B!76oB*T9M4nft{``Bl+H2;P|ru2U55nT5@*4O<~;^JESw3H2^)7Ztimo)0j` z5zd*g-1|6`&XRU2U(&FF<Uy(dHtv1=m#!g9e)120mj_brRw?BNLT~xt`0n!Eu5|og zu09r$c?59i{8jG27V&dwm)IUVCWrEw)cB7WllU{@a)-B4*_Mgti%OfL=N{vGpcx&K zBhS(O?|S?IH{%u<%cps~!`I@QTRrKloX@lg_#;n&yInTiXWk^K>yXhtv&_iJv0NUh zei4?ow|kO6d3S~{@euzt>5O;!(D*k2&}3VemKY*&CM>ktMG(W0aB0$^cE>6m%m*8{ zv}p3yQ_oCJq#@IK&;ux&+u<%nYnz`0pI3@FMe8e?3m=5wUE#(~0E@huX}c5BImNK% zWuhh*ikKFD>I7;eP|%-0*pbQ_$%G=|fA*U-l-!f%C+ZxQ><=i5Ysr7Jh{b><gu!#0 zP{PF{NjMzBbBXc1|D?HZNFafACs2}H2Bf_ztJI5J=FXEIGNH20bNe`R0|<H78IljV zQ~AMAzVh6eTS><x-z0(+5q|!~+!7%%6c<UAJGjaOa8PLTD=QujBo;NCAb-u)o)1PV z9F`{Hy_xVXMt(e47;b5gJCgspG+*-qC}}*-ld<wexb<b&=n^P<1d!Jy_*gX%qMF7Q zn>-stp)H+bw@gUcak9|6=jIRGzV~`{C2H?{43sOj!Q`za>tTf=Iq+0d+N1+|D%i|k z9IeIlXbq#;_UVJqo+Ud&q?#Vb5#y%QlDJHUQ2B?!;^>sDFQ0Otz)D63I9<JGXEwyV zfU3wQ)<i~ZSzlu4|1RdvwBp2$iGoLa4+Cb1CZ}PE2{`9ynpwy+4V{Ss#&m1$6C;gJ zR<+UC$TYqbw9G>W#IV#E3fomsIe*EAkzEUI`K*IO<|C^@$$){tqYf;+M_lWKHvak& zc%ss%Xh{FuedAEJ<xtFC;BISDRC(@z?XZn>?tlD8ScIPcqp_c5LbdA<AO<%wf(5DM zji(nb+=ahQ3x9MH=(%O%g@ZNj$Jas*K`3x`R3S7wlVRzWe(MM)umwZ)NVItmkQP6j zUO3>Xd!k6Dhau1o{>PIxRaX>Rs47yx%F~)1L`e%9KWkIWuDY>{+Fz}5$(jewy$yY$ z4`v0v)YwGe19T1wms=#4Nuly&cO~I;<B?*W8kj&KD3_hUtCA`)iF|3k5-|jVScL?+ zsD|K`P(i+!eT%dCI@VjB^1&74K}<3M>PpVcgLyn-p*AUpE+$xtT>)EUIz&1cTZ1zr z%<eU3px3Y7f%b!yvO?VRPqHaGf_tA7pb9M0W_M~sSPMQdpvlUG2O7F&n4pUmqBfm$ zCmfKIa^eW41PL!oYCSJOI+w3Iyra_N($}0l7l3DeB4d)0fv;~AXoi@IjOzxmjETK2 zVZiD)kcg(@FtC5n87VZMZKZ`%8;mlRf>Zn{E64Fz_qWKzIhSHCEBB3W1#5fXK69_( z2KDD`GNau|b#s6k3o~6|c;?x8Mm~0l-+3<v-Rc;^?u?VwWqE!1#M9Kh7Q~><+r+0+ z;%A8c(wX2<DwS6v_~lg|>3ew#^7;RFbq1|<T~`#A<vii4HW(s`t4VEx!*h$lE+P~% zk?o2ovRxFVg_22QrvbU6c90G_sjbANQBsiIhe-_~vXF(-Q3Cn_u8BR!NLD;(JLt4f zXlEU?l(yfu_POsVnFvYm-FweH_nvjuT6>>;LXfs@-M{PFne($LKYaQyJ^D%?C=8ym zmj(e7>_AE28+e+Ar-vaNKdN0B!8=L_m*j^2ne#{(W?K#zA}F5D9xEeJ(ibd}YLZdU z@Wqb=WequH*`Yu*A$CpxLdJ|zCd98*lD!BtVRq-YO*o9mU$o*6zqN?+Vg;c9&W4PH zn2_YLS%HjL1j&7bP+C7EV5k0<{~dH@i1qnE>$jE%0RnUT@iLo(IgaajMr>aPo;#5H zbW^Kiz;|HjfTS~45z2Igeefx8BR4H)lfX~I(jPyi9MR@4KR6~(5z|VBPUqdFOxvvM zz5|%NE@D_LLF`KP?QQfo%ub4j9;W6t2-um4vQ9$GZO@61d4CFkgMxImOb@i24kQOv zqpk5P2l?eO@7gWR#-Uef1bcIQn(ck`10ukCCzAg@bWH>6oONlau<K?l#bE}9ydjv1 zx&mMr&DPIg9AL&34RlcQf71xjvpxR5bi~liXkiSCL4s+Hd5p5o!dk01M7&8+VD=IB z{*p<B%YB9IwFp~n%;ktpfgt2Bj74SM&crC=J~iza%mfOeO@}rmRLCRwq`@Q1wf=^Y zHW&l{?5f3Wi>xKsQ~WpxwFe(%oedui<FInmbIJgTWoXG37liP3mk&YBk7SiA@EHn0 zM5K7<MXuz;P`I{2r{^T$%4-eD>xr*(<_Y>|c(_&3IKW0!KM93kacJwfNsu64ls=PF zyAqRs3(e;kyUl50DoUDF-5k?Lzqsbf{Cv@L_Tg&(?f@p-7^IT?N_08&b9TpB#0h1} zjDQw0Pk!cOK8Dq|9Lg2_j;Ft2Dg=Ffh3K|MAfY6e*xm9@<?>X0OtKptoq)?75_KG! z<oQU?rt}xBmw`to4{HA6@6LsJQ9olE0?F@L0GQmM$3^srp|>2GQxk6|o9FezyNKXR zUC_k!+B0&&Ean05ye_N?`)-uiD1d0fiM3U>eRIYpxrEXMfz%Eq0W%2JesESZZL-F% z&L<Wd6@f$wvj=T7*w-=+A!lG3w3eHn;>W=SbD>UyS9Sxdl{yf!sxfkkvz-loJ-BG& z<csT~Od$UHjiQCl3meT%G~i(GSk;&ZcxdDHdnQF)ZM*#>a>Z*9UYu69piYa-aNb5= z$v!8FMKme__Wsv--aq>2!@vGewBpPffr&`R?E|a>U*V5@lGV{~3w6-Og+>9pm~|;= zfvlvi5L(#9X*-NO%8nMHczznSY*?D}Ct^a7r7dwh*d>|+lSyt*C|WL?F!$?|{mq%6 zCv^F0EzAKc<4+!Yhpeb9`3?v^@E9+j4Jtpm0eth#W*-sFp6pj*u(U9{5>Qfzx8QhW zaYoAS8{uErTdFY0kbg7Yc+&hmRX*Y*pi>ssO|Y+*P{H*G<nuhRrld3YkY|vlMRQre zrQ<Q^_Qui~$T)+XuJVh{3Z;H+iF7}*7F~@(BaWx?FE`Mk1faxtt&H%*THu~1nZ6o* zgz;8*;~s;adUT0L<T4BCfi4qqT(}ReixTi)CJbDLibw#s(YdDRYy!L50?^{5RJxjF zs!Ji_kxPqbclZvmUjpiW+eIr_wdEI*LU6`#k_oAN%EssB8^*Xm@k0B`;ltbPC-9!d zE-c4sQR|DczU@wXGmV|*?@o}ri+WD`H`=ed&iugMeVIZsdvHr#8|kz~<}TP0(<8mV z$Un3tS8ki~;I<b|m5K5zqj4g`SLs?>%trvQrB#UTyh{(9<~NMpaIdrT%nebUz0@K9 z$#r-k`RC8SC3RuHnwF6Rv4SPtxkwUU7p+-@xlAv>ukf7!ovRz2kcJWB%-v;+GN!O@ z9Z!rz5Gx$Aa$Q`DNRf`%e<YS`FEZ+D%ZUTFj%AOr--I)Taa;V7WOL~mt|p4TZ4)tE zF$0tgo?H^|2qx<mrtSO~mXM^OJ&+^2ytz@tUK^3*N}I~f5PpwHe&i+eA4TYJ%}gSR z(NuirnHgE3kTu2=FBfy)p<H3r{s9^HZI3vjI8V+F6p^`LPb4O{=`I~{O+kd}rcrLs zm6xI0pYklh$jVq<{|W<LS^WYp<{n)Oe|X4k%>tN`tm#?OuCw=J!0GVfa#6rh`VKtJ zvX`A0-&0bJm*`6Zn~6pgZWY(sL7q5vB40+}yJaL7E@}LbkAz7h)M0@|Q(I+?qx<(3 z3BJttKG6_KOC_CX?Vx4bgVHbTEx$%LVKSndYAA=`NU~b)pdbVWAWx%;k3$g9rx|4l z05Ixb{6#Imxd$frP3*xQ!kH|c5Wbu90M~UtxTtPz>_>IDaI(0lps}(h*u1Om)jLaG z%F+>DBWP_$9qUZ%k-_^eFm7*b(40!6yaLw=l}wBSqyY|3j)BC-J#p`=oOpiOxKi$5 zXUQOacouCME#(meZGwoLCTzPpn{!BuroKZjRiO)Xar>NW7C@+H0a8GTlAwv~aOAT8 zTq0VN#!9o}hjz)GbO2CANWYtN&Y$Bo1gV5X;Wb{uJTn6FS6aO(a#`y~Vh3Gix&WhY z__$Wq_$bt~$31evnsHcQnY2uhI!{_U%;S<1lh5?rnWsdCnCs=2CJLCR#4T8*vU4Ca z?fIbiXInWrT<gswXtPoT^?H6?r&Ki0k*;8k$aKG7d!!vQ?WcpETOVB7nwbzaSeawS z&K!n7S&d7sGXydL1h`qTq`9fjo}FSD_95cgl|aa%7}56(HPIzagTeOT4+cXMA5TnI zC?q!swM&9xFhzY_(lV*$V`VjRXaP?^aI^xZZ2*x{JMy{r4`jU~{Ps?tsz_BryeZ>? zb_FnyA@spZ$6%aH3k$D60z3X^AUQh#9WQ)LExAO0%KjUpF&5C=i>A;_fG!E<NbGs* z8FfrIQhZxo%>Qr^LtIM@%R$A=LjS!SGQcT^>?#zCxhHsiOw*KamPfg@4}!G+8&<t| z@n3&zOA7-*?`b#_y*PDLR}kuzRnj9p%wxTkIaN_y={+!jYb_1(`yU6~c;#V-6>Ao} zOy7w<KF!A=j|Hp?4fc37uQA@5d}dx6D)WGuAM=b{Qd4}?U^dA2B`v)Uqb;>h%SUj^ z>EyXV+kJZV<u=-aIoeh0Raitk4zQT79iRcwS}fF|y&5U#pgf3ah-y34Dm)~EvT~kp z5DX#Lu_y7Pd0(VbLyr>T*t{`Oh(PxMGlML_#W1xoLZ#&UL0dA|EpFDG$p}R&1Bv)< zMx-(pT*V?w`s75G44zvx?rU3<w#_;3VdKr}KkgE)$nD(_a0<%Wif`zl{Fhhog=!Bl z^wNN@aVHlDThmJHRsc$fVur9Vq$x*zygOd|!b`-ao-AP3;y%1Sk(>~neV$yP6Ud;Y zNalo_X~;~M<(cR(u^;!H0Dgg_EU^K3fonjTN5M_G0FsBt92I@uYwVJ=POk0?5YY>p zL`t8(j}U$!rVc|nA@Y4@o;xR>Rw?xH0mM9azl1SK=dXag1lN!5Rpye@$;mP|>n>=` zA)`yA%Jagz)*ldG2Cn&yXLTs+5Q~5%jr<b(<W8^4=90u?&W;MSRp&W@%f?=5qT>!; zVM>&ff0I-l>r`U6MP@_XV0!yIwOlg0Td>oJS5PC+C(%rD3^0WqXcXOeZCD|p)3Knp zn?uL~&6pO7IuI$;P#JeA=@gNW4TCtHYZ)i+Qg*UorKBL~d48aH?R&Dd&ja5hwLeTu zRC~)n=}Z)MXeiy$3YzIJ2Kz;<AZ&h2JTYx*gprJ)mQCL<5(`sgGfN=xFfq4auaVQn zEjtR?a?V>Tgh&q18@;nI_9pR^f8YG?&jF8!Y85j&_d=wwLRR*eAjT)X`bDXIdsA0a zbPVGIN{2Z&Y;NAxc>^l7W8>Fa%^(0T3FXZU9Bh}f_`s|9Wf89geQS*P_TC}?0FYxh z`dxwUrE7zf>z!%m@SAv=B!5%1b13;Euf_Pb4~3+Wc2hWw5zf2rD9~+`;}DXL4n{(e zuNbp_!!g3&B#aaEG;<sPnWGyNevIqOY=b)tR+BQl!?{;QCg2KqTdTi!K|U97Pg*PS z3xS;G?FEs*^;c_5wYUw}EAP$L$>N4GP`MkHreMEmmQLA$QTpLMasEaS*}?uOLetTz zIbc2jlpbmICQLyu*D)ARuaZG6g$<-BKn2QT$t=a=zegsA$SP1ekya8;@F>fo!#I~f z)x=;1OK(i(Jk?_yedOVFry%&5cTEL5UI;?OL}cD&z6w`NO8e7HX+rehD@1i}wP|N) zsGW2fL!u|4JkM>ko_C#1&2)%>G6JCW319cd5m?#;pQQ#+aXzc0HRBPqZynE+_2)Ma z^30u4JLl0C#66utU!Qz$oyTZ?P<Z2(S>U|nk5|@qcPSIJd~YTou=aVN4xfyOh8yKL z77bAx-Zeyhw?BjSti*Bk@cR!wp9fQ0_8)Tb{m@JtLb+6xMIUE&Od<{F_iLU{Vzj2{ z;9)8iff+I>iBr>pfNhpqmm8_v7E9vlt?eApH+194#8p;LUQ^Mw=*&dSN>s#9l2Zt- zaF|!7@THv|UjRYe?Ll^V{%RogXU1{B<;K>GK+!yKHVeBc`}=(D3I-}RXjGRY;Av9j zJ#n>`nyBZP4;0U){3N}pQXUITdAZDZ=b8b|tdPNkrJd7-@B4VwEc62<9W)MF-+i=+ zp#Cm``dqOrV2O$SnR^?RO%pfI7g5+c1|Xy|g^3eUwk>zN0J2!#iBl(z0b5bbV>}Qu zBj+E!6-u~FB4qOf`AV`GMb>f~Iq<o_pw#g+V{t?ffs~UZB$b%<9Yo((a6DTw*702P zvM9QM8L$EnVo8RjE~KEvYbUs%L+!#CGk@vZxiP5M?88j&YTg@=Ww;ekLHH50A>2|~ z!p+s<tW}{5&?xAGGl6M;A(+aYrV`C&xBE&W5R6`-#$dRTQQQK;cv@A(CduHVv_U1_ zaBOpZfVw4LH}#G9>_s0pJ{EZ%hYX@qgSYf<tiI3~^{S9Q%U_Yam41`aPe?=<4{X!( zggrWmTA>Jz%^|YiaR}Nf8hmP{_FG6<pB(<g<VqY;4tI59|5aW!Yu$orU?caM4?r29 zlTV!<0Kd&e?gjdXsP&7qk(uv0Ius8=m_zaw?(XRxCPStoxMSj2ZPIxnZOf7)xICS^ zAxxj-O`YA@*36YG=H_Y237i@s7jSMWTKeg01L+4?G8aHZ<?_+=MrfeTpx_nQX<3fv z?}NB{9$Cl^q;lZvxubR|W9wXnH;MDWcDl?$FcMk36~J>9G69Ljz=6?*+Ld8_*~$&S zxB9uGmtfJBD1}m{i?l5rztjCjlBytjmnXCPN(Oo2K%a$Aig%~Yv*Dm3jyV$~>71NP zH<Oh-jF(u3#z0J7loFmi6DCG;L9C)&iEJc^CfMGEj!nMF&I#oiRvPA}IoyyDEX0{D z;_}>I(jdj6OXV)kKtm1C&@NDlYHRS>#Gr?fnU+Eh_J;rp+Jl{|EN~oA#+kvv12JkL zs<r2jw9p$V;yBiw*=UlEX7yrnI+@7G3ve5>jsuVJW+Z!Dr2f`FpZ(82809X#{^l&` z@Y@y_DKAiDYp`hWnfQjrw2>IVkFfRnlUi{y4iI^uI;Mf;g`7d=Kv<^!Td6a=C<{X< z^T4VxNrf`=<_lc~U@ndDe)as&a1?K|S3~Mq45d1kbi!WS4b!A)Eh2pzXa{U7)kmVp zgmB-`az!Un3-@*mz)5_yUgbc~NkrC{hl^0eGV=F)(LdrlQ;SQSK<S6V6_E@<z$kYZ zX^cjJwLzeA7%J!av@Ky}1LG(?Ts{8gGXRxR4PNcFTrHm`cyQX_P{IP{eNUor!2%P} z8P}>`nz!89pc^GeeN3uq*-JAvS*a6h8}E~v4uZM|Yjzf+!6OAYOg{|0oJSRdO3f5S z#E)w-xPV6pBM6@Lj$p_Tgu74+a@*q|$-EajsvOMMIFrPUxuBX<sK=AygssFetC?-O z%n|Sf2d>#6=~JEz@0-(#jU<L6fD`=!ZB1`4a}=Ij$*5fwPv6Q)DR(A12;?pGf4b44 zG>Of86qXo+lHTo1<G}qR+TtRk3Wu|x=hD=+-I~A)HUgJMfP=e<&NwUO7bXHTcj#c= zi|0Q$t7{Q2bK=+rVO};>WQ#G2nWOr)Zn>21EbIwYOTzVRa-O@02&h2`3$u1)ExU`q zI>D=>%v6sGZPpAbZ3@FARUB&gG@+bI`>Ramw<}2oKnpr;?FW};rlusWWW}sU+E$H> zF}U5d`9B423CA>Sy!#GCFA(+6wY8m;t_7hgOVZN>7uEheBNxZ8`DDj9S10|A#WvX$ zhzHkYQvzcPJZXjAnRixMQeKhhJ=CzPCcH2~Yr7~o*J3rLb%XegCEG4He>oA8Vz_VV rG8#l`@t+`W$#A*=Y5ek>wrW`gqdI97tT|-3Nx};%HbnjKe}DQv`I8l5 literal 0 HcmV?d00001 diff --git a/jdk/src/share/demo/java2d/J2DBench/resources/cmm_images/img_icc_medium.jpg b/jdk/src/share/demo/java2d/J2DBench/resources/cmm_images/img_icc_medium.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6b4ef3f38d14d03a7f990e4d50e25af75e1d3a8b GIT binary patch literal 148164 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 E4}Ybyp8x;= literal 0 HcmV?d00001 diff --git a/jdk/src/share/demo/java2d/J2DBench/resources/cmm_images/img_icc_small.jpg b/jdk/src/share/demo/java2d/J2DBench/resources/cmm_images/img_icc_small.jpg new file mode 100644 index 0000000000000000000000000000000000000000..41fb2eaccbafed7d86598d7e7642e197192f402e GIT binary patch literal 16258 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 literal 0 HcmV?d00001 diff --git a/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/ColorConversionTests.java b/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/ColorConversionTests.java index e71b18857f1..4916929c32f 100644 --- a/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/ColorConversionTests.java +++ b/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/ColorConversionTests.java @@ -51,6 +51,7 @@ public class ColorConversionTests extends CMMTests { DataConversionTests.init(); ColorConvertOpTests.init(); + EmbeddedProfileTests.init(); } protected ColorConversionTests(Group parent, String nodeName, String description) { diff --git a/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/EmbeddedProfileTests.java b/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/EmbeddedProfileTests.java new file mode 100644 index 00000000000..3af6313eff1 --- /dev/null +++ b/jdk/src/share/demo/java2d/J2DBench/src/j2dbench/tests/cmm/EmbeddedProfileTests.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +package j2dbench.tests.cmm; + +import j2dbench.Group; +import j2dbench.Option; +import j2dbench.Result; +import j2dbench.TestEnvironment; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.net.URL; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; + +/* This benchmark verifies how changes in cmm library affects image decoding */ +public class EmbeddedProfileTests extends ColorConversionTests { + + protected static Group grpRoot; + protected static Group grpOptionsRoot; + + protected static Option inputImages; + + public static void init() { + grpRoot = new Group(colorConvRoot, "embed", "Embedded Profile Tests"); + + grpOptionsRoot = new Group(grpRoot, "embedOptions", "Options"); + + inputImages = createImageList(); + + new ReadImageTest(); + } + + private static enum IccImageResource { + SMALL("images/img_icc_small.jpg", "512x512", "Small: 512x512"), + MEDIUM("images/img_icc_medium.jpg", "2048x2048", "Medium: 2048x2048"), + LARGE("images/img_icc_large.jpg", "4096x4096", "Large: 4096x4096"); + + private IccImageResource(String file, String name, String description) { + this.url = CMMTests.class.getResource(file); + this.abbrev = name; + this.description = description; + } + + public final URL url; + public final String abbrev; + public final String description; + } + + private static Option createImageList() { + IccImageResource[] images = IccImageResource.values(); + + int num = images.length; + + String[] names = new String[num]; + String[] abbrev = new String[num]; + String[] descr = new String[num]; + + for (int i = 0; i < num; i++) { + names[i] = images[i].toString(); + abbrev[i] = images[i].abbrev; + descr[i] = images[i].description; + } + + Option list = new Option.ObjectList(grpOptionsRoot, + "Images", "Input Images", + names, images, abbrev, descr, 1); + + return list; + } + + public EmbeddedProfileTests(Group parent, String nodeName, String description) { + super(parent, nodeName, description); + addDependencies(grpOptionsRoot, true); + } + + private static class Context { + URL input; + + public Context(TestEnvironment env, Result res) { + + IccImageResource icc_input = (IccImageResource) + env.getModifier(inputImages); + + input = icc_input.url; + } + } + + public Object initTest(TestEnvironment env, Result res) { + return new Context(env, res); + } + + public void cleanupTest(TestEnvironment env, Object o) { + Context ctx = (Context)o; + ctx.input = null; + } + + private static class ReadImageTest extends EmbeddedProfileTests { + public ReadImageTest() { + super(grpRoot, "embd_img_read", "ImageReader.read()"); + } + + public void runTest(Object octx, int numReps) { + final Context ctx = (Context)octx; + final URL url = ctx.input; + ImageInputStream iis = null; + ImageReader reader = null; + + try { + iis = ImageIO.createImageInputStream(url.openStream()); + reader = ImageIO.getImageReaders(iis).next(); + } catch (IOException e) { + throw new RuntimeException("Unable to run the becnhmark", e); + } + + do { + try { + reader.setInput(iis); + BufferedImage img = reader.read(0); + reader.reset(); + + iis = ImageIO.createImageInputStream(url.openStream()); + } catch (Exception e) { + e.printStackTrace(); + } + } while (--numReps >= 0); + } + } +} diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c index 7da0370baad..1340c82a822 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c @@ -117,6 +117,7 @@ static jfieldID IL_offset_fID; static jfieldID IL_nextRowOffset_fID; static jfieldID IL_width_fID; static jfieldID IL_height_fID; +static jfieldID IL_imageAtOnce_fID; static jfieldID PF_ID_fID; JavaVM *javaVM; @@ -237,7 +238,7 @@ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform * Method: loadProfile * Signature: ([B)J */ -JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfile +JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative (JNIEnv *env, jobject obj, jbyteArray data) { jbyte* dataArray; @@ -284,7 +285,7 @@ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfile * Method: freeProfile * Signature: (J)V */ -JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_freeProfile +JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative (JNIEnv *env, jobject obj, jlong id) { storeID_t sProf; @@ -369,48 +370,22 @@ static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize); static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize); static cmsBool _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size); -/* - * Class: sun_java2d_cmm_lcms_LCMS - * Method: getTagSize - * Signature: (JI)I - */ -JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagSize - (JNIEnv *env, jobject obj, jlong id, jint tagSig) -{ - storeID_t sProf; - TagSignature_t sig; - jint result = -1; - - sProf.j = id; - sig.j = tagSig; - - if (tagSig == SigHead) { - result = sizeof(cmsICCHeader); - } else { - if (cmsIsTag(sProf.pf, sig.cms)) { - result = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0); - } else { - JNU_ThrowByName(env, "java/awt/color/CMMException", - "ICC profile tag not found"); - } - } - - return result; -} /* * Class: sun_java2d_cmm_lcms_LCMS * Method: getTagData * Signature: (JI[B)V */ -JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData - (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data) +JNIEXPORT jbyteArray JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagNative + (JNIEnv *env, jobject obj, jlong id, jint tagSig) { storeID_t sProf; TagSignature_t sig; cmsInt32Number tagSize; - jbyte* dataArray; + jbyte* dataArray = NULL; + jbyteArray data = NULL; + jint bufSize; sProf.j = id; @@ -419,12 +394,14 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData if (tagSig == SigHead) { cmsBool status; - bufSize =(*env)->GetArrayLength(env, data); + // allocate java array + bufSize = sizeof(cmsICCHeader); + data = (*env)->NewByteArray(env, bufSize); - if (bufSize < sizeof(cmsICCHeader)) { - JNU_ThrowByName(env, "java/awt/color/CMMException", - "Insufficient buffer capacity"); - return; + if (data == NULL) { + JNU_ThrowByName(env, "java/awt/color/CMMException", + "Unable to allocate buffer"); + return NULL; } dataArray = (*env)->GetByteArrayElements (env, data, 0); @@ -432,7 +409,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData if (dataArray == NULL) { JNU_ThrowByName(env, "java/awt/color/CMMException", "Unable to get buffer"); - return; + return NULL; } status = _getHeaderInfo(sProf.pf, dataArray, bufSize); @@ -442,9 +419,10 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData if (!status) { JNU_ThrowByName(env, "java/awt/color/CMMException", "ICC Profile header not found"); + return NULL; } - return; + return data; } if (cmsIsTag(sProf.pf, sig.cms)) { @@ -452,16 +430,15 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData } else { JNU_ThrowByName(env, "java/awt/color/CMMException", "ICC profile tag not found"); - return; + return NULL; } - // verify data buffer capacity - bufSize = (*env)->GetArrayLength(env, data); - - if (tagSize < 0 || 0 > bufSize || tagSize > bufSize) { + // allocate java array + data = (*env)->NewByteArray(env, tagSize); + if (data == NULL) { JNU_ThrowByName(env, "java/awt/color/CMMException", - "Insufficient buffer capacity."); - return; + "Unable to allocate buffer"); + return NULL; } dataArray = (*env)->GetByteArrayElements (env, data, 0); @@ -469,7 +446,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData if (dataArray == NULL) { JNU_ThrowByName(env, "java/awt/color/CMMException", "Unable to get buffer"); - return; + return NULL; } bufSize = cmsReadRawTag(sProf.pf, sig.cms, dataArray, tagSize); @@ -479,8 +456,9 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData if (bufSize != tagSize) { JNU_ThrowByName(env, "java/awt/color/CMMException", "Can not get tag data."); + return NULL; } - return; + return data; } /* @@ -488,7 +466,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData * Method: setTagData * Signature: (JI[B)V */ -JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagData +JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data) { storeID_t sProf; @@ -586,6 +564,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert char* inputRow; char* outputRow; jobject srcData, dstData; + jboolean srcAtOnce = JNI_FALSE, dstAtOnce = JNI_FALSE; srcOffset = (*env)->GetIntField (env, src, IL_offset_fID); srcNextRowOffset = (*env)->GetIntField (env, src, IL_nextRowOffset_fID); @@ -594,6 +573,9 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert width = (*env)->GetIntField (env, src, IL_width_fID); height = (*env)->GetIntField (env, src, IL_height_fID); + srcAtOnce = (*env)->GetBooleanField(env, src, IL_imageAtOnce_fID); + dstAtOnce = (*env)->GetBooleanField(env, dst, IL_imageAtOnce_fID); + sTrans.j = (*env)->GetLongField (env, trans, Trans_ID_fID); if (sTrans.xf == NULL) { @@ -625,10 +607,14 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert inputRow = (char*)inputBuffer + srcOffset; outputRow = (char*)outputBuffer + dstOffset; - for (i = 0; i < height; i++) { - cmsDoTransform(sTrans.xf, inputRow, outputRow, width); - inputRow += srcNextRowOffset; - outputRow += dstNextRowOffset; + if (srcAtOnce && dstAtOnce) { + cmsDoTransform(sTrans.xf, inputRow, outputRow, width * height); + } else { + for (i = 0; i < height; i++) { + cmsDoTransform(sTrans.xf, inputRow, outputRow, width); + inputRow += srcNextRowOffset; + outputRow += dstNextRowOffset; + } } releaseILData(env, inputBuffer, srcDType, srcData); @@ -670,6 +656,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_initLCMS IL_width_fID = (*env)->GetFieldID (env, IL, "width", "I"); IL_height_fID = (*env)->GetFieldID (env, IL, "height", "I"); IL_offset_fID = (*env)->GetFieldID (env, IL, "offset", "I"); + IL_imageAtOnce_fID = (*env)->GetFieldID (env, IL, "imageAtOnce", "Z"); IL_nextRowOffset_fID = (*env)->GetFieldID (env, IL, "nextRowOffset", "I"); PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J"); From 7d6b4b81def031fd213fab050c8db1fe04eed29d Mon Sep 17 00:00:00 2001 From: Chris Hegarty <chegar@openjdk.org> Date: Thu, 7 Mar 2013 10:07:13 +0000 Subject: [PATCH 150/180] 6370908: Add support for HTTP_CONNECT proxy in Socket class Co-authored-by: Damjan Jovanovic <damjan.jov@gmail.com> Reviewed-by: chegar --- .../java/net/HttpConnectSocketImpl.java | 210 +++++++++++++ jdk/src/share/classes/java/net/Socket.java | 9 +- jdk/test/java/net/Socket/HttpProxy.java | 281 ++++++++++++++++++ 3 files changed, 497 insertions(+), 3 deletions(-) create mode 100644 jdk/src/share/classes/java/net/HttpConnectSocketImpl.java create mode 100644 jdk/test/java/net/Socket/HttpProxy.java diff --git a/jdk/src/share/classes/java/net/HttpConnectSocketImpl.java b/jdk/src/share/classes/java/net/HttpConnectSocketImpl.java new file mode 100644 index 00000000000..b6e70cafd94 --- /dev/null +++ b/jdk/src/share/classes/java/net/HttpConnectSocketImpl.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2010, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.net; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Basic SocketImpl that relies on the internal HTTP protocol handler + * implementation to perform the HTTP tunneling and authentication. The + * sockets impl is swapped out and replaced with the socket from the HTTP + * handler after the tunnel is successfully setup. + * + * @since 1.8 + */ + +/*package*/ class HttpConnectSocketImpl extends PlainSocketImpl { + + private static final String httpURLClazzStr = + "sun.net.www.protocol.http.HttpURLConnection"; + private static final String netClientClazzStr = "sun.net.NetworkClient"; + private static final String doTunnelingStr = "doTunneling"; + private static final Field httpField; + private static final Field serverSocketField; + private static final Method doTunneling; + + private final String server; + private InetSocketAddress external_address; + private HashMap<Integer, Object> optionsMap = new HashMap<>(); + + static { + try { + Class<?> httpClazz = Class.forName(httpURLClazzStr, true, null); + httpField = httpClazz.getDeclaredField("http"); + doTunneling = httpClazz.getDeclaredMethod(doTunnelingStr); + Class<?> netClientClazz = Class.forName(netClientClazzStr, true, null); + serverSocketField = netClientClazz.getDeclaredField("serverSocket"); + + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction<Void>() { + public Void run() { + httpField.setAccessible(true); + serverSocketField.setAccessible(true); + return null; + } + }); + } catch (ReflectiveOperationException x) { + throw new InternalError("Should not reach here", x); + } + } + + HttpConnectSocketImpl(String server, int port) { + this.server = server; + this.port = port; + } + + HttpConnectSocketImpl(Proxy proxy) { + SocketAddress a = proxy.address(); + if ( !(a instanceof InetSocketAddress) ) + throw new IllegalArgumentException("Unsupported address type"); + + InetSocketAddress ad = (InetSocketAddress) a; + server = ad.getHostString(); + port = ad.getPort(); + } + + @Override + protected void connect(SocketAddress endpoint, int timeout) + throws IOException + { + if (endpoint == null || !(endpoint instanceof InetSocketAddress)) + throw new IllegalArgumentException("Unsupported address type"); + final InetSocketAddress epoint = (InetSocketAddress)endpoint; + final String destHost = epoint.isUnresolved() ? epoint.getHostName() + : epoint.getAddress().getHostAddress(); + final int destPort = epoint.getPort(); + + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkConnect(destHost, destPort); + + // Connect to the HTTP proxy server + String urlString = "http://" + destHost + ":" + destPort; + Socket httpSocket = privilegedDoTunnel(urlString, timeout); + + // Success! + external_address = epoint; + + // close the original socket impl and release its descriptor + close(); + + // update the Sockets impl to the impl from the http Socket + AbstractPlainSocketImpl psi = (AbstractPlainSocketImpl) httpSocket.impl; + this.getSocket().impl = psi; + + // best effort is made to try and reset options previously set + Set<Map.Entry<Integer,Object>> options = optionsMap.entrySet(); + try { + for(Map.Entry<Integer,Object> entry : options) { + psi.setOption(entry.getKey(), entry.getValue()); + } + } catch (IOException x) { /* gulp! */ } + } + + @Override + public void setOption(int opt, Object val) throws SocketException { + super.setOption(opt, val); + + if (external_address != null) + return; // we're connected, just return + + // store options so that they can be re-applied to the impl after connect + optionsMap.put(opt, val); + } + + private Socket privilegedDoTunnel(final String urlString, + final int timeout) + throws IOException + { + try { + return java.security.AccessController.doPrivileged( + new java.security.PrivilegedExceptionAction<Socket>() { + public Socket run() throws IOException { + return doTunnel(urlString, timeout); + } + }); + } catch (java.security.PrivilegedActionException pae) { + throw (IOException) pae.getException(); + } + } + + private Socket doTunnel(String urlString, int connectTimeout) + throws IOException + { + Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(server, port)); + URL destURL = new URL(urlString); + HttpURLConnection conn = (HttpURLConnection) destURL.openConnection(proxy); + conn.setConnectTimeout(connectTimeout); + conn.setReadTimeout(this.timeout); + conn.connect(); + doTunneling(conn); + try { + Object httpClient = httpField.get(conn); + return (Socket) serverSocketField.get(httpClient); + } catch (IllegalAccessException x) { + throw new InternalError("Should not reach here", x); + } + } + + private void doTunneling(HttpURLConnection conn) { + try { + doTunneling.invoke(conn); + } catch (ReflectiveOperationException x) { + throw new InternalError("Should not reach here", x); + } + } + + @Override + protected InetAddress getInetAddress() { + if (external_address != null) + return external_address.getAddress(); + else + return super.getInetAddress(); + } + + @Override + protected int getPort() { + if (external_address != null) + return external_address.getPort(); + else + return super.getPort(); + } + + @Override + protected int getLocalPort() { + if (socket != null) + return super.getLocalPort(); + if (external_address != null) + return external_address.getPort(); + else + return super.getLocalPort(); + } +} diff --git a/jdk/src/share/classes/java/net/Socket.java b/jdk/src/share/classes/java/net/Socket.java index 22d4d6acd0a..d4f28e9ab6d 100644 --- a/jdk/src/share/classes/java/net/Socket.java +++ b/jdk/src/share/classes/java/net/Socket.java @@ -117,8 +117,10 @@ class Socket implements java.io.Closeable { if (proxy == null) { throw new IllegalArgumentException("Invalid Proxy"); } - Proxy p = proxy == Proxy.NO_PROXY ? Proxy.NO_PROXY : sun.net.ApplicationProxy.create(proxy); - if (p.type() == Proxy.Type.SOCKS) { + Proxy p = proxy == Proxy.NO_PROXY ? Proxy.NO_PROXY + : sun.net.ApplicationProxy.create(proxy); + Proxy.Type type = p.type(); + if (type == Proxy.Type.SOCKS || type == Proxy.Type.HTTP) { SecurityManager security = System.getSecurityManager(); InetSocketAddress epoint = (InetSocketAddress) p.address(); if (epoint.getAddress() != null) { @@ -133,7 +135,8 @@ class Socket implements java.io.Closeable { security.checkConnect(epoint.getAddress().getHostAddress(), epoint.getPort()); } - impl = new SocksSocketImpl(p); + impl = type == Proxy.Type.SOCKS ? new SocksSocketImpl(p) + : new HttpConnectSocketImpl(p); impl.setSocket(this); } else { if (p == Proxy.NO_PROXY) { diff --git a/jdk/test/java/net/Socket/HttpProxy.java b/jdk/test/java/net/Socket/HttpProxy.java new file mode 100644 index 00000000000..92f14d2d32a --- /dev/null +++ b/jdk/test/java/net/Socket/HttpProxy.java @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2010, 2013, 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 6370908 + * @summary Add support for HTTP_CONNECT proxy in Socket class + */ + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import static java.lang.System.out; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ServerSocket; +import java.net.Socket; +import sun.net.www.MessageHeader; + +public class HttpProxy { + final String proxyHost; + final int proxyPort; + static final int SO_TIMEOUT = 15000; + + public static void main(String[] args) throws Exception { + String host; + int port; + if (args.length == 0) { + // Start internal proxy + ConnectProxyTunnelServer proxy = new ConnectProxyTunnelServer(); + proxy.start(); + host = "localhost"; + port = proxy.getLocalPort(); + out.println("Running with internal proxy: " + host + ":" + port); + } else if (args.length == 2) { + host = args[0]; + port = Integer.valueOf(args[1]); + out.println("Running against specified proxy server: " + host + ":" + port); + } else { + System.err.println("Usage: java HttpProxy [<proxy host> <proxy port>]"); + return; + } + + HttpProxy p = new HttpProxy(host, port); + p.test(); + } + + public HttpProxy(String proxyHost, int proxyPort) { + this.proxyHost = proxyHost; + this.proxyPort = proxyPort; + } + + void test() throws Exception { + InetSocketAddress proxyAddress = new InetSocketAddress(proxyHost, proxyPort); + Proxy httpProxy = new Proxy(Proxy.Type.HTTP, proxyAddress); + + try (ServerSocket ss = new ServerSocket(0); + Socket sock = new Socket(httpProxy)) { + sock.setSoTimeout(SO_TIMEOUT); + sock.setTcpNoDelay(false); + + InetSocketAddress externalAddress = + new InetSocketAddress(InetAddress.getLocalHost(), ss.getLocalPort()); + + out.println("Trying to connect to server socket on " + externalAddress); + sock.connect(externalAddress); + try (Socket externalSock = ss.accept()) { + // perform some simple checks + check(sock.isBound(), "Socket is not bound"); + check(sock.isConnected(), "Socket is not connected"); + check(!sock.isClosed(), "Socket should not be closed"); + check(sock.getSoTimeout() == SO_TIMEOUT, + "Socket should have a previously set timeout"); + check(sock.getTcpNoDelay() == false, "NODELAY should be false"); + + simpleDataExchange(sock, externalSock); + } + } + } + + static void check(boolean condition, String message) { + if (!condition) out.println(message); + } + + static Exception unexpected(Exception e) { + out.println("Unexcepted Exception: " + e); + e.printStackTrace(); + return e; + } + + // performs a simple exchange of data between the two sockets + // and throws an exception if there is any problem. + void simpleDataExchange(Socket s1, Socket s2) throws Exception { + try (final InputStream i1 = s1.getInputStream(); + final InputStream i2 = s2.getInputStream(); + final OutputStream o1 = s1.getOutputStream(); + final OutputStream o2 = s2.getOutputStream()) { + startSimpleWriter("simpleWriter1", o1, 100); + startSimpleWriter("simpleWriter2", o2, 200); + simpleRead(i2, 100); + simpleRead(i1, 200); + } + } + + void startSimpleWriter(String threadName, final OutputStream os, final int start) { + (new Thread(new Runnable() { + public void run() { + try { simpleWrite(os, start); } + catch (Exception e) {unexpected(e); } + }}, threadName)).start(); + } + + void simpleWrite(OutputStream os, int start) throws Exception { + byte b[] = new byte[2]; + for (int i=start; i<start+100; i++) { + b[0] = (byte) (i / 256); + b[1] = (byte) (i % 256); + os.write(b); + } + } + + void simpleRead(InputStream is, int start) throws Exception { + byte b[] = new byte [2]; + for (int i=start; i<start+100; i++) { + int x = is.read(b); + if (x == 1) + x += is.read(b,1,1); + if (x!=2) + throw new Exception("read error"); + int r = bytes(b[0], b[1]); + if (r != i) + throw new Exception("read " + r + " expected " +i); + } + } + + int bytes(byte b1, byte b2) { + int i1 = (int)b1 & 0xFF; + int i2 = (int)b2 & 0xFF; + return i1 * 256 + i2; + } + + static class ConnectProxyTunnelServer extends Thread { + + private final ServerSocket ss; + + public ConnectProxyTunnelServer() throws IOException { + ss = new ServerSocket(0); + } + + @Override + public void run() { + try (Socket clientSocket = ss.accept()) { + processRequest(clientSocket); + } catch (Exception e) { + out.println("Proxy Failed: " + e); + e.printStackTrace(); + } finally { + try { ss.close(); } catch (IOException x) { unexpected(x); } + } + } + + /** + * Returns the port on which the proxy is accepting connections. + */ + public int getLocalPort() { + return ss.getLocalPort(); + } + + /* + * Processes the CONNECT request + */ + private void processRequest(Socket clientSocket) throws Exception { + MessageHeader mheader = new MessageHeader(clientSocket.getInputStream()); + String statusLine = mheader.getValue(0); + + if (!statusLine.startsWith("CONNECT")) { + out.println("proxy server: processes only " + + "CONNECT method requests, recieved: " + + statusLine); + return; + } + + // retrieve the host and port info from the status-line + InetSocketAddress serverAddr = getConnectInfo(statusLine); + + //open socket to the server + try (Socket serverSocket = new Socket(serverAddr.getAddress(), + serverAddr.getPort())) { + Forwarder clientFW = new Forwarder(clientSocket.getInputStream(), + serverSocket.getOutputStream()); + Thread clientForwarderThread = new Thread(clientFW, "ClientForwarder"); + clientForwarderThread.start(); + send200(clientSocket); + Forwarder serverFW = new Forwarder(serverSocket.getInputStream(), + clientSocket.getOutputStream()); + serverFW.run(); + clientForwarderThread.join(); + } + } + + private void send200(Socket clientSocket) throws IOException { + OutputStream out = clientSocket.getOutputStream(); + PrintWriter pout = new PrintWriter(out); + + pout.println("HTTP/1.1 200 OK"); + pout.println(); + pout.flush(); + } + + /* + * This method retrieves the hostname and port of the tunnel destination + * from the request line. + * @param connectStr + * of the form: <i>CONNECT server-name:server-port HTTP/1.x</i> + */ + static InetSocketAddress getConnectInfo(String connectStr) + throws Exception + { + try { + int starti = connectStr.indexOf(' '); + int endi = connectStr.lastIndexOf(' '); + String connectInfo = connectStr.substring(starti+1, endi).trim(); + // retrieve server name and port + endi = connectInfo.indexOf(':'); + String name = connectInfo.substring(0, endi); + int port = Integer.parseInt(connectInfo.substring(endi+1)); + return new InetSocketAddress(name, port); + } catch (Exception e) { + out.println("Proxy recieved a request: " + connectStr); + throw unexpected(e); + } + } + } + + /* Reads from the given InputStream and writes to the given OutputStream */ + static class Forwarder implements Runnable + { + private final InputStream in; + private final OutputStream os; + + Forwarder(InputStream in, OutputStream os) { + this.in = in; + this.os = os; + } + + @Override + public void run() { + try { + byte[] ba = new byte[1024]; + int count; + while ((count = in.read(ba)) != -1) { + os.write(ba, 0, count); + } + } catch (IOException e) { + unexpected(e); + } + } + } +} From 3baff284ba4c5ef69118024dab4f8ee1c88c07e3 Mon Sep 17 00:00:00 2001 From: Tao Mao <tao.mao@oracle.com> Date: Thu, 7 Mar 2013 10:44:04 -0800 Subject: [PATCH 151/180] 8008368: Deprecate MaxGCMinorPauseMillis Deprecate MaxGCMinorPauseMillis and emit a warning if set by users Reviewed-by: brutisso, johnc --- hotspot/src/share/vm/runtime/arguments.cpp | 8 ++++++++ hotspot/src/share/vm/runtime/arguments.hpp | 1 + 2 files changed, 9 insertions(+) diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index db634c621b3..d6e4c308444 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1813,6 +1813,13 @@ void Arguments::check_deprecated_gcs() { } } +void Arguments::check_deprecated_gc_flags() { + if (FLAG_IS_CMDLINE(MaxGCMinorPauseMillis)) { + warning("Using MaxGCMinorPauseMillis as minor pause goal is deprecated" + "and will likely be removed in future release"); + } +} + // Check stack pages settings bool Arguments::check_stack_pages() { @@ -3292,6 +3299,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { set_g1_gc_flags(); } check_deprecated_gcs(); + check_deprecated_gc_flags(); #else // INCLUDE_ALL_GCS assert(verify_serial_gc_flags(), "SerialGC unset"); #endif // INCLUDE_ALL_GCS diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index c116e2028bb..26c029744da 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -414,6 +414,7 @@ class Arguments : AllStatic { // Check for consistency in the selection of the garbage collector. static bool check_gc_consistency(); static void check_deprecated_gcs(); + static void check_deprecated_gc_flags(); // Check consistecy or otherwise of VM argument settings static bool check_vm_args_consistency(); // Check stack pages settings From 4cdcd6dc138f4a951f40a784b226b4e260aff1ea Mon Sep 17 00:00:00 2001 From: Zhengyu Gu <zgu@openjdk.org> Date: Thu, 7 Mar 2013 14:06:44 -0500 Subject: [PATCH 152/180] 8008257: NMT: assert(new_rec->is_allocation_record()) failed when running with shared memory option Corrected virtual memory recording and tagging code when large pages are used Reviewed-by: coleenp, ccheung --- hotspot/src/os/bsd/vm/os_bsd.cpp | 15 +++++++++++++- hotspot/src/os/linux/vm/os_linux.cpp | 14 ++++++++++++- hotspot/src/os/solaris/vm/os_solaris.cpp | 14 ++++++++++++- hotspot/src/os/windows/vm/os_windows.cpp | 26 +++++++++++++++++++++++- 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index fdf5772a764..b8d976dd486 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -57,6 +57,7 @@ #include "runtime/threadCritical.hpp" #include "runtime/timer.hpp" #include "services/attachListener.hpp" +#include "services/memTracker.hpp" #include "services/runtimeService.hpp" #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" @@ -2275,13 +2276,25 @@ char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) { return NULL; } + // The memory is committed + address pc = CALLER_PC; + MemTracker::record_virtual_memory_reserve((address)addr, bytes, pc); + MemTracker::record_virtual_memory_commit((address)addr, bytes, pc); + return addr; } bool os::release_memory_special(char* base, size_t bytes) { // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); - return rslt == 0; + if (rslt == 0) { + MemTracker::record_virtual_memory_uncommit((address)base, bytes); + MemTracker::record_virtual_memory_release((address)base, bytes); + return true; + } else { + return false; + } + } size_t os::large_page_size() { diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 6dfe962b1c5..59cb59d6805 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -58,6 +58,7 @@ #include "runtime/threadCritical.hpp" #include "runtime/timer.hpp" #include "services/attachListener.hpp" +#include "services/memTracker.hpp" #include "services/runtimeService.hpp" #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" @@ -3212,13 +3213,24 @@ char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) { numa_make_global(addr, bytes); } + // The memory is committed + address pc = CALLER_PC; + MemTracker::record_virtual_memory_reserve((address)addr, bytes, pc); + MemTracker::record_virtual_memory_commit((address)addr, bytes, pc); + return addr; } bool os::release_memory_special(char* base, size_t bytes) { // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); - return rslt == 0; + if (rslt == 0) { + MemTracker::record_virtual_memory_uncommit((address)base, bytes); + MemTracker::record_virtual_memory_release((address)base, bytes); + return true; + } else { + return false; + } } size_t os::large_page_size() { diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index a80a0ea4590..ce24b906534 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -3420,13 +3420,25 @@ char* os::reserve_memory_special(size_t size, char* addr, bool exec) { if ((retAddr != NULL) && UseNUMAInterleaving) { numa_make_global(retAddr, size); } + + // The memory is committed + address pc = CALLER_PC; + MemTracker::record_virtual_memory_reserve((address)retAddr, size, pc); + MemTracker::record_virtual_memory_commit((address)retAddr, size, pc); + return retAddr; } bool os::release_memory_special(char* base, size_t bytes) { // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); - return rslt == 0; + if (rslt == 0) { + MemTracker::record_virtual_memory_uncommit((address)base, bytes); + MemTracker::record_virtual_memory_release((address)base, bytes); + return true; + } else { + return false; + } } size_t os::large_page_size() { diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index b1556bf6491..4a99a1b3975 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -60,6 +60,7 @@ #include "runtime/threadCritical.hpp" #include "runtime/timer.hpp" #include "services/attachListener.hpp" +#include "services/memTracker.hpp" #include "services/runtimeService.hpp" #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" @@ -2836,7 +2837,7 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, PAGE_READWRITE); // If reservation failed, return NULL if (p_buf == NULL) return NULL; - + MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC); os::release_memory(p_buf, bytes + chunk_size); // we still need to round up to a page boundary (in case we are using large pages) @@ -2898,6 +2899,11 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, if (next_alloc_addr > p_buf) { // Some memory was committed so release it. size_t bytes_to_release = bytes - bytes_remaining; + // NMT has yet to record any individual blocks, so it + // need to create a dummy 'reserve' record to match + // the release. + MemTracker::record_virtual_memory_reserve((address)p_buf, + bytes_to_release, CALLER_PC); os::release_memory(p_buf, bytes_to_release); } #ifdef ASSERT @@ -2909,10 +2915,19 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, #endif return NULL; } + bytes_remaining -= bytes_to_rq; next_alloc_addr += bytes_to_rq; count++; } + // Although the memory is allocated individually, it is returned as one. + // NMT records it as one block. + address pc = CALLER_PC; + MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, pc); + if ((flags & MEM_COMMIT) != 0) { + MemTracker::record_virtual_memory_commit((address)p_buf, bytes, pc); + } + // made it this far, success return p_buf; } @@ -3099,11 +3114,20 @@ char* os::reserve_memory_special(size_t bytes, char* addr, bool exec) { // normal policy just allocate it all at once DWORD flag = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES; char * res = (char *)VirtualAlloc(NULL, bytes, flag, prot); + if (res != NULL) { + address pc = CALLER_PC; + MemTracker::record_virtual_memory_reserve((address)res, bytes, pc); + MemTracker::record_virtual_memory_commit((address)res, bytes, pc); + } + return res; } } bool os::release_memory_special(char* base, size_t bytes) { + assert(base != NULL, "Sanity check"); + // Memory allocated via reserve_memory_special() is committed + MemTracker::record_virtual_memory_uncommit((address)base, bytes); return release_memory(base, bytes); } From 9849742625be80c3f11e0b34b4717c9045e72f4a Mon Sep 17 00:00:00 2001 From: Alan Bateman <alanb@openjdk.org> Date: Fri, 8 Mar 2013 12:03:26 +0000 Subject: [PATCH 153/180] 8006000: TEST_BUG: java/lang/invoke/lambda/LambdaAccessControlTest.java fails intermittently Reviewed-by: chegar --- jdk/test/java/lang/invoke/lambda/LUtils.java | 171 ++++++++++++++++++ .../LambdaAccessControlDoPrivilegedTest.java | 147 +-------------- .../lambda/LambdaAccessControlTest.java | 2 +- 3 files changed, 173 insertions(+), 147 deletions(-) create mode 100644 jdk/test/java/lang/invoke/lambda/LUtils.java diff --git a/jdk/test/java/lang/invoke/lambda/LUtils.java b/jdk/test/java/lang/invoke/lambda/LUtils.java new file mode 100644 index 00000000000..a7b013e3a6c --- /dev/null +++ b/jdk/test/java/lang/invoke/lambda/LUtils.java @@ -0,0 +1,171 @@ +/* + * 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. + */ + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/* + * support infrastructure to invoke a java class from the command line + */ +class LUtils { + static final sun.tools.jar.Main jarTool = + new sun.tools.jar.Main(System.out, System.err, "jar-tool"); + static final com.sun.tools.javac.Main javac = + new com.sun.tools.javac.Main(); + static final File cwd = new File(".").getAbsoluteFile(); + static final String JAVAHOME = System.getProperty("java.home"); + static final boolean isWindows = + System.getProperty("os.name", "unknown").startsWith("Windows"); + //static final boolean isSDK = JAVAHOME.endsWith("jre"); + static final File JAVA_BIN_FILE = new File(JAVAHOME, "bin"); + static final File JAVA_CMD = new File(JAVA_BIN_FILE, + isWindows ? "java.exe" : "java"); + + protected LUtils() { + } + + public static void compile(String... args) { + if (javac.compile(args) != 0) { + throw new RuntimeException("compilation fails"); + } + } + + static void createFile(File outFile, List<String> content) { + try { + Files.write(outFile.getAbsoluteFile().toPath(), content, + Charset.defaultCharset()); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + static File getClassFile(File javaFile) { + return javaFile.getName().endsWith(".java") + ? new File(javaFile.getName().replace(".java", ".class")) + : null; + } + + static String getSimpleName(File inFile) { + String fname = inFile.getName(); + return fname.substring(0, fname.indexOf(".")); + } + + static TestResult doExec(String... cmds) { + return doExec(null, null, cmds); + } + + /* + * A method which executes a java cmd and returns the results in a container + */ + static TestResult doExec(Map<String, String> envToSet, + java.util.Set<String> envToRemove, String... cmds) { + String cmdStr = ""; + for (String x : cmds) { + cmdStr = cmdStr.concat(x + " "); + } + ProcessBuilder pb = new ProcessBuilder(cmds); + Map<String, String> env = pb.environment(); + if (envToRemove != null) { + for (String key : envToRemove) { + env.remove(key); + } + } + if (envToSet != null) { + env.putAll(envToSet); + } + BufferedReader rdr = null; + try { + List<String> outputList = new ArrayList<>(); + pb.redirectErrorStream(true); + Process p = pb.start(); + rdr = new BufferedReader(new InputStreamReader(p.getInputStream())); + String in = rdr.readLine(); + while (in != null) { + outputList.add(in); + in = rdr.readLine(); + } + p.waitFor(); + p.destroy(); + + return new TestResult(cmdStr, p.exitValue(), outputList, + env, new Throwable("current stack of the test")); + } catch (Exception ex) { + ex.printStackTrace(); + throw new RuntimeException(ex.getMessage()); + } + } + + static class TestResult { + String cmd; + int exitValue; + List<String> testOutput; + Map<String, String> env; + Throwable t; + + public TestResult(String str, int rv, List<String> oList, + Map<String, String> env, Throwable t) { + cmd = str; + exitValue = rv; + testOutput = oList; + this.env = env; + this.t = t; + } + + void assertZero(String message) { + if (exitValue != 0) { + System.err.println(this); + throw new RuntimeException(message); + } + } + + @Override + public String toString() { + StringWriter sw = new StringWriter(); + PrintWriter status = new PrintWriter(sw); + status.println("Cmd: " + cmd); + status.println("Return code: " + exitValue); + status.println("Environment variable:"); + for (String x : env.keySet()) { + status.println("\t" + x + "=" + env.get(x)); + } + status.println("Output:"); + for (String x : testOutput) { + status.println("\t" + x); + } + status.println("Exception:"); + status.println(t.getMessage()); + t.printStackTrace(status); + + return sw.getBuffer().toString(); + } + } +} diff --git a/jdk/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java b/jdk/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java index 8c3d1c5ed5b..e9e5cbcd1c2 100644 --- a/jdk/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java +++ b/jdk/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java @@ -26,20 +26,12 @@ * @bug 8003881 * @summary tests DoPrivileged action (implemented as lambda expressions) by * inserting them into the BootClassPath. - * @compile -XDignore.symbol.file LambdaAccessControlDoPrivilegedTest.java + * @compile -XDignore.symbol.file LambdaAccessControlDoPrivilegedTest.java LUtils.java * @run main/othervm LambdaAccessControlDoPrivilegedTest */ -import java.io.BufferedReader; import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.nio.charset.Charset; -import java.nio.file.Files; import java.util.ArrayList; import java.util.List; -import java.util.Map; public class LambdaAccessControlDoPrivilegedTest extends LUtils { public static void main(String... args) { @@ -87,140 +79,3 @@ public class LambdaAccessControlDoPrivilegedTest extends LUtils { jarFile.delete(); } } - -/* - * support infrastructure to invoke a java class from the command line - */ -class LUtils { - static final sun.tools.jar.Main jarTool = - new sun.tools.jar.Main(System.out, System.err, "jar-tool"); - static final com.sun.tools.javac.Main javac = - new com.sun.tools.javac.Main(); - static final File cwd = new File(".").getAbsoluteFile(); - static final String JAVAHOME = System.getProperty("java.home"); - static final boolean isWindows = - System.getProperty("os.name", "unknown").startsWith("Windows"); - //static final boolean isSDK = JAVAHOME.endsWith("jre"); - static final File JAVA_BIN_FILE = new File(JAVAHOME, "bin"); - static final File JAVA_CMD = new File(JAVA_BIN_FILE, - isWindows ? "java.exe" : "java"); - - protected LUtils() { - } - - public static void compile(String... args) { - if (javac.compile(args) != 0) { - throw new RuntimeException("compilation fails"); - } - } - - static void createFile(File outFile, List<String> content) { - try { - Files.write(outFile.getAbsoluteFile().toPath(), content, - Charset.defaultCharset()); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - - static File getClassFile(File javaFile) { - return javaFile.getName().endsWith(".java") - ? new File(javaFile.getName().replace(".java", ".class")) - : null; - } - - static String getSimpleName(File inFile) { - String fname = inFile.getName(); - return fname.substring(0, fname.indexOf(".")); - } - - static TestResult doExec(String... cmds) { - return doExec(null, null, cmds); - } - - /* - * A method which executes a java cmd and returns the results in a container - */ - static TestResult doExec(Map<String, String> envToSet, - java.util.Set<String> envToRemove, String... cmds) { - String cmdStr = ""; - for (String x : cmds) { - cmdStr = cmdStr.concat(x + " "); - } - ProcessBuilder pb = new ProcessBuilder(cmds); - Map<String, String> env = pb.environment(); - if (envToRemove != null) { - for (String key : envToRemove) { - env.remove(key); - } - } - if (envToSet != null) { - env.putAll(envToSet); - } - BufferedReader rdr = null; - try { - List<String> outputList = new ArrayList<>(); - pb.redirectErrorStream(true); - Process p = pb.start(); - rdr = new BufferedReader(new InputStreamReader(p.getInputStream())); - String in = rdr.readLine(); - while (in != null) { - outputList.add(in); - in = rdr.readLine(); - } - p.waitFor(); - p.destroy(); - - return new TestResult(cmdStr, p.exitValue(), outputList, - env, new Throwable("current stack of the test")); - } catch (Exception ex) { - ex.printStackTrace(); - throw new RuntimeException(ex.getMessage()); - } - } - - static class TestResult { - String cmd; - int exitValue; - List<String> testOutput; - Map<String, String> env; - Throwable t; - - public TestResult(String str, int rv, List<String> oList, - Map<String, String> env, Throwable t) { - cmd = str; - exitValue = rv; - testOutput = oList; - this.env = env; - this.t = t; - } - - void assertZero(String message) { - if (exitValue != 0) { - System.err.println(this); - throw new RuntimeException(message); - } - } - - @Override - public String toString() { - StringWriter sw = new StringWriter(); - PrintWriter status = new PrintWriter(sw); - status.println("Cmd: " + cmd); - status.println("Return code: " + exitValue); - status.println("Environment variable:"); - for (String x : env.keySet()) { - status.println("\t" + x + "=" + env.get(x)); - } - status.println("Output:"); - for (String x : testOutput) { - status.println("\t" + x); - } - status.println("Exception:"); - status.println(t.getMessage()); - t.printStackTrace(status); - - return sw.getBuffer().toString(); - } - } -} diff --git a/jdk/test/java/lang/invoke/lambda/LambdaAccessControlTest.java b/jdk/test/java/lang/invoke/lambda/LambdaAccessControlTest.java index 361a4cffcce..6ca9fb0beb2 100644 --- a/jdk/test/java/lang/invoke/lambda/LambdaAccessControlTest.java +++ b/jdk/test/java/lang/invoke/lambda/LambdaAccessControlTest.java @@ -25,7 +25,7 @@ * @test * @bug 8003881 * @summary tests Lambda expression with a a security manager at top level - * @compile -XDignore.symbol.file LambdaAccessControlTest.java + * @compile -XDignore.symbol.file LambdaAccessControlTest.java LUtils.java * * @run main/othervm LambdaAccessControlTest */ From 5d0afe6210f05bfb5b92a925fe5b26b0bcddd60d Mon Sep 17 00:00:00 2001 From: Alejandro Murillo <amurillo@openjdk.org> Date: Fri, 8 Mar 2013 08:22:18 -0800 Subject: [PATCH 154/180] 8009688: new hotspot build - hs25-b23 Reviewed-by: jcoomes --- hotspot/make/hotspot_version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index b52c3c52dfb..28b5a9a1114 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2013 HS_MAJOR_VER=25 HS_MINOR_VER=0 -HS_BUILD_NUMBER=22 +HS_BUILD_NUMBER=23 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 From addd95f165c2db5c2aedc8d7ed27fcd73d9e3a01 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore <coleenp@openjdk.org> Date: Fri, 8 Mar 2013 11:47:57 -0500 Subject: [PATCH 155/180] 8003553: NPG: metaspace objects should be zeroed in constructors Zero metadata in constructors, not in allocation (and some in constructors) Reviewed-by: jmasa, sspitsyn --- hotspot/src/share/vm/interpreter/rewriter.cpp | 6 +- hotspot/src/share/vm/memory/metablock.cpp | 7 +- hotspot/src/share/vm/memory/metaspace.cpp | 3 +- hotspot/src/share/vm/oops/constMethod.cpp | 6 ++ hotspot/src/share/vm/oops/cpCache.cpp | 12 ++- hotspot/src/share/vm/oops/cpCache.hpp | 14 ++- hotspot/src/share/vm/oops/instanceKlass.cpp | 98 ++++++++++--------- hotspot/src/share/vm/oops/instanceKlass.hpp | 4 +- hotspot/src/share/vm/oops/klass.cpp | 18 ++-- hotspot/src/share/vm/oops/klass.hpp | 5 - hotspot/src/share/vm/oops/method.cpp | 8 +- hotspot/src/share/vm/oops/methodData.cpp | 26 ++--- hotspot/src/share/vm/runtime/vmStructs.cpp | 1 - 13 files changed, 111 insertions(+), 97 deletions(-) diff --git a/hotspot/src/share/vm/interpreter/rewriter.cpp b/hotspot/src/share/vm/interpreter/rewriter.cpp index 0b5d2513925..249fca33afe 100644 --- a/hotspot/src/share/vm/interpreter/rewriter.cpp +++ b/hotspot/src/share/vm/interpreter/rewriter.cpp @@ -84,15 +84,13 @@ void Rewriter::make_constant_pool_cache(TRAPS) { const int length = _cp_cache_map.length(); ClassLoaderData* loader_data = _pool->pool_holder()->class_loader_data(); ConstantPoolCache* cache = - ConstantPoolCache::allocate(loader_data, length, CHECK); + ConstantPoolCache::allocate(loader_data, length, _cp_cache_map, + _invokedynamic_references_map, CHECK); // initialize object cache in constant pool _pool->initialize_resolved_references(loader_data, _resolved_references_map, _resolved_reference_limit, CHECK); - - No_Safepoint_Verifier nsv; - cache->initialize(_cp_cache_map, _invokedynamic_references_map); _pool->set_cache(cache); cache->set_constant_pool(_pool()); } diff --git a/hotspot/src/share/vm/memory/metablock.cpp b/hotspot/src/share/vm/memory/metablock.cpp index 8aa6a9f8372..7ffaec57f71 100644 --- a/hotspot/src/share/vm/memory/metablock.cpp +++ b/hotspot/src/share/vm/memory/metablock.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -65,10 +65,9 @@ Metablock* Metablock::initialize(MetaWord* p, size_t word_size) { } Metablock* result = (Metablock*) p; - - // Clear the memory - Copy::fill_to_aligned_words((HeapWord*)result, word_size); #ifdef ASSERT + // Add just to catch missing initializations + Copy::fill_to_words((HeapWord*) result, word_size, 0xf1f1f1f1); result->set_word_size(word_size); #endif return result; diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index b0891150d9c..7853b3d51f1 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, 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 @@ -52,7 +52,6 @@ const bool metaspace_slow_verify = false; const uint metadata_deallocate_a_lot_block = 10; const uint metadata_deallocate_a_lock_chunk = 3; size_t const allocation_from_dictionary_limit = 64 * K; -const size_t metadata_deallocate = 0xf5f5f5f5; MetaWord* last_allocated = 0; diff --git a/hotspot/src/share/vm/oops/constMethod.cpp b/hotspot/src/share/vm/oops/constMethod.cpp index 35b7be24fc9..ad02e5df35b 100644 --- a/hotspot/src/share/vm/oops/constMethod.cpp +++ b/hotspot/src/share/vm/oops/constMethod.cpp @@ -58,6 +58,12 @@ ConstMethod::ConstMethod(int byte_code_size, set_inlined_tables_length(sizes); set_method_type(method_type); assert(this->size() == size, "wrong size for object"); + set_name_index(0); + set_signature_index(0); + set_constants(NULL); + set_max_stack(0); + set_max_locals(0); + set_method_idnum(0); } diff --git a/hotspot/src/share/vm/oops/cpCache.cpp b/hotspot/src/share/vm/oops/cpCache.cpp index 11ab856e1ca..c2175ca81ff 100644 --- a/hotspot/src/share/vm/oops/cpCache.cpp +++ b/hotspot/src/share/vm/oops/cpCache.cpp @@ -44,6 +44,8 @@ void ConstantPoolCacheEntry::initialize_entry(int index) { assert(0 < index && index < 0x10000, "sanity check"); _indices = index; + _f1 = NULL; + _f2 = _flags = 0; assert(constant_pool_index() == index, ""); } @@ -533,13 +535,17 @@ void ConstantPoolCacheEntry::verify(outputStream* st) const { // Implementation of ConstantPoolCache -ConstantPoolCache* ConstantPoolCache::allocate(ClassLoaderData* loader_data, int length, TRAPS) { +ConstantPoolCache* ConstantPoolCache::allocate(ClassLoaderData* loader_data, + int length, + const intStack& index_map, + const intStack& invokedynamic_map, TRAPS) { int size = ConstantPoolCache::size(length); - return new (loader_data, size, false, THREAD) ConstantPoolCache(length); + return new (loader_data, size, false, THREAD) ConstantPoolCache(length, index_map, invokedynamic_map); } -void ConstantPoolCache::initialize(intArray& inverse_index_map, intArray& invokedynamic_references_map) { +void ConstantPoolCache::initialize(const intArray& inverse_index_map, + const intArray& invokedynamic_references_map) { assert(inverse_index_map.length() == length(), "inverse index map must have same length as cache"); for (int i = 0; i < length(); i++) { ConstantPoolCacheEntry* e = entry_at(i); diff --git a/hotspot/src/share/vm/oops/cpCache.hpp b/hotspot/src/share/vm/oops/cpCache.hpp index c1e058d81db..27ca7980c07 100644 --- a/hotspot/src/share/vm/oops/cpCache.hpp +++ b/hotspot/src/share/vm/oops/cpCache.hpp @@ -377,14 +377,21 @@ class ConstantPoolCache: public MetaspaceObj { debug_only(friend class ClassVerifier;) // Constructor - ConstantPoolCache(int length) : _length(length), _constant_pool(NULL) { + ConstantPoolCache(int length, const intStack& inverse_index_map, + const intStack& invokedynamic_references_map) : + _length(length), _constant_pool(NULL) { + initialize(inverse_index_map, invokedynamic_references_map); for (int i = 0; i < length; i++) { assert(entry_at(i)->is_f1_null(), "Failed to clear?"); } } + // Initialization + void initialize(const intArray& inverse_index_map, const intArray& invokedynamic_references_map); public: - static ConstantPoolCache* allocate(ClassLoaderData* loader_data, int length, TRAPS); + static ConstantPoolCache* allocate(ClassLoaderData* loader_data, int length, + const intStack& inverse_index_map, + const intStack& invokedynamic_references_map, TRAPS); bool is_constantPoolCache() const { return true; } int length() const { return _length; } @@ -405,9 +412,6 @@ class ConstantPoolCache: public MetaspaceObj { friend class ConstantPoolCacheEntry; public: - // Initialization - void initialize(intArray& inverse_index_map, intArray& invokedynamic_references_map); - // Accessors void set_constant_pool(ConstantPool* pool) { _constant_pool = pool; } ConstantPool* constant_pool() const { return _constant_pool; } diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index f492b895605..1b46824aac6 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -220,63 +220,71 @@ InstanceKlass::InstanceKlass(int vtable_len, bool is_anonymous) { No_Safepoint_Verifier no_safepoint; // until k becomes parsable - int size = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size, - access_flags.is_interface(), is_anonymous); + int iksize = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size, + access_flags.is_interface(), is_anonymous); // The sizes of these these three variables are used for determining the // size of the instanceKlassOop. It is critical that these are set to the right // sizes before the first GC, i.e., when we allocate the mirror. - this->set_vtable_length(vtable_len); - this->set_itable_length(itable_len); - this->set_static_field_size(static_field_size); - this->set_nonstatic_oop_map_size(nonstatic_oop_map_size); - this->set_access_flags(access_flags); - this->set_is_anonymous(is_anonymous); - assert(this->size() == size, "wrong size for object"); + set_vtable_length(vtable_len); + set_itable_length(itable_len); + set_static_field_size(static_field_size); + set_nonstatic_oop_map_size(nonstatic_oop_map_size); + set_access_flags(access_flags); + _misc_flags = 0; // initialize to zero + set_is_anonymous(is_anonymous); + assert(size() == iksize, "wrong size for object"); - this->set_array_klasses(NULL); - this->set_methods(NULL); - this->set_method_ordering(NULL); - this->set_local_interfaces(NULL); - this->set_transitive_interfaces(NULL); - this->init_implementor(); - this->set_fields(NULL, 0); - this->set_constants(NULL); - this->set_class_loader_data(NULL); - this->set_protection_domain(NULL); - this->set_signers(NULL); - this->set_source_file_name(NULL); - this->set_source_debug_extension(NULL, 0); - this->set_array_name(NULL); - this->set_inner_classes(NULL); - this->set_static_oop_field_count(0); - this->set_nonstatic_field_size(0); - this->set_is_marked_dependent(false); - this->set_init_state(InstanceKlass::allocated); - this->set_init_thread(NULL); - this->set_init_lock(NULL); - this->set_reference_type(rt); - this->set_oop_map_cache(NULL); - this->set_jni_ids(NULL); - this->set_osr_nmethods_head(NULL); - this->set_breakpoints(NULL); - this->init_previous_versions(); - this->set_generic_signature(NULL); - this->release_set_methods_jmethod_ids(NULL); - this->release_set_methods_cached_itable_indices(NULL); - this->set_annotations(NULL); - this->set_jvmti_cached_class_field_map(NULL); - this->set_initial_method_idnum(0); + set_array_klasses(NULL); + set_methods(NULL); + set_method_ordering(NULL); + set_local_interfaces(NULL); + set_transitive_interfaces(NULL); + init_implementor(); + set_fields(NULL, 0); + set_constants(NULL); + set_class_loader_data(NULL); + set_protection_domain(NULL); + set_signers(NULL); + set_source_file_name(NULL); + set_source_debug_extension(NULL, 0); + set_array_name(NULL); + set_inner_classes(NULL); + set_static_oop_field_count(0); + set_nonstatic_field_size(0); + set_is_marked_dependent(false); + set_init_state(InstanceKlass::allocated); + set_init_thread(NULL); + set_init_lock(NULL); + set_reference_type(rt); + set_oop_map_cache(NULL); + set_jni_ids(NULL); + set_osr_nmethods_head(NULL); + set_breakpoints(NULL); + init_previous_versions(); + set_generic_signature(NULL); + release_set_methods_jmethod_ids(NULL); + release_set_methods_cached_itable_indices(NULL); + set_annotations(NULL); + set_jvmti_cached_class_field_map(NULL); + set_initial_method_idnum(0); + _dependencies = NULL; + set_jvmti_cached_class_field_map(NULL); + set_cached_class_file(NULL, 0); + set_initial_method_idnum(0); + set_minor_version(0); + set_major_version(0); + NOT_PRODUCT(_verify_count = 0;) // initialize the non-header words to zero intptr_t* p = (intptr_t*)this; - for (int index = InstanceKlass::header_size(); index < size; index++) { + for (int index = InstanceKlass::header_size(); index < iksize; index++) { p[index] = NULL_WORD; } // Set temporary value until parseClassFile updates it with the real instance // size. - this->set_layout_helper(Klass::instance_layout_helper(0, true)); + set_layout_helper(Klass::instance_layout_helper(0, true)); } @@ -2781,7 +2789,7 @@ void InstanceKlass::print_on(outputStream* st) const { st->print(BULLET"protection domain: "); ((InstanceKlass*)this)->protection_domain()->print_value_on(st); st->cr(); st->print(BULLET"host class: "); host_klass()->print_value_on_maybe_null(st); st->cr(); st->print(BULLET"signers: "); signers()->print_value_on(st); st->cr(); - st->print(BULLET"init_lock: "); ((oop)init_lock())->print_value_on(st); st->cr(); + st->print(BULLET"init_lock: "); ((oop)_init_lock)->print_value_on(st); st->cr(); if (source_file_name() != NULL) { st->print(BULLET"source file: "); source_file_name()->print_value_on(st); diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index 600cb56465c..c4cf8bbc051 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -269,6 +269,8 @@ class InstanceKlass: public Klass { JvmtiCachedClassFieldMap* _jvmti_cached_class_field_map; // JVMTI: used during heap iteration + NOT_PRODUCT(int _verify_count;) // to avoid redundant verifies + // Method array. Array<Method*>* _methods; // Interface (Klass*s) this class declares locally to implement. @@ -586,7 +588,7 @@ class InstanceKlass: public Klass { // symbol unloading support (refcount already added) Symbol* array_name() { return _array_name; } - void set_array_name(Symbol* name) { assert(_array_name == NULL, "name already created"); _array_name = name; } + void set_array_name(Symbol* name) { assert(_array_name == NULL || name == NULL, "name already created"); _array_name = name; } // nonstatic oop-map blocks static int nonstatic_oop_map_size(unsigned int oop_map_count) { diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp index 341f60c3fe8..edfda97a539 100644 --- a/hotspot/src/share/vm/oops/klass.cpp +++ b/hotspot/src/share/vm/oops/klass.cpp @@ -146,16 +146,16 @@ void* Klass::operator new(size_t size, ClassLoaderData* loader_data, size_t word Klass::Klass() { Klass* k = this; - { // Preinitialize supertype information. - // A later call to initialize_supers() may update these settings: - set_super(NULL); - for (juint i = 0; i < Klass::primary_super_limit(); i++) { - _primary_supers[i] = NULL; - } - set_secondary_supers(NULL); - _primary_supers[0] = k; - set_super_check_offset(in_bytes(primary_supers_offset())); + // Preinitialize supertype information. + // A later call to initialize_supers() may update these settings: + set_super(NULL); + for (juint i = 0; i < Klass::primary_super_limit(); i++) { + _primary_supers[i] = NULL; } + set_secondary_supers(NULL); + set_secondary_super_cache(NULL); + _primary_supers[0] = k; + set_super_check_offset(in_bytes(primary_supers_offset())); set_java_mirror(NULL); set_modifier_flags(0); diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index 803f4da2737..d2a41914653 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -79,7 +79,6 @@ // [last_biased_lock_bulk_revocation_time] (64 bits) // [prototype_header] // [biased_lock_revocation_count] -// [verify_count ] - not in product // [alloc_count ] // [_modified_oops] // [_accumulated_modified_oops] @@ -172,10 +171,6 @@ class Klass : public Metadata { markOop _prototype_header; // Used when biased locking is both enabled and disabled for this type jint _biased_lock_revocation_count; -#ifndef PRODUCT - int _verify_count; // to avoid redundant verifies -#endif - juint _alloc_count; // allocation profiling support TRACE_DEFINE_KLASS_TRACE_ID; diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index bb9a5115693..da19ccaad31 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -77,20 +77,14 @@ Method* Method::allocate(ClassLoaderData* loader_data, return new (loader_data, size, false, THREAD) Method(cm, access_flags, size); } -Method::Method(ConstMethod* xconst, - AccessFlags access_flags, int size) { +Method::Method(ConstMethod* xconst, AccessFlags access_flags, int size) { No_Safepoint_Verifier no_safepoint; set_constMethod(xconst); set_access_flags(access_flags); set_method_size(size); - set_name_index(0); - set_signature_index(0); #ifdef CC_INTERP set_result_index(T_VOID); #endif - set_constants(NULL); - set_max_stack(0); - set_max_locals(0); set_intrinsic_id(vmIntrinsics::_none); set_jfr_towrite(false); set_method_data(NULL); diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp index c7a200f9e47..c9687fb32b6 100644 --- a/hotspot/src/share/vm/oops/methodData.cpp +++ b/hotspot/src/share/vm/oops/methodData.cpp @@ -652,23 +652,25 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) { // Set the method back-pointer. _method = method(); - if (TieredCompilation) { - _invocation_counter.init(); - _backedge_counter.init(); - _invocation_counter_start = 0; - _backedge_counter_start = 0; - _num_loops = 0; - _num_blocks = 0; - _highest_comp_level = 0; - _highest_osr_comp_level = 0; - _would_profile = true; - } + _invocation_counter.init(); + _backedge_counter.init(); + _invocation_counter_start = 0; + _backedge_counter_start = 0; + _num_loops = 0; + _num_blocks = 0; + _highest_comp_level = 0; + _highest_osr_comp_level = 0; + _would_profile = true; set_creation_mileage(mileage_of(method())); // Initialize flags and trap history. _nof_decompiles = 0; _nof_overflow_recompiles = 0; _nof_overflow_traps = 0; + _eflags = 0; + _arg_local = 0; + _arg_stack = 0; + _arg_returned = 0; assert(sizeof(_trap_hist) % sizeof(HeapWord) == 0, "align"); Copy::zero_to_words((HeapWord*) &_trap_hist, sizeof(_trap_hist) / sizeof(HeapWord)); @@ -677,6 +679,7 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) { // corresponding data cells. int data_size = 0; int empty_bc_count = 0; // number of bytecodes lacking data + _data[0] = 0; // apparently not set below. BytecodeStream stream(method); Bytecodes::Code c; while ((c = stream.next()) >= 0) { @@ -710,6 +713,7 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) { post_initialize(&stream); set_size(object_size); + } // Get a measure of how much mileage the method has on it. diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 158060b6958..b3e445f3d9e 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -336,7 +336,6 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary; nonstatic_field(Klass, _access_flags, AccessFlags) \ nonstatic_field(Klass, _subklass, Klass*) \ nonstatic_field(Klass, _next_sibling, Klass*) \ - nonproduct_nonstatic_field(Klass, _verify_count, int) \ nonstatic_field(Klass, _alloc_count, juint) \ nonstatic_field(MethodData, _size, int) \ nonstatic_field(MethodData, _method, Method*) \ From 1430ceb19da7c3040ac2270951f9da5e105b0661 Mon Sep 17 00:00:00 2001 From: Alan Bateman <alanb@openjdk.org> Date: Fri, 8 Mar 2013 19:51:09 +0000 Subject: [PATCH 156/180] 8009645: ClassFileTransformer hooks in ClassLoader no longer required Reviewed-by: mchung, iris --- .../share/classes/java/lang/ClassLoader.java | 61 +------------------ .../sun/misc/ClassFileTransformer.java | 50 ++++++--------- 2 files changed, 20 insertions(+), 91 deletions(-) diff --git a/jdk/src/share/classes/java/lang/ClassLoader.java b/jdk/src/share/classes/java/lang/ClassLoader.java index e62c69a1ccd..a1e18ffe62d 100644 --- a/jdk/src/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/share/classes/java/lang/ClassLoader.java @@ -51,7 +51,6 @@ import java.util.Vector; import java.util.Hashtable; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; -import sun.misc.ClassFileTransformer; import sun.misc.CompoundEnumeration; import sun.misc.Resource; import sun.misc.URLClassPath; @@ -669,41 +668,6 @@ public abstract class ClassLoader { return source; } - private Class<?> defineTransformedClass(String name, byte[] b, int off, int len, - ProtectionDomain pd, - ClassFormatError cfe, String source) - throws ClassFormatError - { - // Class format error - try to transform the bytecode and - // define the class again - // - ClassFileTransformer[] transformers = - ClassFileTransformer.getTransformers(); - Class<?> c = null; - - if (transformers != null) { - for (ClassFileTransformer transformer : transformers) { - try { - // Transform byte code using transformer - byte[] tb = transformer.transform(b, off, len); - c = defineClass1(name, tb, 0, tb.length, - pd, source); - break; - } catch (ClassFormatError cfe2) { - // If ClassFormatError occurs, try next transformer - } - } - } - - // Rethrow original ClassFormatError if unable to transform - // bytecode to well-formed - // - if (c == null) - throw cfe; - - return c; - } - private void postDefineClass(Class<?> c, ProtectionDomain pd) { if (pd.getCodeSource() != null) { @@ -783,17 +747,8 @@ public abstract class ClassLoader { throws ClassFormatError { protectionDomain = preDefineClass(name, protectionDomain); - - Class<?> c = null; String source = defineClassSourceLocation(protectionDomain); - - try { - c = defineClass1(name, b, off, len, protectionDomain, source); - } catch (ClassFormatError cfe) { - c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, - source); - } - + Class<?> c = defineClass1(name, b, off, len, protectionDomain, source); postDefineClass(c, protectionDomain); return c; } @@ -881,20 +836,8 @@ public abstract class ClassLoader { } protectionDomain = preDefineClass(name, protectionDomain); - - Class<?> c = null; String source = defineClassSourceLocation(protectionDomain); - - try { - c = defineClass2(name, b, b.position(), len, protectionDomain, - source); - } catch (ClassFormatError cfe) { - byte[] tb = new byte[len]; - b.get(tb); // get bytes out of byte buffer. - c = defineTransformedClass(name, tb, 0, len, protectionDomain, cfe, - source); - } - + Class<?> c = defineClass2(name, b, b.position(), len, protectionDomain, source); postDefineClass(c, protectionDomain); return c; } diff --git a/jdk/src/share/classes/sun/misc/ClassFileTransformer.java b/jdk/src/share/classes/sun/misc/ClassFileTransformer.java index 61524ba3b30..669b9e8aac8 100644 --- a/jdk/src/share/classes/sun/misc/ClassFileTransformer.java +++ b/jdk/src/share/classes/sun/misc/ClassFileTransformer.java @@ -25,43 +25,31 @@ package sun.misc; import java.util.ArrayList; +import java.util.List; /** - * This is an abstract base class which is called by java.lang.ClassLoader - * when ClassFormatError is thrown inside defineClass(). - * - * The purpose of this class is to allow applications (e.g. Java Plug-in) - * to have a chance to transform the byte code from one form to another - * if necessary. - * - * One application of this class is used by Java Plug-in to transform - * malformed JDK 1.1 class file into a well-formed Java 2 class file - * on-the-fly, so JDK 1.1 applets with malformed class file in the - * Internet may run in Java 2 after transformation. + * This is an abstract base class originally intended to be called by + * {@code java.lang.ClassLoader} when {@code ClassFormatError} is + * thrown inside {@code defineClass()}. It is no longer hooked into + * {@code ClassLoader} and will be removed in a future release. * * @author Stanley Man-Kit Ho */ -public abstract class ClassFileTransformer -{ - // Singleton of ClassFileTransformer - // - private static ArrayList<ClassFileTransformer> transformerList +@Deprecated +public abstract class ClassFileTransformer { + + private static final List<ClassFileTransformer> transformers = new ArrayList<ClassFileTransformer>(); - private static ClassFileTransformer[] transformers - = new ClassFileTransformer[0]; /** * Add the class file transformer object. * * @param t Class file transformer instance */ - public static void add(ClassFileTransformer t) - { - synchronized(transformerList) - { - transformerList.add(t); - transformers = transformerList.toArray(new ClassFileTransformer[0]); + public static void add(ClassFileTransformer t) { + synchronized (transformers) { + transformers.add(t); } } @@ -70,13 +58,11 @@ public abstract class ClassFileTransformer * * @return ClassFileTransformer object array */ - public static ClassFileTransformer[] getTransformers() - { - // transformers is not intended to be changed frequently, - // so it is okay to not put synchronized block here - // to speed up performance. - // - return transformers; + public static ClassFileTransformer[] getTransformers() { + synchronized (transformers) { + ClassFileTransformer[] result = new ClassFileTransformer[transformers.size()]; + return transformers.toArray(result); + } } @@ -89,5 +75,5 @@ public abstract class ClassFileTransformer * @return Transformed byte array */ public abstract byte[] transform(byte[] b, int off, int len) - throws ClassFormatError; + throws ClassFormatError; } From 9db647931860a3f80cb9f705ba75b52d37152802 Mon Sep 17 00:00:00 2001 From: Henry Jen <henry.jen@oracle.com> Date: Fri, 8 Mar 2013 15:45:06 -0800 Subject: [PATCH 157/180] 8001667: Comparator combinators and extension methods Reviewed-by: mduigou, briangoetz --- jdk/make/java/java/FILES_java.gmk | 1 + .../share/classes/java/util/Collections.java | 2 +- .../share/classes/java/util/Comparator.java | 94 +++++ .../share/classes/java/util/Comparators.java | 279 ++++++++++++++ .../java/util/Collections/ReverseOrder.java | 37 +- jdk/test/java/util/ComparatorsTest.java | 353 ++++++++++++++++++ 6 files changed, 763 insertions(+), 3 deletions(-) create mode 100644 jdk/src/share/classes/java/util/Comparators.java create mode 100644 jdk/test/java/util/ComparatorsTest.java diff --git a/jdk/make/java/java/FILES_java.gmk b/jdk/make/java/java/FILES_java.gmk index 8c2f80c5248..189b9fcb7c2 100644 --- a/jdk/make/java/java/FILES_java.gmk +++ b/jdk/make/java/java/FILES_java.gmk @@ -257,6 +257,7 @@ JAVA_JAVA_java = \ sun/util/calendar/ZoneInfoFile.java \ java/util/TooManyListenersException.java \ java/util/Comparator.java \ + java/util/Comparators.java \ java/util/Collections.java \ java/util/Iterator.java \ java/util/ListIterator.java \ diff --git a/jdk/src/share/classes/java/util/Collections.java b/jdk/src/share/classes/java/util/Collections.java index 58eae6f9509..b6bac484dac 100644 --- a/jdk/src/share/classes/java/util/Collections.java +++ b/jdk/src/share/classes/java/util/Collections.java @@ -3759,7 +3759,7 @@ public class Collections { return c2.compareTo(c1); } - private Object readResolve() { return reverseOrder(); } + private Object readResolve() { return Collections.reverseOrder(); } } /** diff --git a/jdk/src/share/classes/java/util/Comparator.java b/jdk/src/share/classes/java/util/Comparator.java index 35ead373b82..017c2e78e2c 100644 --- a/jdk/src/share/classes/java/util/Comparator.java +++ b/jdk/src/share/classes/java/util/Comparator.java @@ -25,6 +25,11 @@ package java.util; +import java.util.function.Function; +import java.util.function.ToIntFunction; +import java.util.function.ToLongFunction; +import java.util.function.ToDoubleFunction; + /** * A comparison function, which imposes a <i>total ordering</i> on some * collection of objects. Comparators can be passed to a sort method (such @@ -165,4 +170,93 @@ public interface Comparator<T> { * @see Object#hashCode() */ boolean equals(Object obj); + + /** + * Returns a comparator that imposes the reverse ordering of this + * comparator. + * + * @return A comparator that imposes the reverse ordering of this + * comparator. + * @since 1.8 + */ + default Comparator<T> reverseOrder() { + return Collections.reverseOrder(this); + } + + /** + * Constructs a lexicographic order comparator with another comparator. + * For example, a {@code Comparator<Person> byLastName} can be composed + * with another {@code Comparator<Person> byFirstName}, then {@code + * byLastName.thenComparing(byFirstName)} creates a {@code + * Comparator<Person>} which sorts by last name, and for equal last names + * sorts by first name. + * + * @param other the other comparator used when equals on this. + * @throws NullPointerException if the argument is null. + * @since 1.8 + */ + default Comparator<T> thenComparing(Comparator<? super T> other) { + return Comparators.compose(this, other); + } + + /** + * Constructs a lexicographic order comparator with a function that + * extracts a {@code Comparable} key. This default implementation calls + * {@code thenComparing(this, Comparators.comparing(keyExtractor))}. + * + * @param <U> the {@link Comparable} type for comparison + * @param keyExtractor the function used to extract the {@link Comparable} sort key + * @throws NullPointerException if the argument is null. + * @see Comparators#comparing(Function) + * @see #thenComparing(Comparator) + * @since 1.8 + */ + default <U extends Comparable<? super U>> Comparator<T> thenComparing(Function<? super T, ? extends U> keyExtractor) { + return thenComparing(Comparators.comparing(keyExtractor)); + } + + /** + * Constructs a lexicographic order comparator with a function that + * extracts a {@code int} value. This default implementation calls {@code + * thenComparing(this, Comparators.comparing(keyExtractor))}. + * + * @param keyExtractor the function used to extract the integer value + * @throws NullPointerException if the argument is null. + * @see Comparators#comparing(ToIntFunction) + * @see #thenComparing(Comparator) + * @since 1.8 + */ + default Comparator<T> thenComparing(ToIntFunction<? super T> keyExtractor) { + return thenComparing(Comparators.comparing(keyExtractor)); + } + + /** + * Constructs a lexicographic order comparator with a function that + * extracts a {@code long} value. This default implementation calls + * {@code thenComparing(this, Comparators.comparing(keyExtractor))}. + * + * @param keyExtractor the function used to extract the long value + * @throws NullPointerException if the argument is null. + * @see Comparators#comparing(ToLongFunction) + * @see #thenComparing(Comparator) + * @since 1.8 + */ + default Comparator<T> thenComparing(ToLongFunction<? super T> keyExtractor) { + return thenComparing(Comparators.comparing(keyExtractor)); + } + + /** + * Constructs a lexicographic order comparator with a function that + * extracts a {@code double} value. This default implementation calls + * {@code thenComparing(this, Comparators.comparing(keyExtractor))}. + * + * @param keyExtractor the function used to extract the double value + * @throws NullPointerException if the argument is null. + * @see Comparators#comparing(ToDoubleFunction) + * @see #thenComparing(Comparator) + * @since 1.8 + */ + default Comparator<T> thenComparing(ToDoubleFunction<? super T> keyExtractor) { + return thenComparing(Comparators.comparing(keyExtractor)); + } } diff --git a/jdk/src/share/classes/java/util/Comparators.java b/jdk/src/share/classes/java/util/Comparators.java new file mode 100644 index 00000000000..75821339b49 --- /dev/null +++ b/jdk/src/share/classes/java/util/Comparators.java @@ -0,0 +1,279 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util; + +import java.io.Serializable; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.ToDoubleFunction; +import java.util.function.ToIntFunction; +import java.util.function.ToLongFunction; + +/** + * This class consists of {@code static} utility methods for comparators. Mostly + * factory method that returns a {@link Comparator}. + * + * <p> Unless otherwise noted, passing a {@code null} argument to a method in + * this class will cause a {@link NullPointerException} to be thrown. + * + * @see Comparator + * @since 1.8 + */ +public class Comparators { + private Comparators() { + throw new AssertionError("no instances"); + } + + /** + * Compares {@link Comparable} objects in natural order. + * + * @see Comparable + */ + private enum NaturalOrderComparator implements Comparator<Comparable<Object>> { + INSTANCE; + + @Override + public int compare(Comparable<Object> c1, Comparable<Object> c2) { + return c1.compareTo(c2); + } + } + + /** + * Returns a comparator that imposes the reverse of the <em>natural + * ordering</em>. + * + * <p>The returned comparator is serializable. + * + * @param <T> {@link Comparable} type + * + * @return A comparator that imposes the reverse of the <i>natural + * ordering</i> on a collection of objects that implement + * the {@link Comparable} interface. + * @see Comparable + */ + public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() { + return Collections.reverseOrder(); + } + + /** + * Returns a comparator that imposes the reverse ordering of the specified + * {@link Comparator}. + * + * <p>The returned comparator is serializable (assuming the specified + * comparator is also serializable). + * + * @param <T> the element type to be compared + * @param cmp a comparator whose ordering is to be reversed by the returned + * comparator + * @return A comparator that imposes the reverse ordering of the + * specified comparator. + */ + public static <T> Comparator<T> reverseOrder(Comparator<T> cmp) { + Objects.requireNonNull(cmp); + return Collections.reverseOrder(cmp); + } + + /** + * Gets a comparator compares {@link Comparable} type in natural order. + * + * @param <T> {@link Comparable} type + */ + public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() { + return (Comparator<T>) NaturalOrderComparator.INSTANCE; + } + + /** + * Gets a comparator compares {@link Map.Entry} in natural order on key. + * + * @param <K> {@link Comparable} key type + * @param <V> value type + */ + public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> naturalOrderKeys() { + return (Comparator<Map.Entry<K, V>> & Serializable) + (c1, c2) -> c1.getKey().compareTo(c2.getKey()); + } + + /** + * Gets a comparator compares {@link Map.Entry} in natural order on value. + * + * @param <K> key type + * @param <V> {@link Comparable} value type + */ + public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> naturalOrderValues() { + return (Comparator<Map.Entry<K, V>> & Serializable) + (c1, c2) -> c1.getValue().compareTo(c2.getValue()); + } + + /** + * Gets a comparator compares {@link Map.Entry} by key using the given + * {@link Comparator}. + * + * <p>The returned comparator is serializable assuming the specified + * comparators are also serializable. + * + * @param <K> key type + * @param <V> value type + * @param cmp the key {@link Comparator} + */ + public static <K, V> Comparator<Map.Entry<K, V>> byKey(Comparator<? super K> cmp) { + Objects.requireNonNull(cmp); + return (Comparator<Map.Entry<K, V>> & Serializable) + (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey()); + } + + /** + * Gets a comparator compares {@link Map.Entry} by value using the given + * {@link Comparator}. + * + * @param <K> key type + * @param <V> value type + * @param cmp the value {@link Comparator} + */ + public static <K, V> Comparator<Map.Entry<K, V>> byValue(Comparator<? super V> cmp) { + Objects.requireNonNull(cmp); + return (Comparator<Map.Entry<K, V>> & Serializable) + (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue()); + } + + /** + * Accepts a function that extracts a {@link java.lang.Comparable + * Comparable} sort key from a type {@code T}, and returns a {@code + * Comparator<T>} that compares by that sort key. For example, if a class + * {@code Person} has a {@code String}-valued getter {@code getLastName}, + * then {@code comparing(Person::getLastName)} would return a {@code + * Comparator<Person>} that compares {@code Person} objects by their last + * name. + * + * @param <T> the original element type + * @param <U> the {@link Comparable} type for comparison + * @param keyExtractor the function used to extract the {@link Comparable} sort key + */ + public static <T, U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T, ? extends U> keyExtractor) { + Objects.requireNonNull(keyExtractor); + return (Comparator<T> & Serializable) + (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2)); + } + + /** + * Accepts a function that extracts an {@code int} value from a type {@code + * T}, and returns a {@code Comparator<T>} that compares by that value. + * + * <p>The returned comparator is serializable assuming the specified + * function is also serializable. + * + * @see #comparing(Function) + * @param <T> the original element type + * @param keyExtractor the function used to extract the integer value + */ + public static <T> Comparator<T> comparing(ToIntFunction<? super T> keyExtractor) { + Objects.requireNonNull(keyExtractor); + return (Comparator<T> & Serializable) + (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2)); + } + + /** + * Accepts a function that extracts a {@code long} value from a type {@code + * T}, and returns a {@code Comparator<T>} that compares by that value. + * + * <p>The returned comparator is serializable assuming the specified + * function is also serializable. + * + * @see #comparing(Function) + * @param <T> the original element type + * @param keyExtractor the function used to extract the long value + */ + public static <T> Comparator<T> comparing(ToLongFunction<? super T> keyExtractor) { + Objects.requireNonNull(keyExtractor); + return (Comparator<T> & Serializable) + (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2)); + } + + /** + * Accepts a function that extracts a {@code double} value from a type + * {@code T}, and returns a {@code Comparator<T>} that compares by that + * value. + * + * <p>The returned comparator is serializable assuming the specified + * function is also serializable. + * + * @see #comparing(Function) + * @param <T> the original element type + * @param keyExtractor the function used to extract the double value + */ + public static<T> Comparator<T> comparing(ToDoubleFunction<? super T> keyExtractor) { + Objects.requireNonNull(keyExtractor); + return (Comparator<T> & Serializable) + (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2)); + } + + /** + * Constructs a lexicographic order from two {@link Comparator}s. For + * example, if you have comparators {@code byLastName} and {@code + * byFirstName}, each of type {@code Comparator<Person>}, then {@code + * compose(byLastName, byFirstName)} creates a {@code Comparator<Person>} + * which sorts by last name, and for equal last names sorts by first name. + * + * <p>The returned comparator is serializable assuming the specified + * comparators are also serializable. + * + * @param <T> the element type to be compared + * @param first the first comparator + * @param second the secondary comparator used when equals on the first + */ + public static<T> Comparator<T> compose(Comparator<? super T> first, Comparator<? super T> second) { + Objects.requireNonNull(first); + Objects.requireNonNull(second); + return (Comparator<T> & Serializable) (c1, c2) -> { + int res = first.compare(c1, c2); + return (res != 0) ? res : second.compare(c1, c2); + }; + } + + /** + * Constructs a {@link BinaryOperator} which returns the lesser of two elements + * according to the specified {@code Comparator} + * + * @param comparator A {@code Comparator} for comparing the two values + * @param <T> the type of the elements to be compared + * @return a {@code BinaryOperator} which returns the lesser of its operands, + * according to the supplied {@code Comparator} + */ + public static<T> BinaryOperator<T> lesserOf(Comparator<? super T> comparator) { + return (a, b) -> comparator.compare(a, b) <= 0 ? a : b; + } + + /** + * Constructs a {@link BinaryOperator} which returns the greater of two elements + * according to the specified {@code Comparator} + * + * @param comparator A {@code Comparator} for comparing the two values + * @param <T> the type of the elements to be compared + * @return a {@code BinaryOperator} which returns the greater of its operands, + * according to the supplied {@code Comparator} + */ + public static<T> BinaryOperator<T> greaterOf(Comparator<? super T> comparator) { + return (a, b) -> comparator.compare(a, b) >= 0 ? a : b; + } +} diff --git a/jdk/test/java/util/Collections/ReverseOrder.java b/jdk/test/java/util/Collections/ReverseOrder.java index d4fed080783..9831b57c5a5 100644 --- a/jdk/test/java/util/Collections/ReverseOrder.java +++ b/jdk/test/java/util/Collections/ReverseOrder.java @@ -23,23 +23,56 @@ /* * @test - * @bug 4593209 + * @bug 4593209 8001667 * @summary Reverse comparator was subtly broken * @author Josh bloch */ import java.util.*; +import java.io.*; public class ReverseOrder { + static byte[] serialBytes(Object o) { + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + oos.writeObject(o); + oos.flush(); + oos.close(); + return bos.toByteArray(); + } catch (Throwable t) { + throw new Error(t); + } + } + + @SuppressWarnings("unchecked") + static <T> T serialClone(T o) { + try { + ObjectInputStream ois = new ObjectInputStream + (new ByteArrayInputStream(serialBytes(o))); + T clone = (T) ois.readObject(); + return clone; + } catch (Throwable t) { + throw new Error(t); + } + } + public static void main(String[] args) throws Exception { Foo[] a = { new Foo(2), new Foo(3), new Foo(1) }; List list = Arrays.asList(a); - Collections.sort(list, Collections.reverseOrder()); + Comparator cmp = Collections.reverseOrder(); + Collections.sort(list, cmp); Foo[] golden = { new Foo(3), new Foo(2), new Foo(1) }; List goldenList = Arrays.asList(golden); if (!list.equals(goldenList)) throw new Exception(list.toString()); + + Comparator clone = serialClone(cmp); + List list2 = Arrays.asList(a); + Collections.sort(list2, clone); + if (!list2.equals(goldenList)) + throw new Exception(list.toString()); } } diff --git a/jdk/test/java/util/ComparatorsTest.java b/jdk/test/java/util/ComparatorsTest.java new file mode 100644 index 00000000000..1640c2d657a --- /dev/null +++ b/jdk/test/java/util/ComparatorsTest.java @@ -0,0 +1,353 @@ +/* + * 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 8001667 + * @run testng ComparatorsTest + */ + +import java.util.Comparator; +import java.util.Comparators; +import java.util.AbstractMap; +import java.util.Map; +import org.testng.annotations.Test; + +import java.util.function.Function; +import java.util.function.ToIntFunction; +import java.util.function.ToLongFunction; +import java.util.function.ToDoubleFunction; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertSame; + +/** + * Unit tests for helper methods in Comparators + */ +@Test(groups = "unit") +public class ComparatorsTest { + private static class Thing { + public final int intField; + public final long longField; + public final double doubleField; + public final String stringField; + + private Thing(int intField, long longField, double doubleField, String stringField) { + this.intField = intField; + this.longField = longField; + this.doubleField = doubleField; + this.stringField = stringField; + } + + public int getIntField() { + return intField; + } + + public long getLongField() { + return longField; + } + + public double getDoubleField() { + return doubleField; + } + + public String getStringField() { + return stringField; + } + } + + private final int[] intValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 }; + private final long[] longValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 }; + private final double[] doubleValues = { -2, -2, -1, -1, 0, 0, 1, 1, 2, 2 }; + private final String[] stringValues = { "a", "a", "b", "b", "c", "c", "d", "d", "e", "e" }; + private final int[] comparisons = { 0, -1, 0, -1, 0, -1, 0, -1, 0 }; + + private<T> void assertComparisons(T[] things, Comparator<T> comp, int[] comparisons) { + for (int i=0; i<comparisons.length; i++) { + assertEquals(comparisons.length + 1, things.length); + assertEquals(comparisons[i], comp.compare(things[i], things[i+1])); + assertEquals(-comparisons[i], comp.compare(things[i+1], things[i])); + } + } + + public void testIntComparator() { + Thing[] things = new Thing[intValues.length]; + for (int i=0; i<intValues.length; i++) + things[i] = new Thing(intValues[i], 0L, 0.0, null); + Comparator<Thing> comp = Comparators.comparing(new ToIntFunction<ComparatorsTest.Thing>() { + @Override + public int applyAsInt(Thing thing) { + return thing.getIntField(); + } + }); + + assertComparisons(things, comp, comparisons); + } + + public void testLongComparator() { + Thing[] things = new Thing[longValues.length]; + for (int i=0; i<longValues.length; i++) + things[i] = new Thing(0, longValues[i], 0.0, null); + Comparator<Thing> comp = Comparators.comparing(new ToLongFunction<ComparatorsTest.Thing>() { + @Override + public long applyAsLong(Thing thing) { + return thing.getLongField(); + } + }); + + assertComparisons(things, comp, comparisons); + } + + public void testDoubleComparator() { + Thing[] things = new Thing[doubleValues.length]; + for (int i=0; i<doubleValues.length; i++) + things[i] = new Thing(0, 0L, doubleValues[i], null); + Comparator<Thing> comp = Comparators.comparing(new ToDoubleFunction<ComparatorsTest.Thing>() { + @Override + public double applyAsDouble(Thing thing) { + return thing.getDoubleField(); + } + }); + + assertComparisons(things, comp, comparisons); + } + + public void testComparing() { + Thing[] things = new Thing[doubleValues.length]; + for (int i=0; i<doubleValues.length; i++) + things[i] = new Thing(0, 0L, 0.0, stringValues[i]); + Comparator<Thing> comp = Comparators.comparing(new Function<Thing, String>() { + @Override + public String apply(Thing thing) { + return thing.getStringField(); + } + }); + + assertComparisons(things, comp, comparisons); + } + + public void testNaturalOrderComparator() { + Comparator<String> comp = Comparators.naturalOrder(); + + assertComparisons(stringValues, comp, comparisons); + } + + public void testReverseComparator() { + Comparator<String> cmpr = Comparators.reverseOrder(); + Comparator<String> cmp = cmpr.reverseOrder(); + + assertEquals(cmp.reverseOrder(), cmpr); + assertEquals(0, cmp.compare("a", "a")); + assertEquals(0, cmpr.compare("a", "a")); + assertTrue(cmp.compare("a", "b") < 0); + assertTrue(cmpr.compare("a", "b") > 0); + assertTrue(cmp.compare("b", "a") > 0); + assertTrue(cmpr.compare("b", "a") < 0); + } + + public void testReverseComparator2() { + Comparator<String> cmp = (s1, s2) -> s1.length() - s2.length(); + Comparator<String> cmpr = cmp.reverseOrder(); + + assertEquals(cmpr.reverseOrder(), cmp); + assertEquals(0, cmp.compare("abc", "def")); + assertEquals(0, cmpr.compare("abc", "def")); + assertTrue(cmp.compare("abcd", "def") > 0); + assertTrue(cmpr.compare("abcd", "def") < 0); + assertTrue(cmp.compare("abc", "defg") < 0); + assertTrue(cmpr.compare("abc", "defg") > 0); + } + + @Test(expectedExceptions=NullPointerException.class) + public void testReverseComparatorNPE() { + Comparator<String> cmp = Comparators.reverseOrder(null); + } + + public void testComposeComparator() { + // Longer string in front + Comparator<String> first = (s1, s2) -> s2.length() - s1.length(); + Comparator<String> second = Comparators.naturalOrder(); + Comparator<String> composed = Comparators.compose(first, second); + + assertTrue(composed.compare("abcdefg", "abcdef") < 0); + assertTrue(composed.compare("abcdef", "abcdefg") > 0); + assertTrue(composed.compare("abcdef", "abcdef") == 0); + assertTrue(composed.compare("abcdef", "ghijkl") < 0); + assertTrue(composed.compare("ghijkl", "abcdefg") > 0); + } + + private <K, V> void assertPairComparison(K k1, V v1, K k2, V v2, + Comparator<Map.Entry<K, V>> ck, + Comparator<Map.Entry<K, V>> cv) { + final Map.Entry<K, V> p11 = new AbstractMap.SimpleImmutableEntry<>(k1, v1); + final Map.Entry<K, V> p12 = new AbstractMap.SimpleImmutableEntry<>(k1, v2); + final Map.Entry<K, V> p21 = new AbstractMap.SimpleImmutableEntry<>(k2, v1); + final Map.Entry<K, V> p22 = new AbstractMap.SimpleImmutableEntry<>(k2, v2); + + assertTrue(ck.compare(p11, p11) == 0); + assertTrue(ck.compare(p12, p11) == 0); + assertTrue(ck.compare(p11, p12) == 0); + assertTrue(ck.compare(p12, p22) < 0); + assertTrue(ck.compare(p12, p21) < 0); + assertTrue(ck.compare(p21, p11) > 0); + assertTrue(ck.compare(p21, p12) > 0); + + assertTrue(cv.compare(p11, p11) == 0); + assertTrue(cv.compare(p12, p11) > 0); + assertTrue(cv.compare(p11, p12) < 0); + assertTrue(cv.compare(p12, p22) == 0); + assertTrue(cv.compare(p12, p21) > 0); + assertTrue(cv.compare(p21, p11) == 0); + assertTrue(cv.compare(p21, p12) < 0); + + Comparator<Map.Entry<K, V>> cmp = Comparators.compose(ck, cv); + assertTrue(cmp.compare(p11, p11) == 0); + assertTrue(cmp.compare(p12, p11) > 0); + assertTrue(cmp.compare(p11, p12) < 0); + assertTrue(cmp.compare(p12, p22) < 0); + assertTrue(cmp.compare(p12, p21) < 0); + assertTrue(cmp.compare(p21, p11) > 0); + assertTrue(cmp.compare(p21, p12) > 0); + + cmp = Comparators.compose(cv, ck); + assertTrue(cmp.compare(p11, p11) == 0); + assertTrue(cmp.compare(p12, p11) > 0); + assertTrue(cmp.compare(p11, p12) < 0); + assertTrue(cmp.compare(p12, p22) < 0); + assertTrue(cmp.compare(p12, p21) > 0); + assertTrue(cmp.compare(p21, p11) > 0); + assertTrue(cmp.compare(p21, p12) < 0); + } + + public void testKVComparatorable() { + assertPairComparison(1, "ABC", 2, "XYZ", + Comparators.<Integer, String>naturalOrderKeys(), + Comparators.<Integer, String>naturalOrderValues()); + } + + private static class People { + final String firstName; + final String lastName; + final int age; + + People(String first, String last, int age) { + firstName = first; + lastName = last; + this.age = age; + } + + String getFirstName() { return firstName; } + String getLastName() { return lastName; } + int getAge() { return age; } + long getAgeAsLong() { return (long) age; }; + double getAgeAsDouble() { return (double) age; }; + } + + private final People people[] = { + new People("John", "Doe", 34), + new People("Mary", "Doe", 30), + new People("Maria", "Doe", 14), + new People("Jonah", "Doe", 10), + new People("John", "Cook", 54), + new People("Mary", "Cook", 50), + }; + + public void testKVComparators() { + // Comparator<People> cmp = Comparators.naturalOrder(); // Should fail to compiler as People is not comparable + // We can use simple comparator, but those have been tested above. + // Thus choose to do compose for some level of interation. + Comparator<People> cmp1 = Comparators.comparing((Function<People, String>) People::getFirstName); + Comparator<People> cmp2 = Comparators.comparing((Function<People, String>) People::getLastName); + Comparator<People> cmp = Comparators.compose(cmp1, cmp2); + + assertPairComparison(people[0], people[0], people[1], people[1], + Comparators.<People, People>byKey(cmp), + Comparators.<People, People>byValue(cmp)); + + } + + private <T> void assertComparison(Comparator<T> cmp, T less, T greater) { + assertTrue(cmp.compare(less, greater) < 0, "less"); + assertTrue(cmp.compare(less, less) == 0, "equal"); + assertTrue(cmp.compare(greater, less) > 0, "greater"); + } + + public void testComparatorDefaultMethods() { + Comparator<People> cmp = Comparators.comparing((Function<People, String>) People::getFirstName); + Comparator<People> cmp2 = Comparators.comparing((Function<People, String>) People::getLastName); + // reverseOrder + assertComparison(cmp.reverseOrder(), people[1], people[0]); + // thenComparing(Comparator) + assertComparison(cmp.thenComparing(cmp2), people[0], people[1]); + assertComparison(cmp.thenComparing(cmp2), people[4], people[0]); + // thenComparing(Function) + assertComparison(cmp.thenComparing(People::getLastName), people[0], people[1]); + assertComparison(cmp.thenComparing(People::getLastName), people[4], people[0]); + // thenComparing(ToIntFunction) + assertComparison(cmp.thenComparing(People::getAge), people[0], people[1]); + assertComparison(cmp.thenComparing(People::getAge), people[1], people[5]); + // thenComparing(ToLongFunction) + assertComparison(cmp.thenComparing(People::getAgeAsLong), people[0], people[1]); + assertComparison(cmp.thenComparing(People::getAgeAsLong), people[1], people[5]); + // thenComparing(ToDoubleFunction) + assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[0], people[1]); + assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[1], people[5]); + } + + public void testGreaterOf() { + // lesser + assertSame(Comparators.greaterOf(Comparators.comparing( + (Function<People, String>) People::getFirstName)) + .apply(people[0], people[1]), + people[1]); + // euqal + assertSame(Comparators.greaterOf(Comparators.comparing( + (Function<People, String>) People::getLastName)) + .apply(people[0], people[1]), + people[0]); + // greater + assertSame(Comparators.greaterOf(Comparators.comparing( + (ToIntFunction<People>) People::getAge)) + .apply(people[0], people[1]), + people[0]); + } + + public void testLesserOf() { + // lesser + assertSame(Comparators.lesserOf(Comparators.comparing( + (Function<People, String>) People::getFirstName)) + .apply(people[0], people[1]), + people[0]); + // euqal + assertSame(Comparators.lesserOf(Comparators.comparing( + (Function<People, String>) People::getLastName)) + .apply(people[0], people[1]), + people[0]); + // greater + assertSame(Comparators.lesserOf(Comparators.comparing( + (ToIntFunction<People>) People::getAge)) + .apply(people[0], people[1]), + people[1]); + } +} \ No newline at end of file From 2ec1224ff0bb8fa3447a8c061844e99f088265db Mon Sep 17 00:00:00 2001 From: Weijun Wang <weijun@openjdk.org> Date: Sat, 9 Mar 2013 17:27:58 +0800 Subject: [PATCH 158/180] 8000653: SPNEGO tests fail at context.getDelegCred().getRemainingInitLifetime(mechOid) Reviewed-by: valeriep --- .../sun/security/jgss/GSSCredentialImpl.java | 7 +++ .../jgss/spnego/SpNegoCredElement.java | 2 +- jdk/test/sun/security/krb5/auto/Context.java | 7 +++ .../security/krb5/auto/SpnegoLifeTime.java | 58 +++++++++++++++++++ 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 jdk/test/sun/security/krb5/auto/SpnegoLifeTime.java diff --git a/jdk/src/share/classes/sun/security/jgss/GSSCredentialImpl.java b/jdk/src/share/classes/sun/security/jgss/GSSCredentialImpl.java index 6330f71c1b0..584e1784c8a 100644 --- a/jdk/src/share/classes/sun/security/jgss/GSSCredentialImpl.java +++ b/jdk/src/share/classes/sun/security/jgss/GSSCredentialImpl.java @@ -29,6 +29,7 @@ import org.ietf.jgss.*; import sun.security.jgss.spi.*; import java.util.*; import com.sun.security.jgss.*; +import sun.security.jgss.spnego.SpNegoCredElement; public class GSSCredentialImpl implements ExtendedGSSCredential { @@ -87,6 +88,7 @@ public class GSSCredentialImpl implements ExtendedGSSCredential { throw new GSSException(GSSException.NO_CRED); } + // Wrap a mech cred into a GSS cred public GSSCredentialImpl(GSSManagerImpl gssManager, GSSCredentialSpi mechElement) throws GSSException { @@ -103,6 +105,11 @@ public class GSSCredentialImpl implements ExtendedGSSCredential { usage); tempCred = mechElement; hashtable.put(key, tempCred); + // More mechs that can use this cred, say, SPNEGO + if (!GSSUtil.isSpNegoMech(mechElement.getMechanism())) { + key = new SearchKey(GSSUtil.GSS_SPNEGO_MECH_OID, usage); + hashtable.put(key, new SpNegoCredElement(mechElement)); + } } void init(GSSManagerImpl gssManager) { diff --git a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoCredElement.java b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoCredElement.java index 69116f56bd2..ee5999ced55 100644 --- a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoCredElement.java +++ b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoCredElement.java @@ -44,7 +44,7 @@ public class SpNegoCredElement implements GSSCredentialSpi { private GSSCredentialSpi cred = null; - SpNegoCredElement(GSSCredentialSpi cred) throws GSSException { + public SpNegoCredElement(GSSCredentialSpi cred) throws GSSException { this.cred = cred; } diff --git a/jdk/test/sun/security/krb5/auto/Context.java b/jdk/test/sun/security/krb5/auto/Context.java index aae14f46bd3..738f2c3d4e3 100644 --- a/jdk/test/sun/security/krb5/auto/Context.java +++ b/jdk/test/sun/security/krb5/auto/Context.java @@ -296,6 +296,13 @@ public class Context { return s; } + /** + * Returns the cred inside, if there is one + */ + public GSSCredential cred() { + return cred; + } + /** * Disposes the GSSContext within * @throws org.ietf.jgss.GSSException diff --git a/jdk/test/sun/security/krb5/auto/SpnegoLifeTime.java b/jdk/test/sun/security/krb5/auto/SpnegoLifeTime.java new file mode 100644 index 00000000000..906cfbee786 --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/SpnegoLifeTime.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2013, 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 8000653 + * @summary SPNEGO tests fail at context.getDelegCred().getRemainingInitLifetime(mechOid) + * @compile -XDignore.symbol.file SpnegoLifeTime.java + * @run main/othervm SpnegoLifeTime + */ + +import org.ietf.jgss.Oid; +import org.ietf.jgss.GSSCredential; +import sun.security.jgss.GSSUtil; + +public class SpnegoLifeTime { + + public static void main(String[] args) throws Exception { + + Oid oid = GSSUtil.GSS_SPNEGO_MECH_OID; + new OneKDC(null).writeJAASConf(); + + Context c, s; + c = Context.fromJAAS("client"); + s = Context.fromJAAS("server"); + + c.startAsClient(OneKDC.SERVER, oid); + c.x().requestCredDeleg(true); + s.startAsServer(oid); + + Context.handshake(c, s); + + GSSCredential cred = s.delegated().cred(); + cred.getRemainingInitLifetime(oid); + cred.getUsage(oid); + } +} + From a181e6d5056d9a25eee3319cd4475844f7b831d2 Mon Sep 17 00:00:00 2001 From: Kevin Walls <kevinw@openjdk.org> Date: Mon, 11 Mar 2013 12:56:00 +0000 Subject: [PATCH 159/180] 8009723: CMS logs "concurrent mode failure" twice when using (disabling) -XX:-UseCMSCompactAtFullCollection Reviewed-by: jwilhelm, ehelin, brutisso --- .../concurrentMarkSweep/concurrentMarkSweepGeneration.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index a9b2714c213..9375c0efb53 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -2063,11 +2063,6 @@ void CMSCollector::do_mark_sweep_work(bool clear_all_soft_refs, // required. _collectorState = FinalMarking; } - if (PrintGCDetails && - (_collectorState > Idling || - !GCCause::is_user_requested_gc(GenCollectedHeap::heap()->gc_cause()))) { - gclog_or_tty->print(" (concurrent mode failure)"); - } collect_in_foreground(clear_all_soft_refs); // For a mark-sweep, compute_new_size() will be called From 1aa6c2729857895f7d8e624c8508854f717a270b Mon Sep 17 00:00:00 2001 From: Mikael Gerdin <mgerdin@openjdk.org> Date: Tue, 12 Mar 2013 09:42:24 +0100 Subject: [PATCH 160/180] 8009282: Assertion "assert(used_and_free == capacity_bytes) failed: Accounting is wrong" failed with -XX:+Verbose -XX:+TraceMetadataChunkAllocation Assertion is only valid when at a safepoint, adjust accordingly. Reviewed-by: stefank, jmasa, tamao --- hotspot/src/share/vm/memory/metaspace.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index b0891150d9c..56b14c22cf7 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -2440,7 +2440,8 @@ void MetaspaceAux::print_on(outputStream* out, Metaspace::MetadataType mdtype) { free_chunks_capacity_bytes / K, used_and_free / K, capacity_bytes / K); - assert(used_and_free == capacity_bytes, "Accounting is wrong"); + // Accounting can only be correct if we got the values during a safepoint + assert(!SafepointSynchronize::is_at_safepoint() || used_and_free == capacity_bytes, "Accounting is wrong"); } // Print total fragmentation for class and data metaspaces separately From 1e1174e0be3a6e7fbecf9bb729179f3a1ab73853 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson <stefank@openjdk.org> Date: Mon, 11 Mar 2013 02:24:01 -0700 Subject: [PATCH 161/180] 8004697: SIGSEGV on Solaris sparc with -XX:+UseNUMA Don't scan pages outside the given range. Reviewed-by: jwilhelm, jmasa --- hotspot/src/os/solaris/vm/os_solaris.cpp | 2 +- .../src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index a80a0ea4590..147254dd4de 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -2945,7 +2945,7 @@ char *os::scan_pages(char *start, char* end, page_info* page_expected, page_info while (p < (uint64_t)end) { addrs[0] = p; size_t addrs_count = 1; - while (addrs_count < MAX_MEMINFO_CNT && addrs[addrs_count - 1] < (uint64_t)end) { + while (addrs_count < MAX_MEMINFO_CNT && addrs[addrs_count - 1] + page_size < (uint64_t)end) { addrs[addrs_count] = addrs[addrs_count - 1] + page_size; addrs_count++; } diff --git a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp index 8de8b3a2983..d3d758b79bd 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp @@ -948,6 +948,8 @@ void MutableNUMASpace::LGRPSpace::scan_pages(size_t page_size, size_t page_count break; } if (e != scan_end) { + assert(e < scan_end, err_msg("e: " PTR_FORMAT " scan_end: " PTR_FORMAT, e, scan_end)); + if ((page_expected.size != page_size || page_expected.lgrp_id != lgrp_id()) && page_expected.size != 0) { os::free_memory(s, pointer_delta(e, s, sizeof(char)), page_size); From 2f5e08742afb0fce35e3a134eb0b3aed7c30d2d1 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev <aleksey.shipilev@oracle.com> Date: Mon, 11 Mar 2013 14:00:09 -0400 Subject: [PATCH 162/180] 8008965: @Contended fails with classes having static fields Disable @Contended support for static fields Reviewed-by: coleenp, kvn --- .../share/vm/classfile/classFileParser.cpp | 110 +------ hotspot/test/runtime/8003985/Test8003985.java | 302 ++++++++++++++++++ 2 files changed, 311 insertions(+), 101 deletions(-) create mode 100644 hotspot/test/runtime/8003985/Test8003985.java diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index 3650e05406f..005bda61bd3 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -3492,7 +3492,6 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, int next_static_word_offset; int next_static_short_offset; int next_static_byte_offset; - int next_static_padded_offset; int next_nonstatic_oop_offset; int next_nonstatic_double_offset; int next_nonstatic_word_offset; @@ -3505,33 +3504,25 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, int next_nonstatic_padded_offset; // Count the contended fields by type. - int static_contended_count = 0; int nonstatic_contended_count = 0; FieldAllocationCount fac_contended; for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); if (fs.is_contended()) { fac_contended.count[atype]++; - if (fs.access_flags().is_static()) { - static_contended_count++; - } else { + if (!fs.access_flags().is_static()) { nonstatic_contended_count++; } } } - int contended_count = static_contended_count + nonstatic_contended_count; + int contended_count = nonstatic_contended_count; // Calculate the starting byte offsets next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields(); - // class is contended, pad before all the fields - if (parsed_annotations.is_contended()) { - next_static_oop_offset += pad_size; - } - next_static_double_offset = next_static_oop_offset + - ((fac.count[STATIC_OOP] - fac_contended.count[STATIC_OOP]) * heapOopSize); + ((fac.count[STATIC_OOP]) * heapOopSize); if ( fac.count[STATIC_DOUBLE] && (Universe::field_type_should_be_aligned(T_DOUBLE) || Universe::field_type_should_be_aligned(T_LONG)) ) { @@ -3539,13 +3530,11 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } next_static_word_offset = next_static_double_offset + - ((fac.count[STATIC_DOUBLE] - fac_contended.count[STATIC_DOUBLE]) * BytesPerLong); + ((fac.count[STATIC_DOUBLE]) * BytesPerLong); next_static_short_offset = next_static_word_offset + - ((fac.count[STATIC_WORD] - fac_contended.count[STATIC_WORD]) * BytesPerInt); + ((fac.count[STATIC_WORD]) * BytesPerInt); next_static_byte_offset = next_static_short_offset + - ((fac.count[STATIC_SHORT] - fac_contended.count[STATIC_SHORT]) * BytesPerShort); - next_static_padded_offset = next_static_byte_offset + - ((fac.count[STATIC_BYTE] - fac_contended.count[STATIC_BYTE]) * 1); + ((fac.count[STATIC_SHORT]) * BytesPerShort); first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size * heapOopSize; @@ -3738,8 +3727,8 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, // skip already laid out fields if (fs.is_offset_set()) continue; - // contended fields are handled below - if (fs.is_contended()) continue; + // contended instance fields are handled below + if (fs.is_contended() && !fs.access_flags().is_static()) continue; int real_offset; FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); @@ -3943,86 +3932,6 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, // handle static fields - // if there is at least one contended field, we need to have pre-padding for them - if (static_contended_count > 0) { - next_static_padded_offset += pad_size; - } - - current_group = -1; - while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) { - - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - - // skip already laid out fields - if (fs.is_offset_set()) continue; - - // skip non-contended fields and fields from different group - if (!fs.is_contended() || (fs.contended_group() != current_group)) continue; - - // non-statics already handled above - if (!fs.access_flags().is_static()) continue; - - int real_offset; - FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); - - switch (atype) { - - case STATIC_BYTE: - next_static_padded_offset = align_size_up(next_static_padded_offset, 1); - real_offset = next_static_padded_offset; - next_static_padded_offset += 1; - break; - - case STATIC_SHORT: - next_static_padded_offset = align_size_up(next_static_padded_offset, BytesPerShort); - real_offset = next_static_padded_offset; - next_static_padded_offset += BytesPerShort; - break; - - case STATIC_WORD: - next_static_padded_offset = align_size_up(next_static_padded_offset, BytesPerInt); - real_offset = next_static_padded_offset; - next_static_padded_offset += BytesPerInt; - break; - - case STATIC_DOUBLE: - next_static_padded_offset = align_size_up(next_static_padded_offset, BytesPerLong); - real_offset = next_static_padded_offset; - next_static_padded_offset += BytesPerLong; - break; - - case STATIC_OOP: - next_static_padded_offset = align_size_up(next_static_padded_offset, heapOopSize); - real_offset = next_static_padded_offset; - next_static_padded_offset += heapOopSize; - break; - - default: - ShouldNotReachHere(); - } - - if (fs.contended_group() == 0) { - // Contended group defines the equivalence class over the fields: - // the fields within the same contended group are not inter-padded. - // The only exception is default group, which does not incur the - // equivalence, and so requires intra-padding. - next_static_padded_offset += pad_size; - } - - fs.set_offset(real_offset); - } // for - - // Start laying out the next group. - // Note that this will effectively pad the last group in the back; - // this is expected to alleviate memory contention effects for - // subclass fields and/or adjacent object. - // If this was the default group, the padding is already in place. - if (current_group != 0) { - next_static_padded_offset += pad_size; - } - - } - } // handle contended // Size of instances @@ -4035,10 +3944,9 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, // and/or adjacent object. if (parsed_annotations.is_contended()) { notaligned_offset += pad_size; - next_static_padded_offset += pad_size; } - int next_static_type_offset = align_size_up(next_static_padded_offset, wordSize); + int next_static_type_offset = align_size_up(next_static_byte_offset, wordSize); int static_field_size = (next_static_type_offset - InstanceMirrorKlass::offset_of_static_fields()) / wordSize; diff --git a/hotspot/test/runtime/8003985/Test8003985.java b/hotspot/test/runtime/8003985/Test8003985.java new file mode 100644 index 00000000000..5e30f670257 --- /dev/null +++ b/hotspot/test/runtime/8003985/Test8003985.java @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2013, 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. + */ + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.lang.Class; +import java.lang.String; +import java.lang.System; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CyclicBarrier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import sun.misc.Unsafe; +import sun.misc.Contended; + +/* + * @test + * @bug 8003985 + * @summary Support Contended Annotation - JEP 142 + * + * @run main/othervm -XX:-RestrictContended Test8003985 + */ +public class Test8003985 { + + private static final Unsafe U; + private static int ADDRESS_SIZE; + private static int HEADER_SIZE; + + static { + // steal Unsafe + try { + Field unsafe = Unsafe.class.getDeclaredField("theUnsafe"); + unsafe.setAccessible(true); + U = (Unsafe) unsafe.get(null); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + + // When running with CompressedOops on 64-bit platform, the address size + // reported by Unsafe is still 8, while the real reference fields are 4 bytes long. + // Try to guess the reference field size with this naive trick. + try { + long off1 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj1")); + long off2 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj2")); + ADDRESS_SIZE = (int) Math.abs(off2 - off1); + HEADER_SIZE = (int) Math.min(off1, off2); + } catch (NoSuchFieldException e) { + ADDRESS_SIZE = -1; + } + } + + static class CompressedOopsClass { + public Object obj1; + public Object obj2; + } + + public static boolean arePaddedPairwise(Class klass, String field1, String field2) throws Exception { + Field f1 = klass.getDeclaredField(field1); + Field f2 = klass.getDeclaredField(field2); + + if (isStatic(f1) != isStatic(f2)) { + return true; // these guys are in naturally disjoint locations + } + + int diff = offset(f1) - offset(f2); + if (diff < 0) { + // f1 is first + return (offset(f2) - (offset(f1) + getSize(f1))) > 64; + } else { + // f2 is first + return (offset(f1) - (offset(f2) + getSize(f2))) > 64; + } + } + + public static boolean isPadded(Class klass, String field1) throws Exception { + Field f1 = klass.getDeclaredField(field1); + + if (isStatic(f1)) { + return offset(f1) > 128 + 64; + } + + return offset(f1) > 64; + } + + public static boolean sameLayout(Class klass1, Class klass2) throws Exception { + for (Field f1 : klass1.getDeclaredFields()) { + Field f2 = klass2.getDeclaredField(f1.getName()); + if (offset(f1) != offset(f2)) { + return false; + } + } + + for (Field f2 : klass1.getDeclaredFields()) { + Field f1 = klass2.getDeclaredField(f2.getName()); + if (offset(f1) != offset(f2)) { + return false; + } + } + + return true; + } + + public static boolean isStatic(Field field) { + return Modifier.isStatic(field.getModifiers()); + } + + public static int offset(Field field) { + if (isStatic(field)) { + return (int) U.staticFieldOffset(field); + } else { + return (int) U.objectFieldOffset(field); + } + } + + public static int getSize(Field field) { + Class type = field.getType(); + if (type == byte.class) { return 1; } + if (type == boolean.class) { return 1; } + if (type == short.class) { return 2; } + if (type == char.class) { return 2; } + if (type == int.class) { return 4; } + if (type == float.class) { return 4; } + if (type == long.class) { return 8; } + if (type == double.class) { return 8; } + return ADDRESS_SIZE; + } + + public static void main(String[] args) throws Exception { + boolean endResult = true; + + // --------------- INSTANCE FIELDS --------------------- + + if (arePaddedPairwise(Test1.class, "int1", "int2") || + isPadded(Test1.class, "int1") || + isPadded(Test1.class, "int2")) { + System.err.println("Test1 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test2.class, "int1", "int2") || + !isPadded(Test2.class, "int1") || + isPadded(Test2.class, "int2")) { + System.err.println("Test2 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test3.class, "int1", "int2") || + !isPadded(Test3.class, "int1") || + !isPadded(Test3.class, "int2")) { + System.err.println("Test3 failed"); + endResult &= false; + } + + if (arePaddedPairwise(Test4.class, "int1", "int2") || + !isPadded(Test4.class, "int1") || + !isPadded(Test4.class, "int2")) { + System.err.println("Test4 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test5.class, "int1", "int2") || + !isPadded(Test5.class, "int1") || + !isPadded(Test5.class, "int2")) { + System.err.println("Test5 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test6.class, "int1", "int2") || + !isPadded(Test6.class, "int1") || + !isPadded(Test6.class, "int2")) { + System.err.println("Test6 failed"); + endResult &= false; + } + + if (arePaddedPairwise(Test7.class, "int1", "int2") || + !isPadded(Test7.class, "int1") || + !isPadded(Test7.class, "int2")) { + System.err.println("Test7 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test8.class, "int1", "int2") || + !isPadded(Test8.class, "int1") || + !isPadded(Test8.class, "int2")) { + System.err.println("Test8 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test9.class, "int1", "int2") || + !isPadded(Test9.class, "int1") || + !isPadded(Test9.class, "int2")) { + System.err.println("Test9 failed"); + endResult &= false; + } + + if (!sameLayout(Test4.class, Test7.class)) { + System.err.println("Test4 and Test7 have different layouts"); + endResult &= false; + } + + if (!sameLayout(Test5.class, Test6.class)) { + System.err.println("Test5 and Test6 have different layouts"); + endResult &= false; + } + + if (!sameLayout(Test8.class, Test9.class)) { + System.err.println("Test8 and Test9 have different layouts"); + endResult &= false; + } + + System.out.println(endResult ? "Test PASSES" : "Test FAILS"); + if (!endResult) { + throw new Error("Test failed"); + } + } + + // ----------------------------------- INSTANCE FIELDS ----------------------------------------- + + // naturally packed + public static class Test1 { + private int int1; + private int int2; + } + + // int1 is padded + public static class Test2 { + @Contended private int int1; + private int int2; + } + + // both fields are padded + public static class Test3 { + @Contended private int int1; + @Contended private int int2; + } + + // fields are padded in the singular group + public static class Test4 { + @Contended("sameGroup") private int int1; + @Contended("sameGroup") private int int2; + } + + // fields are padded in disjoint groups + public static class Test5 { + @Contended("diffGroup1") private int int1; + @Contended("diffGroup2") private int int2; + } + + // fields are padded in disjoint groups + public static class Test6 { + @Contended private int int1; + @Contended("diffGroup2") private int int2; + } + + // fields are padded in the singular group + @Contended + public static class Test7 { + private int int1; + private int int2; + } + + // all fields are padded as the group, and one field is padded specifically + @Contended + public static class Test8 { + @Contended private int int1; + private int int2; + } + + // all fields are padded as the group, and one field is padded specifically + @Contended + public static class Test9 { + @Contended("group") private int int1; + private int int2; + } + +} + From 0f54c506382f5c2826660a668e3199fba78acc79 Mon Sep 17 00:00:00 2001 From: Joseph Provino <jprovino@openjdk.org> Date: Tue, 12 Mar 2013 00:02:16 -0400 Subject: [PATCH 163/180] 8009835: Only produce a warning when -Xshare:auto is explicitly requested The minimal JVM is printing a warning message for default settings when it should quitely ignore them. Reviewed-by: coleenp, dholmes --- hotspot/src/share/vm/runtime/arguments.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 554d6a75433..a74e62d6b95 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -3262,7 +3262,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { "Shared spaces are not supported in this VM\n"); return JNI_ERR; } - if (UseSharedSpaces || PrintSharedSpaces) { + if ((UseSharedSpaces && FLAG_IS_CMDLINE(UseSharedSpaces)) || PrintSharedSpaces) { warning("Shared spaces are not supported in this VM"); FLAG_SET_DEFAULT(UseSharedSpaces, false); FLAG_SET_DEFAULT(PrintSharedSpaces, false); From c51ea967ce53ad1533e2ec8aa507d77a67c024ce Mon Sep 17 00:00:00 2001 From: Bengt Rutisson <brutisso@openjdk.org> Date: Tue, 12 Mar 2013 08:33:57 +0100 Subject: [PATCH 164/180] 8001049: VM crashes when running with large -Xms and not specifying ObjectAlignmentInBytes Take the initial heap size into account when checking the heap size for compressed oops Reviewed-by: jmasa, kvn, hseigel, ctornqvi --- hotspot/src/share/vm/memory/universe.cpp | 2 + hotspot/src/share/vm/runtime/arguments.cpp | 59 +++++++++++++--------- hotspot/src/share/vm/runtime/arguments.hpp | 1 + 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index a7a6c24bfd2..79e092a3b19 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -885,6 +885,8 @@ ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) { // the actual alignment depends on its size. Universe::set_class_metaspace_size(align_size_up(ClassMetaspaceSize, alignment)); size_t total_reserved = align_size_up(heap_size + Universe::class_metaspace_size(), alignment); + assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())), + "heap size is too big for compressed oops"); char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); ReservedHeapSpace total_rs(total_reserved, alignment, UseLargePages, addr); diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index d6e4c308444..44acefb4c05 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1381,6 +1381,40 @@ bool Arguments::should_auto_select_low_pause_collector() { return false; } +void Arguments::set_use_compressed_oops() { +#ifndef ZERO +#ifdef _LP64 + // MaxHeapSize is not set up properly at this point, but + // the only value that can override MaxHeapSize if we are + // to use UseCompressedOops is InitialHeapSize. + size_t max_heap_size = MAX2(MaxHeapSize, InitialHeapSize); + + if (max_heap_size <= max_heap_for_compressed_oops()) { +#if !defined(COMPILER1) || defined(TIERED) + if (FLAG_IS_DEFAULT(UseCompressedOops)) { + FLAG_SET_ERGO(bool, UseCompressedOops, true); + } +#endif +#ifdef _WIN64 + if (UseLargePages && UseCompressedOops) { + // Cannot allocate guard pages for implicit checks in indexed addressing + // mode, when large pages are specified on windows. + // This flag could be switched ON if narrow oop base address is set to 0, + // see code in Universe::initialize_heap(). + Universe::set_narrow_oop_use_implicit_null_checks(false); + } +#endif // _WIN64 + } else { + if (UseCompressedOops && !FLAG_IS_DEFAULT(UseCompressedOops)) { + warning("Max heap size too large for Compressed Oops"); + FLAG_SET_DEFAULT(UseCompressedOops, false); + FLAG_SET_DEFAULT(UseCompressedKlassPointers, false); + } + } +#endif // _LP64 +#endif // ZERO +} + void Arguments::set_ergonomics_flags() { if (os::is_server_class_machine()) { @@ -1410,30 +1444,7 @@ void Arguments::set_ergonomics_flags() { #ifndef ZERO #ifdef _LP64 - // Check that UseCompressedOops can be set with the max heap size allocated - // by ergonomics. - if (MaxHeapSize <= max_heap_for_compressed_oops()) { -#if !defined(COMPILER1) || defined(TIERED) - if (FLAG_IS_DEFAULT(UseCompressedOops)) { - FLAG_SET_ERGO(bool, UseCompressedOops, true); - } -#endif -#ifdef _WIN64 - if (UseLargePages && UseCompressedOops) { - // Cannot allocate guard pages for implicit checks in indexed addressing - // mode, when large pages are specified on windows. - // This flag could be switched ON if narrow oop base address is set to 0, - // see code in Universe::initialize_heap(). - Universe::set_narrow_oop_use_implicit_null_checks(false); - } -#endif // _WIN64 - } else { - if (UseCompressedOops && !FLAG_IS_DEFAULT(UseCompressedOops)) { - warning("Max heap size too large for Compressed Oops"); - FLAG_SET_DEFAULT(UseCompressedOops, false); - FLAG_SET_DEFAULT(UseCompressedKlassPointers, false); - } - } + set_use_compressed_oops(); // UseCompressedOops must be on for UseCompressedKlassPointers to be on. if (!UseCompressedOops) { if (UseCompressedKlassPointers) { diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index 26c029744da..d75fc9a82bd 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -309,6 +309,7 @@ class Arguments : AllStatic { // Garbage-First (UseG1GC) static void set_g1_gc_flags(); // GC ergonomics + static void set_use_compressed_oops(); static void set_ergonomics_flags(); static void set_shared_spaces_flags(); // Setup heap size From 401d1f315d080b806636e06fa6c6f90b87b4191f Mon Sep 17 00:00:00 2001 From: Thomas Schatzl <tschatzl@openjdk.org> Date: Tue, 12 Mar 2013 15:10:39 +0100 Subject: [PATCH 165/180] 8008684: CMS: concurrent phase start markers should always be printed Print the concurrent phase start markers for CMS when PrintGCDetails is enabled, not only if both PrintGCDetails and PrintGCTimeStamps are. Reviewed-by: mgerdin, jmasa --- .../concurrentMarkSweep/concurrentMarkSweepGeneration.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index 9375c0efb53..1d056338c7d 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -3395,10 +3395,10 @@ CMSPhaseAccounting::CMSPhaseAccounting(CMSCollector *collector, if (PrintCMSStatistics != 0) { _collector->resetYields(); } - if (PrintGCDetails && PrintGCTimeStamps) { + if (PrintGCDetails) { gclog_or_tty->date_stamp(PrintGCDateStamps); - gclog_or_tty->stamp(); - gclog_or_tty->print_cr(": [%s-concurrent-%s-start]", + gclog_or_tty->stamp(PrintGCTimeStamps); + gclog_or_tty->print_cr("[%s-concurrent-%s-start]", _collector->cmsGen()->short_name(), _phase); } _collector->resetTimer(); From 7d74801ce2e73b529c394db6f20f40f12d290bf6 Mon Sep 17 00:00:00 2001 From: Harold Seigel <harold.seigel@oracle.com> Date: Tue, 12 Mar 2013 10:35:44 -0400 Subject: [PATCH 166/180] 7154889: Non-zero padding is still not allowed in the tableswitch/lookupswitch instructions Do not check that the padding bytes are zero if class file format version >=51. Reviewed-by: dholmes, coleenp, mullan, kvn --- jdk/src/share/native/common/check_code.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/jdk/src/share/native/common/check_code.c b/jdk/src/share/native/common/check_code.c index 7ecf096a679..e1170293f07 100644 --- a/jdk/src/share/native/common/check_code.c +++ b/jdk/src/share/native/common/check_code.c @@ -206,6 +206,8 @@ enum { #define LDC_METHOD_HANDLE_MAJOR_VERSION 51 +#define NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION 51 + #define STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION 52 #define ALLOC_STACK_SIZE 16 /* big enough */ @@ -1146,11 +1148,14 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) int *saved_operand; int keys; int k, delta; - /* 4639449, 4647081: Padding bytes must be zero. */ - unsigned char* bptr = (unsigned char*) (code + offset + 1); - for (; bptr < (unsigned char*)lpc; bptr++) { - if (*bptr != 0) { - CCerror(context, "Non zero padding bytes in switch"); + + if (context->major_version < NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION) { + /* 4639449, 4647081: Padding bytes must be zero. */ + unsigned char* bptr = (unsigned char*) (code + offset + 1); + for (; bptr < (unsigned char*)lpc; bptr++) { + if (*bptr != 0) { + CCerror(context, "Non zero padding bytes in switch"); + } } } if (opcode == JVM_OPC_tableswitch) { From 79c091f28714c5c0ce01a724942eeb4f8194443f Mon Sep 17 00:00:00 2001 From: Jon Masamitsu <jmasa@openjdk.org> Date: Tue, 12 Mar 2013 11:00:49 -0700 Subject: [PATCH 167/180] 6976528: PS: assert(!limit_exceeded || softrefs_clear) failed: Should have been cleared Reviewed-by: johnc --- .../gc_implementation/parallelScavenge/parallelScavengeHeap.cpp | 2 +- hotspot/src/share/vm/memory/collectorPolicy.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp index cbd56f755c5..21e08b6f874 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp @@ -409,7 +409,7 @@ HeapWord* ParallelScavengeHeap::mem_allocate( // heap remains parsable. const bool limit_exceeded = size_policy()->gc_overhead_limit_exceeded(); const bool softrefs_clear = collector_policy()->all_soft_refs_clear(); - assert(!limit_exceeded || softrefs_clear, "Should have been cleared"); + if (limit_exceeded && softrefs_clear) { *gc_overhead_limit_was_exceeded = true; size_policy()->set_gc_overhead_limit_exceeded(false); diff --git a/hotspot/src/share/vm/memory/collectorPolicy.cpp b/hotspot/src/share/vm/memory/collectorPolicy.cpp index ab8f2ca7fc0..d5eb387a04c 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp @@ -620,7 +620,7 @@ HeapWord* GenCollectorPolicy::mem_allocate_work(size_t size, const bool limit_exceeded = size_policy()->gc_overhead_limit_exceeded(); const bool softrefs_clear = all_soft_refs_clear(); - assert(!limit_exceeded || softrefs_clear, "Should have been cleared"); + if (limit_exceeded && softrefs_clear) { *gc_overhead_limit_was_exceeded = true; size_policy()->set_gc_overhead_limit_exceeded(false); From 9e5da0ad31d3ee5626ed4ba4c0fdc49a6fe64af9 Mon Sep 17 00:00:00 2001 From: Bradford Wetmore <wetmore@openjdk.org> Date: Tue, 12 Mar 2013 15:31:49 -0700 Subject: [PATCH 168/180] 8009925: Back out AEAD CipherSuites temporarily Reviewed-by: valeriep --- .../provider/TlsKeyMaterialGenerator.java | 28 +- .../spec/TlsKeyMaterialParameterSpec.java | 8 +- .../internal/spec/TlsKeyMaterialSpec.java | 26 +- .../pkcs11/P11TlsKeyMaterialGenerator.java | 18 +- .../sun/security/ssl/Authenticator.java | 161 ----- .../classes/sun/security/ssl/CipherBox.java | 582 +++++------------- .../classes/sun/security/ssl/CipherSuite.java | 228 ++----- .../sun/security/ssl/EngineInputRecord.java | 148 +++-- .../sun/security/ssl/EngineOutputRecord.java | 160 ++--- .../sun/security/ssl/EngineWriter.java | 12 +- .../classes/sun/security/ssl/Handshaker.java | 80 +-- .../classes/sun/security/ssl/InputRecord.java | 110 +--- .../classes/sun/security/ssl/JsseJce.java | 7 +- .../share/classes/sun/security/ssl/MAC.java | 124 +++- .../sun/security/ssl/OutputRecord.java | 149 ++--- .../classes/sun/security/ssl/Record.java | 35 +- .../sun/security/ssl/SSLEngineImpl.java | 53 +- .../sun/security/ssl/SSLSocketImpl.java | 44 +- jdk/test/sun/security/ec/TestEC.java | 7 +- .../sun/security/pkcs11/fips/CipherTest.java | 21 +- .../security/pkcs11/sslecc/CipherTest.java | 21 +- .../SSLEngineBadBufferArrayAccess.java | 8 +- .../javax/net/ssl/TLSv12/ShortRSAKeyGCM.java | 445 ------------- .../ciphersuites/CipherSuitesInOrder.java | 27 +- .../ssl/sanity/interop/CipherTest.java | 21 +- .../templates/SSLSocketSSLEngineTemplate.java | 11 +- 26 files changed, 706 insertions(+), 1828 deletions(-) delete mode 100644 jdk/src/share/classes/sun/security/ssl/Authenticator.java delete mode 100644 jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKeyGCM.java diff --git a/jdk/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java b/jdk/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java index d1255d42164..4146f190875 100644 --- a/jdk/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java +++ b/jdk/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -165,18 +165,16 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi { // partition keyblock into individual secrets int ofs = 0; - if (macLength != 0) { - byte[] tmp = new byte[macLength]; + byte[] tmp = new byte[macLength]; - // mac keys - System.arraycopy(keyBlock, ofs, tmp, 0, macLength); - ofs += macLength; - clientMacKey = new SecretKeySpec(tmp, "Mac"); + // mac keys + System.arraycopy(keyBlock, ofs, tmp, 0, macLength); + ofs += macLength; + clientMacKey = new SecretKeySpec(tmp, "Mac"); - System.arraycopy(keyBlock, ofs, tmp, 0, macLength); - ofs += macLength; - serverMacKey = new SecretKeySpec(tmp, "Mac"); - } + System.arraycopy(keyBlock, ofs, tmp, 0, macLength); + ofs += macLength; + serverMacKey = new SecretKeySpec(tmp, "Mac"); if (keyLength == 0) { // SSL_RSA_WITH_NULL_* ciphersuites return new TlsKeyMaterialSpec(clientMacKey, serverMacKey); @@ -200,7 +198,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi { // IV keys if needed. if (ivLength != 0) { - byte[] tmp = new byte[ivLength]; + tmp = new byte[ivLength]; System.arraycopy(keyBlock, ofs, tmp, 0, ivLength); ofs += ivLength; @@ -222,8 +220,8 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi { // TLS 1.0 byte[] seed = concat(clientRandom, serverRandom); - byte[] tmp = doTLS10PRF(clientKeyBytes, - LABEL_CLIENT_WRITE_KEY, seed, expandedKeyLength, md5, sha); + tmp = doTLS10PRF(clientKeyBytes, LABEL_CLIENT_WRITE_KEY, seed, + expandedKeyLength, md5, sha); clientCipherKey = new SecretKeySpec(tmp, alg); tmp = doTLS10PRF(serverKeyBytes, LABEL_SERVER_WRITE_KEY, seed, @@ -241,7 +239,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi { } } else { // SSLv3 - byte[] tmp = new byte[expandedKeyLength]; + tmp = new byte[expandedKeyLength]; md5.update(clientKeyBytes); md5.update(clientRandom); diff --git a/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java b/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java index 71388b79718..80aa79a2596 100644 --- a/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java +++ b/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialParameterSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, 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 @@ -212,6 +212,12 @@ public class TlsKeyMaterialParameterSpec implements AlgorithmParameterSpec { * generated. */ public int getIvLength() { + // TLS v1.1 or later uses an explicit IV to protect against + // the CBC attacks. + if (majorVersion >= 0x03 && minorVersion >= 0x02) { + return 0; + } + return ivLength; } diff --git a/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialSpec.java b/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialSpec.java index 2dd8a93765b..d1204962881 100644 --- a/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialSpec.java +++ b/jdk/src/share/classes/sun/security/internal/spec/TlsKeyMaterialSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, 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 @@ -58,8 +58,9 @@ public class TlsKeyMaterialSpec implements KeySpec, SecretKey { * <code>new TlsKeymaterialSpec(clientMacKey, serverMacKey, * null, null, null, null)</code>. * - * @param clientMacKey the client MAC key (or null) - * @param serverMacKey the server MAC key (or null) + * @param clientMacKey the client MAC key + * @param serverMacKey the server MAC key + * @throws NullPointerException if clientMacKey or serverMacKey is null */ public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey) { this(clientMacKey, serverMacKey, null, null, null, null); @@ -72,10 +73,11 @@ public class TlsKeyMaterialSpec implements KeySpec, SecretKey { * <code>new TlsKeymaterialSpec(clientMacKey, serverMacKey, * clientCipherKey, serverCipherKey, null, null)</code>. * - * @param clientMacKey the client MAC key (or null) - * @param serverMacKey the server MAC key (or null) + * @param clientMacKey the client MAC key + * @param serverMacKey the server MAC key * @param clientCipherKey the client cipher key (or null) * @param serverCipherKey the server cipher key (or null) + * @throws NullPointerException if clientMacKey or serverMacKey is null */ public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey, SecretKey clientCipherKey, SecretKey serverCipherKey) { @@ -88,17 +90,21 @@ public class TlsKeyMaterialSpec implements KeySpec, SecretKey { * keys, client and server cipher keys, and client and server * initialization vectors. * - * @param clientMacKey the client MAC key (or null) - * @param serverMacKey the server MAC key (or null) + * @param clientMacKey the client MAC key + * @param serverMacKey the server MAC key * @param clientCipherKey the client cipher key (or null) * @param clientIv the client initialization vector (or null) * @param serverCipherKey the server cipher key (or null) * @param serverIv the server initialization vector (or null) + * + * @throws NullPointerException if clientMacKey or serverMacKey is null */ public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey, SecretKey clientCipherKey, IvParameterSpec clientIv, SecretKey serverCipherKey, IvParameterSpec serverIv) { - + if ((clientMacKey == null) || (serverMacKey == null)) { + throw new NullPointerException("MAC keys must not be null"); + } this.clientMacKey = clientMacKey; this.serverMacKey = serverMacKey; this.clientCipherKey = clientCipherKey; @@ -137,7 +143,7 @@ public class TlsKeyMaterialSpec implements KeySpec, SecretKey { /** * Returns the client MAC key. * - * @return the client MAC key (or null). + * @return the client MAC key. */ public SecretKey getClientMacKey() { return clientMacKey; @@ -146,7 +152,7 @@ public class TlsKeyMaterialSpec implements KeySpec, SecretKey { /** * Return the server MAC key. * - * @return the server MAC key (or null). + * @return the server MAC key. */ public SecretKey getServerMacKey() { return serverMacKey; diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java b/jdk/src/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java index 14d1708537a..94e731b01f9 100644 --- a/jdk/src/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java +++ b/jdk/src/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2007, 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 @@ -168,22 +168,10 @@ public final class P11TlsKeyMaterialGenerator extends KeyGeneratorSpi { // Note that the MAC keys do not inherit all attributes from the // template, but they do inherit the sensitive/extractable/token // flags, which is all P11Key cares about. - SecretKey clientMacKey, serverMacKey; - - // The MAC size may be zero for GCM mode. - // - // PKCS11 does not support GCM mode as the author made the comment, - // so the macBits is unlikely to be zero. It's only a place holder. - if (macBits != 0) { - clientMacKey = P11Key.secretKey + SecretKey clientMacKey = P11Key.secretKey (session, out.hClientMacSecret, "MAC", macBits, attributes); - serverMacKey = P11Key.secretKey + SecretKey serverMacKey = P11Key.secretKey (session, out.hServerMacSecret, "MAC", macBits, attributes); - } else { - clientMacKey = null; - serverMacKey = null; - } - SecretKey clientCipherKey, serverCipherKey; if (keyBits != 0) { clientCipherKey = P11Key.secretKey(session, out.hClientKey, diff --git a/jdk/src/share/classes/sun/security/ssl/Authenticator.java b/jdk/src/share/classes/sun/security/ssl/Authenticator.java deleted file mode 100644 index a97ce7d5f0c..00000000000 --- a/jdk/src/share/classes/sun/security/ssl/Authenticator.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.security.ssl; - -import java.util.Arrays; - -/** - * This class represents an SSL/TLS message authentication token, - * which encapsulates a sequence number and ensures that attempts to - * delete or reorder messages can be detected. - * - * Each SSL/TLS connection state contains a sequence number, which - * is maintained separately for read and write states. The sequence - * number MUST be set to zero whenever a connection state is made the - * active state. Sequence numbers are of type uint64 and may not - * exceed 2^64-1. Sequence numbers do not wrap. If a SSL/TLS - * implementation would need to wrap a sequence number, it must - * renegotiate instead. A sequence number is incremented after each - * record: specifically, the first record transmitted under a - * particular connection state MUST use sequence number 0. - */ -class Authenticator { - - // byte array containing the additional authentication information for - // each record - private final byte[] block; - - // the block size of SSL v3.0: - // sequence number + record type + + record length - private static final int BLOCK_SIZE_SSL = 8 + 1 + 2; - - // the block size of TLS v1.0 and later: - // sequence number + record type + protocol version + record length - private static final int BLOCK_SIZE_TLS = 8 + 1 + 2 + 2; - - /** - * Default construct, no message authentication token is initialized. - * - * Note that this construct can only be called for null MAC - */ - Authenticator() { - block = new byte[0]; - } - - /** - * Constructs the message authentication token for the specified - * SSL/TLS protocol. - */ - Authenticator(ProtocolVersion protocolVersion) { - if (protocolVersion.v >= ProtocolVersion.TLS10.v) { - block = new byte[BLOCK_SIZE_TLS]; - block[9] = protocolVersion.major; - block[10] = protocolVersion.minor; - } else { - block = new byte[BLOCK_SIZE_SSL]; - } - } - - /** - * Checks whether the sequence number is close to wrap. - * - * Sequence numbers are of type uint64 and may not exceed 2^64-1. - * Sequence numbers do not wrap. When the sequence number is near - * to wrap, we need to close the connection immediately. - * - * @return true if the sequence number is close to wrap - */ - final boolean seqNumOverflow() { - /* - * Conservatively, we don't allow more records to be generated - * when there are only 2^8 sequence numbers left. - */ - return (block.length != 0 && - block[0] == (byte)0xFF && block[1] == (byte)0xFF && - block[2] == (byte)0xFF && block[3] == (byte)0xFF && - block[4] == (byte)0xFF && block[5] == (byte)0xFF && - block[6] == (byte)0xFF); - } - - /** - * Checks whether the sequence number close to renew. - * - * Sequence numbers are of type uint64 and may not exceed 2^64-1. - * Sequence numbers do not wrap. If a TLS - * implementation would need to wrap a sequence number, it must - * renegotiate instead. - * - * @return true if the sequence number is huge enough to renew - */ - final boolean seqNumIsHuge() { - /* - * Conservatively, we should ask for renegotiation when there are - * only 2^48 sequence numbers left. - */ - return (block.length != 0 && - block[0] == (byte)0xFF && block[1] == (byte)0xFF); - } - - /** - * Gets the current sequence number. - * - * @return the byte array of the current sequence number - */ - final byte[] sequenceNumber() { - return Arrays.copyOf(block, 8); - } - - /** - * Acquires the current message authentication information with the - * specified record type and fragment length, and then increases the - * sequence number. - * - * @param type the record type - * @param length the fragment of the record - * @return the byte array of the current message authentication information - */ - final byte[] acquireAuthenticationBytes(byte type, int length) { - byte[] copy = block.clone(); - - if (block.length != 0) { - copy[8] = type; - copy[copy.length - 2] = (byte)(length >> 8); - copy[copy.length - 1] = (byte)(length); - - /* - * Increase the sequence number in the block array - * it is a 64-bit number stored in big-endian format - */ - int k = 7; - while ((k >= 0) && (++block[k] == 0)) { - k--; - } - } - - return copy; - } - -} diff --git a/jdk/src/share/classes/sun/security/ssl/CipherBox.java b/jdk/src/share/classes/sun/security/ssl/CipherBox.java index bce44dabda3..362f9b5d904 100644 --- a/jdk/src/share/classes/sun/security/ssl/CipherBox.java +++ b/jdk/src/share/classes/sun/security/ssl/CipherBox.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,18 +29,15 @@ package sun.security.ssl; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Hashtable; -import java.util.Arrays; import java.security.*; import javax.crypto.*; import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.GCMParameterSpec; import java.nio.*; import sun.security.ssl.CipherSuite.*; import static sun.security.ssl.CipherSuite.*; -import static sun.security.ssl.CipherSuite.CipherType.*; import sun.misc.HexDumpEncoder; @@ -104,41 +101,20 @@ final class CipherBox { // cipher object private final Cipher cipher; + /** + * Cipher blocksize, 0 for stream ciphers + */ + private int blockSize; + /** * secure random */ private SecureRandom random; /** - * fixed IV, the implicit nonce of AEAD cipher suite, only apply to - * AEAD cipher suites + * Is the cipher of CBC mode? */ - private final byte[] fixedIv; - - /** - * the key, reserved only for AEAD cipher initialization - */ - private final Key key; - - /** - * the operation mode, reserved for AEAD cipher initialization - */ - private final int mode; - - /** - * the authentication tag size, only apply to AEAD cipher suites - */ - private final int tagSize; - - /** - * the record IV length, only apply to AEAD cipher suites - */ - private final int recordIvSize; - - /** - * cipher type - */ - private final CipherType cipherType; + private final boolean isCBCMode; /** * Fixed masks of various block size, as the initial decryption IVs @@ -156,13 +132,7 @@ final class CipherBox { private CipherBox() { this.protocolVersion = ProtocolVersion.DEFAULT; this.cipher = null; - this.cipherType = STREAM_CIPHER; - this.fixedIv = new byte[0]; - this.key = null; - this.mode = Cipher.ENCRYPT_MODE; // choose at random - this.random = null; - this.tagSize = 0; - this.recordIvSize = 0; + this.isCBCMode = false; } /** @@ -177,13 +147,13 @@ final class CipherBox { try { this.protocolVersion = protocolVersion; this.cipher = JsseJce.getCipher(bulkCipher.transformation); - this.mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; + int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; if (random == null) { random = JsseJce.getSecureRandom(); } this.random = random; - this.cipherType = bulkCipher.cipherType; + this.isCBCMode = bulkCipher.isCBCMode; /* * RFC 4346 recommends two algorithms used to generated the @@ -201,40 +171,14 @@ final class CipherBox { iv = getFixedMask(bulkCipher.ivSize); } - if (cipherType == AEAD_CIPHER) { - // AEAD must completely initialize the cipher for each packet, - // and so we save initialization parameters for packet - // processing time. + cipher.init(mode, key, iv, random); - // Set the tag size for AEAD cipher - tagSize = bulkCipher.tagSize; - - // Reserve the key for AEAD cipher initialization - this.key = key; - - fixedIv = iv.getIV(); - if (fixedIv == null || - fixedIv.length != bulkCipher.fixedIvSize) { - throw new RuntimeException("Improper fixed IV for AEAD"); - } - - // Set the record IV length for AEAD cipher - recordIvSize = bulkCipher.ivSize - bulkCipher.fixedIvSize; - - // DON'T initialize the cipher for AEAD! - } else { - // CBC only requires one initialization during its lifetime - // (future packets/IVs set the proper CBC state), so we can - // initialize now. - - // Zeroize the variables that only apply to AEAD cipher - this.tagSize = 0; - this.fixedIv = new byte[0]; - this.recordIvSize = 0; - this.key = null; - - // Initialize the cipher - cipher.init(mode, key, iv, random); + // Do not call getBlockSize until after init() + // otherwise we would disrupt JCE delayed provider selection + blockSize = cipher.getBlockSize(); + // some providers implement getBlockSize() incorrectly + if (blockSize == 1) { + blockSize = 0; } } catch (NoSuchAlgorithmException e) { throw e; @@ -291,11 +235,26 @@ final class CipherBox { } try { - int blockSize = cipher.getBlockSize(); - if (cipherType == BLOCK_CIPHER) { + if (blockSize != 0) { + // TLSv1.1 needs a IV block + if (protocolVersion.v >= ProtocolVersion.TLS11.v) { + // generate a random number + byte[] prefix = new byte[blockSize]; + random.nextBytes(prefix); + + // move forward the plaintext + System.arraycopy(buf, offset, + buf, offset + prefix.length, len); + + // prefix the plaintext + System.arraycopy(prefix, 0, + buf, offset, prefix.length); + + len += prefix.length; + } + len = addPadding(buf, offset, len, blockSize); } - if (debug != null && Debug.isOn("plaintext")) { try { HexDumpEncoder hd = new HexDumpEncoder(); @@ -308,28 +267,14 @@ final class CipherBox { System.out); } catch (IOException e) { } } - - - if (cipherType == AEAD_CIPHER) { - try { - return cipher.doFinal(buf, offset, len, buf, offset); - } catch (IllegalBlockSizeException | BadPaddingException ibe) { - // unlikely to happen - throw new RuntimeException( - "Cipher error in AEAD mode in JCE provider " + - cipher.getProvider().getName(), ibe); - } - } else { - int newLen = cipher.update(buf, offset, len, buf, offset); - if (newLen != len) { - // catch BouncyCastle buffering error - throw new RuntimeException("Cipher buffering error " + - "in JCE provider " + cipher.getProvider().getName()); - } - return newLen; + int newLen = cipher.update(buf, offset, len, buf, offset); + if (newLen != len) { + // catch BouncyCastle buffering error + throw new RuntimeException("Cipher buffering error " + + "in JCE provider " + cipher.getProvider().getName()); } + return newLen; } catch (ShortBufferException e) { - // unlikely to happen, we should have enough buffer space here throw new ArrayIndexOutOfBoundsException(e.toString()); } } @@ -343,7 +288,7 @@ final class CipherBox { * set to last position padded/encrypted. The limit may have changed * because of the added padding bytes. */ - int encrypt(ByteBuffer bb, int outLimit) { + int encrypt(ByteBuffer bb) { int len = bb.remaining(); @@ -352,71 +297,66 @@ final class CipherBox { return len; } - int pos = bb.position(); + try { + int pos = bb.position(); - int blockSize = cipher.getBlockSize(); - if (cipherType == BLOCK_CIPHER) { - // addPadding adjusts pos/limit - len = addPadding(bb, blockSize); - bb.position(pos); - } + if (blockSize != 0) { + // TLSv1.1 needs a IV block + if (protocolVersion.v >= ProtocolVersion.TLS11.v) { + // generate a random number + byte[] prefix = new byte[blockSize]; + random.nextBytes(prefix); - if (debug != null && Debug.isOn("plaintext")) { - try { - HexDumpEncoder hd = new HexDumpEncoder(); - - System.out.println( - "Padded plaintext before ENCRYPTION: len = " - + len); - hd.encodeBuffer(bb.duplicate(), System.out); - - } catch (IOException e) { } - } - - /* - * Encrypt "in-place". This does not add its own padding. - */ - ByteBuffer dup = bb.duplicate(); - if (cipherType == AEAD_CIPHER) { - try { - int outputSize = cipher.getOutputSize(dup.remaining()); - if (outputSize > bb.remaining()) { - // need to expand the limit of the output buffer for - // the authentication tag. - // - // DON'T worry about the buffer's capacity, we have - // reserved space for the authentication tag. - if (outLimit < pos + outputSize) { - // unlikely to happen - throw new ShortBufferException( - "need more space in output buffer"); + // move forward the plaintext + byte[] buf = null; + int limit = bb.limit(); + if (bb.hasArray()) { + int arrayOffset = bb.arrayOffset(); + buf = bb.array(); + System.arraycopy(buf, arrayOffset + pos, + buf, arrayOffset + pos + prefix.length, + limit - pos); + bb.limit(limit + prefix.length); + } else { + buf = new byte[limit - pos]; + bb.get(buf, 0, limit - pos); + bb.position(pos + prefix.length); + bb.limit(limit + prefix.length); + bb.put(buf); } - bb.limit(pos + outputSize); + bb.position(pos); + + // prefix the plaintext + bb.put(prefix); + bb.position(pos); } - int newLen = cipher.doFinal(dup, bb); - if (newLen != outputSize) { - throw new RuntimeException( - "Cipher buffering error in JCE provider " + - cipher.getProvider().getName()); - } - return newLen; - } catch (IllegalBlockSizeException | - BadPaddingException | ShortBufferException ibse) { - // unlikely to happen - throw new RuntimeException( - "Cipher error in AEAD mode in JCE provider " + - cipher.getProvider().getName(), ibse); + + // addPadding adjusts pos/limit + len = addPadding(bb, blockSize); + bb.position(pos); } - } else { - int newLen; - try { - newLen = cipher.update(dup, bb); - } catch (ShortBufferException sbe) { - // unlikely to happen - throw new RuntimeException("Cipher buffering error " + - "in JCE provider " + cipher.getProvider().getName()); + if (debug != null && Debug.isOn("plaintext")) { + try { + HexDumpEncoder hd = new HexDumpEncoder(); + + System.out.println( + "Padded plaintext before ENCRYPTION: len = " + + len); + hd.encodeBuffer(bb, System.out); + + } catch (IOException e) { } + /* + * reset back to beginning + */ + bb.position(pos); } + /* + * Encrypt "in-place". This does not add its own padding. + */ + ByteBuffer dup = bb.duplicate(); + int newLen = cipher.update(dup, bb); + if (bb.position() != dup.position()) { throw new RuntimeException("bytebuffer padding error"); } @@ -427,6 +367,10 @@ final class CipherBox { "in JCE provider " + cipher.getProvider().getName()); } return newLen; + } catch (ShortBufferException e) { + RuntimeException exc = new RuntimeException(e.toString()); + exc.initCause(e); + throw exc; } } @@ -454,23 +398,11 @@ final class CipherBox { } try { - int newLen; - if (cipherType == AEAD_CIPHER) { - try { - newLen = cipher.doFinal(buf, offset, len, buf, offset); - } catch (IllegalBlockSizeException ibse) { - // unlikely to happen - throw new RuntimeException( - "Cipher error in AEAD mode in JCE provider " + - cipher.getProvider().getName(), ibse); - } - } else { - newLen = cipher.update(buf, offset, len, buf, offset); - if (newLen != len) { - // catch BouncyCastle buffering error - throw new RuntimeException("Cipher buffering error " + - "in JCE provider " + cipher.getProvider().getName()); - } + int newLen = cipher.update(buf, offset, len, buf, offset); + if (newLen != len) { + // catch BouncyCastle buffering error + throw new RuntimeException("Cipher buffering error " + + "in JCE provider " + cipher.getProvider().getName()); } if (debug != null && Debug.isOn("plaintext")) { try { @@ -484,9 +416,7 @@ final class CipherBox { System.out); } catch (IOException e) { } } - - if (cipherType == BLOCK_CIPHER) { - int blockSize = cipher.getBlockSize(); + if (blockSize != 0) { newLen = removePadding(buf, offset, newLen, blockSize, protocolVersion); @@ -494,11 +424,16 @@ final class CipherBox { if (newLen < blockSize) { throw new BadPaddingException("invalid explicit IV"); } + + // discards the first cipher block, the IV component. + System.arraycopy(buf, offset + blockSize, + buf, offset, newLen - blockSize); + + newLen -= blockSize; } } return newLen; } catch (ShortBufferException e) { - // unlikely to happen, we should have enough buffer space here throw new ArrayIndexOutOfBoundsException(e.toString()); } } @@ -528,29 +463,15 @@ final class CipherBox { */ int pos = bb.position(); ByteBuffer dup = bb.duplicate(); - int newLen; - if (cipherType == AEAD_CIPHER) { - try { - newLen = cipher.doFinal(dup, bb); - } catch (IllegalBlockSizeException ibse) { - // unlikely to happen - throw new RuntimeException( - "Cipher error in AEAD mode \"" + ibse.getMessage() + - " \"in JCE provider " + cipher.getProvider().getName()); - } - } else { - newLen = cipher.update(dup, bb); - if (newLen != len) { - // catch BouncyCastle buffering error - throw new RuntimeException("Cipher buffering error " + - "in JCE provider " + cipher.getProvider().getName()); - } + int newLen = cipher.update(dup, bb); + if (newLen != len) { + // catch BouncyCastle buffering error + throw new RuntimeException("Cipher buffering error " + + "in JCE provider " + cipher.getProvider().getName()); } - // reset the limit to the end of the decryted data - bb.limit(pos + newLen); - if (debug != null && Debug.isOn("plaintext")) { + bb.position(pos); try { HexDumpEncoder hd = new HexDumpEncoder(); @@ -558,33 +479,50 @@ final class CipherBox { "Padded plaintext after DECRYPTION: len = " + newLen); - hd.encodeBuffer( - (ByteBuffer)bb.duplicate().position(pos), System.out); + hd.encodeBuffer(bb, System.out); } catch (IOException e) { } } /* * Remove the block padding. */ - if (cipherType == BLOCK_CIPHER) { - int blockSize = cipher.getBlockSize(); + if (blockSize != 0) { bb.position(pos); newLen = removePadding(bb, blockSize, protocolVersion); - // check the explicit IV of TLS v1.1 or later if (protocolVersion.v >= ProtocolVersion.TLS11.v) { if (newLen < blockSize) { throw new BadPaddingException("invalid explicit IV"); } + // discards the first cipher block, the IV component. + byte[] buf = null; + int limit = bb.limit(); + if (bb.hasArray()) { + int arrayOffset = bb.arrayOffset(); + buf = bb.array(); + System.arraycopy(buf, arrayOffset + pos + blockSize, + buf, arrayOffset + pos, limit - pos - blockSize); + bb.limit(limit - blockSize); + } else { + buf = new byte[limit - pos - blockSize]; + bb.position(pos + blockSize); + bb.get(buf); + bb.position(pos); + bb.put(buf); + bb.limit(limit - blockSize); + } + // reset the position to the end of the decrypted data - bb.position(bb.limit()); + limit = bb.limit(); + bb.position(limit); } } return newLen; } catch (ShortBufferException e) { - // unlikely to happen, we should have enough buffer space here - throw new ArrayIndexOutOfBoundsException(e.toString()); + RuntimeException exc = new RuntimeException(e.toString()); + exc.initCause(e); + throw exc; } } @@ -757,8 +695,8 @@ final class CipherBox { // ignore return value. cipher.doFinal(); } - } catch (Exception e) { - // swallow all types of exceptions. + } catch (GeneralSecurityException e) { + // swallow for now. } } @@ -768,234 +706,6 @@ final class CipherBox { * @return true if the cipher use CBC mode, false otherwise. */ boolean isCBCMode() { - return cipherType == BLOCK_CIPHER; - } - - /* - * Does the cipher use AEAD mode? - * - * @return true if the cipher use AEAD mode, false otherwise. - */ - boolean isAEADMode() { - return cipherType == AEAD_CIPHER; - } - - /* - * Is the cipher null? - * - * @return true if the cipher is null, false otherwise. - */ - boolean isNullCipher() { - return cipher == null; - } - - /* - * Gets the explicit nonce/IV size of the cipher. - * - * The returned value is the SecurityParameters.record_iv_length in - * RFC 4346/5246. It is the size of explicit IV for CBC mode, and the - * size of explicit nonce for AEAD mode. - * - * @return the explicit nonce size of the cipher. - */ - int getExplicitNonceSize() { - switch (cipherType) { - case BLOCK_CIPHER: - // For block ciphers, the explicit IV length is of length - // SecurityParameters.record_iv_length, which is equal to - // the SecurityParameters.block_size. - if (protocolVersion.v >= ProtocolVersion.TLS11.v) { - return cipher.getBlockSize(); - } - break; - case AEAD_CIPHER: - return recordIvSize; - // It is also the length of sequence number, which is - // used as the nonce_explicit for AEAD cipher suites. - } - - return 0; - } - - /* - * Applies the explicit nonce/IV to this cipher. This method is used to - * decrypt an SSL/TLS input record. - * - * The returned value is the SecurityParameters.record_iv_length in - * RFC 4346/5246. It is the size of explicit IV for CBC mode, and the - * size of explicit nonce for AEAD mode. - * - * @param authenticator the authenticator to get the additional - * authentication data - * @param contentType the content type of the input record - * @param bb the byte buffer to get the explicit nonce from - * - * @return the explicit nonce size of the cipher. - */ - int applyExplicitNonce(Authenticator authenticator, byte contentType, - ByteBuffer bb) throws BadPaddingException { - switch (cipherType) { - case BLOCK_CIPHER: - // For block ciphers, the explicit IV length is of length - // SecurityParameters.record_iv_length, which is equal to - // the SecurityParameters.block_size. - if (protocolVersion.v >= ProtocolVersion.TLS11.v) { - return cipher.getBlockSize(); - } - break; - case AEAD_CIPHER: - if (bb.remaining() < (recordIvSize + tagSize)) { - throw new BadPaddingException( - "invalid AEAD cipher fragment"); - } - - // initialize the AEAD cipher for the unique IV - byte[] iv = Arrays.copyOf(fixedIv, - fixedIv.length + recordIvSize); - bb.get(iv, fixedIv.length, recordIvSize); - bb.position(bb.position() - recordIvSize); - GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv); - try { - cipher.init(mode, key, spec, random); - } catch (InvalidKeyException | - InvalidAlgorithmParameterException ikae) { - // unlikely to happen - throw new RuntimeException( - "invalid key or spec in GCM mode", ikae); - } - - // update the additional authentication data - byte[] aad = authenticator.acquireAuthenticationBytes( - contentType, bb.remaining() - recordIvSize - tagSize); - cipher.updateAAD(aad); - - return recordIvSize; - // It is also the length of sequence number, which is - // used as the nonce_explicit for AEAD cipher suites. - } - - return 0; - } - - /* - * Applies the explicit nonce/IV to this cipher. This method is used to - * decrypt an SSL/TLS input record. - * - * The returned value is the SecurityParameters.record_iv_length in - * RFC 4346/5246. It is the size of explicit IV for CBC mode, and the - * size of explicit nonce for AEAD mode. - * - * @param authenticator the authenticator to get the additional - * authentication data - * @param contentType the content type of the input record - * @param buf the byte array to get the explicit nonce from - * @param offset the offset of the byte buffer - * @param cipheredLength the ciphered fragment length of the output - * record, it is the TLSCiphertext.length in RFC 4346/5246. - * - * @return the explicit nonce size of the cipher. - */ - int applyExplicitNonce(Authenticator authenticator, - byte contentType, byte[] buf, int offset, - int cipheredLength) throws BadPaddingException { - - ByteBuffer bb = ByteBuffer.wrap(buf, offset, cipheredLength); - - return applyExplicitNonce(authenticator, contentType, bb); - } - - /* - * Creates the explicit nonce/IV to this cipher. This method is used to - * encrypt an SSL/TLS output record. - * - * The size of the returned array is the SecurityParameters.record_iv_length - * in RFC 4346/5246. It is the size of explicit IV for CBC mode, and the - * size of explicit nonce for AEAD mode. - * - * @param authenticator the authenticator to get the additional - * authentication data - * @param contentType the content type of the input record - * @param fragmentLength the fragment length of the output record, it is - * the TLSCompressed.length in RFC 4346/5246. - * - * @return the explicit nonce of the cipher. - */ - byte[] createExplicitNonce(Authenticator authenticator, - byte contentType, int fragmentLength) { - - byte[] nonce = new byte[0]; - switch (cipherType) { - case BLOCK_CIPHER: - if (protocolVersion.v >= ProtocolVersion.TLS11.v) { - // For block ciphers, the explicit IV length is of length - // SecurityParameters.record_iv_length, which is equal to - // the SecurityParameters.block_size. - // - // Generate a random number as the explicit IV parameter. - nonce = new byte[cipher.getBlockSize()]; - random.nextBytes(nonce); - } - break; - case AEAD_CIPHER: - // To be unique and aware of overflow-wrap, sequence number - // is used as the nonce_explicit of AEAD cipher suites. - nonce = authenticator.sequenceNumber(); - - // initialize the AEAD cipher for the unique IV - byte[] iv = Arrays.copyOf(fixedIv, - fixedIv.length + nonce.length); - System.arraycopy(nonce, 0, iv, fixedIv.length, nonce.length); - GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv); - try { - cipher.init(mode, key, spec, random); - } catch (InvalidKeyException | - InvalidAlgorithmParameterException ikae) { - // unlikely to happen - throw new RuntimeException( - "invalid key or spec in GCM mode", ikae); - } - - // update the additional authentication data - byte[] aad = authenticator.acquireAuthenticationBytes( - contentType, fragmentLength); - cipher.updateAAD(aad); - break; - } - - return nonce; - } - - /* - * Is this cipher available? - * - * This method can only be called by CipherSuite.BulkCipher.isAvailable() - * to test the availability of a cipher suites. Please DON'T use it in - * other places, otherwise, the behavior may be unexpected because we may - * initialize AEAD cipher improperly in the method. - */ - Boolean isAvailable() { - // We won't know whether a cipher for a particular key size is - // available until the cipher is successfully initialized. - // - // We do not initialize AEAD cipher in the constructor. Need to - // initialize the cipher to ensure that the AEAD mode for a - // particular key size is supported. - if (cipherType == AEAD_CIPHER) { - try { - Authenticator authenticator = - new Authenticator(protocolVersion); - byte[] nonce = authenticator.sequenceNumber(); - byte[] iv = Arrays.copyOf(fixedIv, - fixedIv.length + nonce.length); - System.arraycopy(nonce, 0, iv, fixedIv.length, nonce.length); - GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv); - - cipher.init(mode, key, spec, random); - } catch (Exception e) { - return Boolean.FALSE; - } - } // Otherwise, we have initialized the cipher in the constructor. - - return Boolean.TRUE; + return isCBCMode; } } diff --git a/jdk/src/share/classes/sun/security/ssl/CipherSuite.java b/jdk/src/share/classes/sun/security/ssl/CipherSuite.java index 435693751c7..555304880b7 100644 --- a/jdk/src/share/classes/sun/security/ssl/CipherSuite.java +++ b/jdk/src/share/classes/sun/security/ssl/CipherSuite.java @@ -33,14 +33,12 @@ import java.security.InvalidKeyException; import java.security.SecureRandom; import java.security.KeyManagementException; -import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import static sun.security.ssl.CipherSuite.KeyExchange.*; import static sun.security.ssl.CipherSuite.PRF.*; -import static sun.security.ssl.CipherSuite.CipherType.*; import static sun.security.ssl.JsseJce.*; /** @@ -137,9 +135,7 @@ final class CipherSuite implements Comparable<CipherSuite> { this.keyExchange = keyExchange; this.cipher = cipher; this.exportable = cipher.exportable; - if (cipher.cipherType == CipherType.AEAD_CIPHER) { - macAlg = M_NULL; - } else if (name.endsWith("_MD5")) { + if (name.endsWith("_MD5")) { macAlg = M_MD5; } else if (name.endsWith("_SHA")) { macAlg = M_SHA; @@ -389,12 +385,6 @@ final class CipherSuite implements Comparable<CipherSuite> { } } - static enum CipherType { - STREAM_CIPHER, // null or stream cipher - BLOCK_CIPHER, // block cipher in CBC mode - AEAD_CIPHER // AEAD cipher - } - /** * An SSL/TLS bulk cipher algorithm. One instance per combination of * cipher and key length. @@ -427,26 +417,14 @@ final class CipherSuite implements Comparable<CipherSuite> { // for non-exportable ciphers, this is the same as keySize final int expandedKeySize; - // size of the IV + // size of the IV (also block size) final int ivSize; - // size of fixed IV - // - // record_iv_length = ivSize - fixedIvSize - final int fixedIvSize; - // exportable under 512/40 bit rules final boolean exportable; // Is the cipher algorithm of Cipher Block Chaining (CBC) mode? - final CipherType cipherType; - - // size of the authentication tag, only applicable to cipher suites in - // Galois Counter Mode (GCM) - // - // As far as we know, all supported GCM cipher suites use 128-bits - // authentication tags. - final int tagSize = 16; + final boolean isCBCMode; // The secure random used to detect the cipher availability. private final static SecureRandom secureRandom; @@ -459,34 +437,32 @@ final class CipherSuite implements Comparable<CipherSuite> { } } - BulkCipher(String transformation, CipherType cipherType, int keySize, - int expandedKeySize, int ivSize, - int fixedIvSize, boolean allowed) { - + BulkCipher(String transformation, int keySize, + int expandedKeySize, int ivSize, boolean allowed) { this.transformation = transformation; String[] splits = transformation.split("/"); this.algorithm = splits[0]; - this.cipherType = cipherType; + this.isCBCMode = + splits.length <= 1 ? false : "CBC".equalsIgnoreCase(splits[1]); this.description = this.algorithm + "/" + (keySize << 3); this.keySize = keySize; this.ivSize = ivSize; - this.fixedIvSize = fixedIvSize; this.allowed = allowed; this.expandedKeySize = expandedKeySize; this.exportable = true; } - BulkCipher(String transformation, CipherType cipherType, int keySize, - int ivSize, int fixedIvSize, boolean allowed) { + BulkCipher(String transformation, int keySize, + int ivSize, boolean allowed) { this.transformation = transformation; String[] splits = transformation.split("/"); this.algorithm = splits[0]; - this.cipherType = cipherType; + this.isCBCMode = + splits.length <= 1 ? false : "CBC".equalsIgnoreCase(splits[1]); this.description = this.algorithm + "/" + (keySize << 3); this.keySize = keySize; this.ivSize = ivSize; - this.fixedIvSize = fixedIvSize; this.allowed = allowed; this.expandedKeySize = keySize; @@ -510,20 +486,16 @@ final class CipherSuite implements Comparable<CipherSuite> { * Test if this bulk cipher is available. For use by CipherSuite. * * Currently all supported ciphers except AES are always available - * via the JSSE internal implementations. We also assume AES/128 of - * CBC mode is always available since it is shipped with the SunJCE - * provider. However, AES/256 is unavailable when the default JCE - * policy jurisdiction files are installed because of key length - * restrictions, and AEAD is unavailable when the underlying providers - * do not support AEAD/GCM mode. + * via the JSSE internal implementations. We also assume AES/128 + * is always available since it is shipped with the SunJCE provider. + * However, AES/256 is unavailable when the default JCE policy + * jurisdiction files are installed because of key length restrictions. */ boolean isAvailable() { if (allowed == false) { return false; } - - if ((this == B_AES_256) || - (this.cipherType == CipherType.AEAD_CIPHER)) { + if (this == B_AES_256) { return isAvailable(this); } @@ -541,50 +513,19 @@ final class CipherSuite implements Comparable<CipherSuite> { private static synchronized boolean isAvailable(BulkCipher cipher) { Boolean b = availableCache.get(cipher); if (b == null) { - int keySizeInBits = cipher.keySize * 8; - if (keySizeInBits > 128) { // need the JCE unlimited - // strength jurisdiction policy - try { - if (Cipher.getMaxAllowedKeyLength( - cipher.transformation) < keySizeInBits) { - b = Boolean.FALSE; - } - } catch (Exception e) { - b = Boolean.FALSE; - } - } - - if (b == null) { - b = Boolean.FALSE; // may be reset to TRUE if - // the cipher is available - CipherBox temporary = null; - try { - SecretKey key = new SecretKeySpec( - new byte[cipher.expandedKeySize], - cipher.algorithm); - IvParameterSpec iv; - if (cipher.cipherType == CipherType.AEAD_CIPHER) { - iv = new IvParameterSpec( - new byte[cipher.fixedIvSize]); - } else { - iv = new IvParameterSpec(new byte[cipher.ivSize]); - } - temporary = cipher.newCipher( - ProtocolVersion.DEFAULT, + try { + SecretKey key = new SecretKeySpec + (new byte[cipher.expandedKeySize], cipher.algorithm); + IvParameterSpec iv = + new IvParameterSpec(new byte[cipher.ivSize]); + cipher.newCipher(ProtocolVersion.DEFAULT, key, iv, secureRandom, true); - b = temporary.isAvailable(); - } catch (NoSuchAlgorithmException e) { - // not available - } finally { - if (temporary != null) { - temporary.dispose(); - } - } + b = Boolean.TRUE; + } catch (NoSuchAlgorithmException e) { + b = Boolean.FALSE; } - availableCache.put(cipher, b); } - return b.booleanValue(); } @@ -632,31 +573,27 @@ final class CipherSuite implements Comparable<CipherSuite> { // export strength ciphers final static BulkCipher B_NULL = - new BulkCipher("NULL", STREAM_CIPHER, 0, 0, 0, 0, true); + new BulkCipher("NULL", 0, 0, 0, true); final static BulkCipher B_RC4_40 = - new BulkCipher(CIPHER_RC4, STREAM_CIPHER, 5, 16, 0, 0, true); + new BulkCipher(CIPHER_RC4, 5, 16, 0, true); final static BulkCipher B_RC2_40 = - new BulkCipher("RC2", BLOCK_CIPHER, 5, 16, 8, 0, false); + new BulkCipher("RC2", 5, 16, 8, false); final static BulkCipher B_DES_40 = - new BulkCipher(CIPHER_DES, BLOCK_CIPHER, 5, 8, 8, 0, true); + new BulkCipher(CIPHER_DES, 5, 8, 8, true); // domestic strength ciphers final static BulkCipher B_RC4_128 = - new BulkCipher(CIPHER_RC4, STREAM_CIPHER, 16, 0, 0, true); + new BulkCipher(CIPHER_RC4, 16, 0, true); final static BulkCipher B_DES = - new BulkCipher(CIPHER_DES, BLOCK_CIPHER, 8, 8, 0, true); + new BulkCipher(CIPHER_DES, 8, 8, true); final static BulkCipher B_3DES = - new BulkCipher(CIPHER_3DES, BLOCK_CIPHER, 24, 8, 0, true); + new BulkCipher(CIPHER_3DES, 24, 8, true); final static BulkCipher B_IDEA = - new BulkCipher("IDEA", BLOCK_CIPHER, 16, 8, 0, false); + new BulkCipher("IDEA", 16, 8, false); final static BulkCipher B_AES_128 = - new BulkCipher(CIPHER_AES, BLOCK_CIPHER, 16, 16, 0, true); + new BulkCipher(CIPHER_AES, 16, 16, true); final static BulkCipher B_AES_256 = - new BulkCipher(CIPHER_AES, BLOCK_CIPHER, 32, 16, 0, true); - final static BulkCipher B_AES_128_GCM = - new BulkCipher(CIPHER_AES_GCM, AEAD_CIPHER, 16, 12, 4, true); - final static BulkCipher B_AES_256_GCM = - new BulkCipher(CIPHER_AES_GCM, AEAD_CIPHER, 32, 12, 4, true); + new BulkCipher(CIPHER_AES, 32, 16, true); // MACs final static MacAlg M_NULL = new MacAlg("NULL", 0); @@ -956,12 +893,11 @@ final class CipherSuite implements Comparable<CipherSuite> { * Definition of the CipherSuites that are enabled by default. * They are listed in preference order, most preferred first, using * the following criteria: - * 1. Prefer Suite B compliant cipher suites, see RFC6460. - * 2. Prefer the stronger bulk cipher, in the order of AES_256(GCM), - * AES_128(GCM), AES_256, AES_128, RC-4, 3DES-EDE. - * 3. Prefer the stronger MAC algorithm, in the order of SHA384, + * 1. Prefer the stronger buld cipher, in the order of AES_256, + * AES_128, RC-4, 3DES-EDE. + * 2. Prefer the stronger MAC algorithm, in the order of SHA384, * SHA256, SHA, MD5. - * 4. Prefer the better performance of key exchange and digital + * 3. Prefer the better performance of key exchange and digital * signature algorithm, in the order of ECDHE-ECDSA, ECDHE-RSA, * RSA, ECDH-ECDSA, ECDH-RSA, DHE-RSA, DHE-DSS. */ @@ -974,16 +910,6 @@ final class CipherSuite implements Comparable<CipherSuite> { // ID Key Exchange Cipher A obs suprt PRF // ====== ============ ========= = === ===== ======== - - - // Placeholder for cipher suites in GCM mode. - // - // For better compatibility and interoperability, we decrease the - // priority of cipher suites in GCM mode for a while as GCM - // technologies mature in the industry. Eventually we'll move - // the GCM suites here. - - // AES_256(CBC) add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", 0xc024, --p, K_ECDHE_ECDSA, B_AES_256, T, max, tls12, P_SHA384); add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", @@ -1014,7 +940,6 @@ final class CipherSuite implements Comparable<CipherSuite> { add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", 0x0038, --p, K_DHE_DSS, B_AES_256, T); - // AES_128(CBC) add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 0xc023, --p, K_ECDHE_ECDSA, B_AES_128, T, max, tls12, P_SHA256); add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", @@ -1045,7 +970,6 @@ final class CipherSuite implements Comparable<CipherSuite> { add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", 0x0032, --p, K_DHE_DSS, B_AES_128, T); - // RC-4 add("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 0xC007, --p, K_ECDHE_ECDSA, B_RC4_128, N); add("TLS_ECDHE_RSA_WITH_RC4_128_SHA", @@ -1057,51 +981,6 @@ final class CipherSuite implements Comparable<CipherSuite> { add("TLS_ECDH_RSA_WITH_RC4_128_SHA", 0xC00C, --p, K_ECDH_RSA, B_RC4_128, N); - // Cipher suites in GCM mode, see RFC 5288/5289. - // - // We may increase the priority of cipher suites in GCM mode when - // GCM technologies become mature in the industry. - - // Suite B compliant cipher suites, see RFC 6460. - // - // Note that, at present this provider is not Suite B compliant. The - // preference order of the GCM cipher suites does not follow the spec - // of RFC 6460. - add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", - 0xc02c, --p, K_ECDHE_ECDSA, B_AES_256_GCM, T, max, tls12, P_SHA384); - add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", - 0xc02b, --p, K_ECDHE_ECDSA, B_AES_128_GCM, T, max, tls12, P_SHA256); - - // AES_256(GCM) - add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", - 0xc030, --p, K_ECDHE_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); - add("TLS_RSA_WITH_AES_256_GCM_SHA384", - 0x009d, --p, K_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); - add("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", - 0xc02e, --p, K_ECDH_ECDSA, B_AES_256_GCM, T, max, tls12, P_SHA384); - add("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", - 0xc032, --p, K_ECDH_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); - add("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", - 0x009f, --p, K_DHE_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); - add("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", - 0x00a3, --p, K_DHE_DSS, B_AES_256_GCM, T, max, tls12, P_SHA384); - - // AES_128(GCM) - add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - 0xc02f, --p, K_ECDHE_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); - add("TLS_RSA_WITH_AES_128_GCM_SHA256", - 0x009c, --p, K_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); - add("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", - 0xc02d, --p, K_ECDH_ECDSA, B_AES_128_GCM, T, max, tls12, P_SHA256); - add("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", - 0xc031, --p, K_ECDH_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); - add("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", - 0x009e, --p, K_DHE_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); - add("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", - 0x00a2, --p, K_DHE_DSS, B_AES_128_GCM, T, max, tls12, P_SHA256); - // End of cipher suites in GCM mode. - - // 3DES_EDE add("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xC008, --p, K_ECDHE_ECDSA, B_3DES, T); add("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", @@ -1145,22 +1024,17 @@ final class CipherSuite implements Comparable<CipherSuite> { */ p = DEFAULT_SUITES_PRIORITY; - add("TLS_DH_anon_WITH_AES_256_GCM_SHA384", - 0x00a7, --p, K_DH_ANON, B_AES_256_GCM, N, max, tls12, P_SHA384); - add("TLS_DH_anon_WITH_AES_128_GCM_SHA256", - 0x00a6, --p, K_DH_ANON, B_AES_128_GCM, N, max, tls12, P_SHA256); - add("TLS_DH_anon_WITH_AES_256_CBC_SHA256", 0x006d, --p, K_DH_ANON, B_AES_256, N, max, tls12, P_SHA256); add("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", - 0xC019, --p, K_ECDH_ANON, B_AES_256, N); + 0xC019, --p, K_ECDH_ANON, B_AES_256, T); add("TLS_DH_anon_WITH_AES_256_CBC_SHA", 0x003a, --p, K_DH_ANON, B_AES_256, N); add("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x006c, --p, K_DH_ANON, B_AES_128, N, max, tls12, P_SHA256); add("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", - 0xC018, --p, K_ECDH_ANON, B_AES_128, N); + 0xC018, --p, K_ECDH_ANON, B_AES_128, T); add("TLS_DH_anon_WITH_AES_128_CBC_SHA", 0x0034, --p, K_DH_ANON, B_AES_128, N); @@ -1170,7 +1044,7 @@ final class CipherSuite implements Comparable<CipherSuite> { 0x0018, --p, K_DH_ANON, B_RC4_128, N); add("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", - 0xC017, --p, K_ECDH_ANON, B_3DES, N); + 0xC017, --p, K_ECDH_ANON, B_3DES, T); add("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", 0x001b, --p, K_DH_ANON, B_3DES, N); @@ -1325,10 +1199,18 @@ final class CipherSuite implements Comparable<CipherSuite> { add("TLS_DH_RSA_WITH_AES_256_CBC_SHA256", 0x0069); // Unsupported cipher suites from RFC 5288 + add("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x009c); + add("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x009d); + add("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x009e); + add("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x009f); add("TLS_DH_RSA_WITH_AES_128_GCM_SHA256", 0x00a0); add("TLS_DH_RSA_WITH_AES_256_GCM_SHA384", 0x00a1); + add("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x00a2); + add("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x00a3); add("TLS_DH_DSS_WITH_AES_128_GCM_SHA256", 0x00a4); add("TLS_DH_DSS_WITH_AES_256_GCM_SHA384", 0x00a5); + add("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x00a6); + add("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x00a7); // Unsupported cipher suites from RFC 5487 add("TLS_PSK_WITH_AES_128_GCM_SHA256", 0x00a8); @@ -1387,6 +1269,16 @@ final class CipherSuite implements Comparable<CipherSuite> { add("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", 0xc021); add("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", 0xc022); + // Unsupported cipher suites from RFC 5289 + add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02b); + add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02c); + add("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02d); + add("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02e); + add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0xc02f); + add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0xc030); + add("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0xc031); + add("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0xc032); + // Unsupported cipher suites from RFC 5489 add("TLS_ECDHE_PSK_WITH_RC4_128_SHA", 0xc033); add("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", 0xc034); diff --git a/jdk/src/share/classes/sun/security/ssl/EngineInputRecord.java b/jdk/src/share/classes/sun/security/ssl/EngineInputRecord.java index 0464d5b5de9..6b064385203 100644 --- a/jdk/src/share/classes/sun/security/ssl/EngineInputRecord.java +++ b/jdk/src/share/classes/sun/security/ssl/EngineInputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2007, 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 @@ -177,6 +177,71 @@ final class EngineInputRecord extends InputRecord { return len; } + /* + * Verifies and removes the MAC value. Returns true if + * the MAC checks out OK. + * + * On entry: + * position = beginning of app/MAC data + * limit = end of MAC data. + * + * On return: + * position = beginning of app data + * limit = end of app data + */ + boolean checkMAC(MAC signer, ByteBuffer bb) { + if (internalData) { + return checkMAC(signer); + } + + int len = signer.MAClen(); + if (len == 0) { // no mac + return true; + } + + /* + * Grab the original limit + */ + int lim = bb.limit(); + + /* + * Delineate the area to apply a MAC on. + */ + int macData = lim - len; + bb.limit(macData); + + byte[] mac = signer.compute(contentType(), bb); + + if (len != mac.length) { + throw new RuntimeException("Internal MAC error"); + } + + /* + * Delineate the MAC values, position was already set + * by doing the compute above. + * + * We could zero the MAC area, but not much useful information + * there anyway. + */ + bb.position(macData); + bb.limit(lim); + + try { + for (int i = 0; i < len; i++) { + if (bb.get() != mac[i]) { // No BB.equals(byte []); ! + return false; + } + } + return true; + } finally { + /* + * Position to the data. + */ + bb.rewind(); + bb.limit(macData); + } + } + /* * Pass the data down if it's internally cached, otherwise * do it here. @@ -186,85 +251,16 @@ final class EngineInputRecord extends InputRecord { * If external data(app), return a new ByteBuffer with data to * process. */ - ByteBuffer decrypt(Authenticator authenticator, - CipherBox box, ByteBuffer bb) throws BadPaddingException { + ByteBuffer decrypt(CipherBox box, ByteBuffer bb) + throws BadPaddingException { if (internalData) { - decrypt(authenticator, box); // MAC is checked during decryption + decrypt(box); return tmpBB; } - BadPaddingException bpe = null; - if (!box.isNullCipher()) { - try { - // apply explicit nonce for AEAD/CBC cipher suites if needed - int nonceSize = - box.applyExplicitNonce(authenticator, contentType(), bb); - - // decrypt the content - if (box.isAEADMode()) { - // DON'T encrypt the nonce_explicit for AEAD mode - bb.position(bb.position() + nonceSize); - } // The explicit IV for CBC mode can be decrypted. - - box.decrypt(bb); - bb.position(nonceSize); // We don't actually remove the nonce. - } catch (BadPaddingException e) { - // RFC 2246 states that decryption_failed should be used - // for this purpose. However, that allows certain attacks, - // so we just send bad record MAC. We also need to make - // sure to always check the MAC to avoid a timing attack - // for the same issue. See paper by Vaudenay et al and the - // update in RFC 4346/5246. - // - // Failover to message authentication code checking. - bpe = new BadPaddingException("invalid padding"); - } - } - - // Requires message authentication code for null, stream and block - // cipher suites. - if (authenticator instanceof MAC) { - MAC signer = (MAC)authenticator; - int macLen = signer.MAClen(); - if (macLen != 0) { - if (bb.remaining() < macLen) { - // negative data length, something is wrong - throw new BadPaddingException("bad record"); - } - - int position = bb.position(); - int limit = bb.limit(); - int macOffset = limit - macLen; - - bb.limit(macOffset); - byte[] hash = signer.compute(contentType(), bb); - if (hash == null || macLen != hash.length) { - // something is wrong with MAC implementation - throw new RuntimeException("Internal MAC error"); - } - - bb.position(macOffset); - bb.limit(limit); - - try { - for (byte b : hash) { // No BB.equals(byte []); ! - if (bb.get() != b) { - throw new BadPaddingException("bad record MAC"); - } - } - } finally { - // reset to the data - bb.position(position); - bb.limit(macOffset); - } - } - } - - // Is it a failover? - if (bpe != null) { - throw bpe; - } + box.decrypt(bb); + bb.rewind(); return bb.slice(); } @@ -342,8 +338,8 @@ final class EngineInputRecord extends InputRecord { if (debug != null && Debug.isOn("packet")) { try { HexDumpEncoder hd = new HexDumpEncoder(); + srcBB.limit(srcPos + len); ByteBuffer bb = srcBB.duplicate(); // Use copy of BB - bb.limit(srcPos + len); System.out.println("[Raw read (bb)]: length = " + len); hd.encodeBuffer(bb, System.out); diff --git a/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java b/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java index a46a88bf708..e9d39805b36 100644 --- a/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java +++ b/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java @@ -29,6 +29,7 @@ package sun.security.ssl; import java.io.*; import java.nio.*; + /** * A OutputRecord class extension which uses external ByteBuffers * or the internal ByteArrayOutputStream for data manipulations. @@ -100,6 +101,51 @@ final class EngineOutputRecord extends OutputRecord { return finishedMsg; } + + /** + * Calculate the MAC value, storing the result either in + * the internal buffer, or at the end of the destination + * ByteBuffer. + * <P> + * We assume that the higher levels have assured us enough + * room, otherwise we'll indirectly throw a + * BufferOverFlowException runtime exception. + * + * position should equal limit, and points to the next + * free spot. + */ + private void addMAC(MAC signer, ByteBuffer bb) + throws IOException { + + if (signer.MAClen() != 0) { + byte[] hash = signer.compute(contentType(), bb); + + /* + * position was advanced to limit in compute above. + * + * Mark next area as writable (above layers should have + * established that we have plenty of room), then write + * out the hash. + */ + bb.limit(bb.limit() + hash.length); + bb.put(hash); + } + } + + /* + * Encrypt a ByteBuffer. + * + * We assume that the higher levels have assured us enough + * room for the encryption (plus padding), otherwise we'll + * indirectly throw a BufferOverFlowException runtime exception. + * + * position and limit will be the same, and points to the + * next free spot. + */ + void encrypt(CipherBox box, ByteBuffer bb) { + box.encrypt(bb); + } + /* * Override the actual write below. We do things this way to be * consistent with InputRecord. InputRecord may try to write out @@ -114,8 +160,7 @@ final class EngineOutputRecord extends OutputRecord { * Copy data out of buffer, it's ready to go. */ ByteBuffer netBB = (ByteBuffer) - ByteBuffer.allocate(len).put(buf, off, len).flip(); - + ByteBuffer.allocate(len).put(buf, 0, len).flip(); writer.putOutboundData(netBB); } @@ -123,19 +168,17 @@ final class EngineOutputRecord extends OutputRecord { * Main method for writing non-application data. * We MAC/encrypt, then send down for processing. */ - void write(Authenticator authenticator, CipherBox writeCipher) - throws IOException { - + void write(MAC writeMAC, CipherBox writeCipher) throws IOException { /* * Sanity check. */ switch (contentType()) { - case ct_change_cipher_spec: - case ct_alert: - case ct_handshake: - break; - default: - throw new RuntimeException("unexpected byte buffers"); + case ct_change_cipher_spec: + case ct_alert: + case ct_handshake: + break; + default: + throw new RuntimeException("unexpected byte buffers"); } /* @@ -150,10 +193,10 @@ final class EngineOutputRecord extends OutputRecord { */ if (!isEmpty()) { // compress(); // eventually - encrypt(authenticator, writeCipher); - - // send down for processing - write((OutputStream)null, false, (ByteArrayOutputStream)null); + addMAC(writeMAC); + encrypt(writeCipher); + write((OutputStream)null, false, // send down for processing + (ByteArrayOutputStream)null); } return; } @@ -161,8 +204,8 @@ final class EngineOutputRecord extends OutputRecord { /** * Main wrap/write driver. */ - void write(EngineArgs ea, Authenticator authenticator, - CipherBox writeCipher) throws IOException { + void write(EngineArgs ea, MAC writeMAC, CipherBox writeCipher) + throws IOException { /* * sanity check to make sure someone didn't inadvertantly * send us an impossible combination we don't know how @@ -174,7 +217,7 @@ final class EngineOutputRecord extends OutputRecord { * Have we set the MAC's yet? If not, we're not ready * to process application data yet. */ - if (authenticator == MAC.NULL) { + if (writeMAC == MAC.NULL) { return; } @@ -212,7 +255,7 @@ final class EngineOutputRecord extends OutputRecord { */ int length; if (engine.needToSplitPayload(writeCipher, protocolVersion)) { - write(ea, authenticator, writeCipher, 0x01); + write(ea, writeMAC, writeCipher, 0x01); ea.resetLim(); // reset application data buffer limit length = Math.min(ea.getAppRemaining(), maxDataSizeMinusOneByteRecord); @@ -222,14 +265,14 @@ final class EngineOutputRecord extends OutputRecord { // Don't bother to really write empty records. if (length > 0) { - write(ea, authenticator, writeCipher, length); + write(ea, writeMAC, writeCipher, length); } return; } - void write(EngineArgs ea, Authenticator authenticator, - CipherBox writeCipher, int length) throws IOException { + void write(EngineArgs ea, MAC writeMAC, CipherBox writeCipher, + int length) throws IOException { /* * Copy out existing buffer values. */ @@ -243,76 +286,39 @@ final class EngineOutputRecord extends OutputRecord { * Don't need to worry about SSLv2 rewrites, if we're here, * that's long since done. */ - int dstData = dstPos + headerSize + writeCipher.getExplicitNonceSize(); + int dstData = dstPos + headerSize; dstBB.position(dstData); - /* - * transfer application data into the network data buffer - */ ea.gather(length); - dstBB.limit(dstBB.position()); - dstBB.position(dstData); /* * "flip" but skip over header again, add MAC & encrypt + * addMAC will expand the limit to reflect the new + * data. */ - if (authenticator instanceof MAC) { - MAC signer = (MAC)authenticator; - if (signer.MAClen() != 0) { - byte[] hash = signer.compute(contentType(), dstBB); + dstBB.limit(dstBB.position()); + dstBB.position(dstData); + addMAC(writeMAC, dstBB); - /* - * position was advanced to limit in compute above. - * - * Mark next area as writable (above layers should have - * established that we have plenty of room), then write - * out the hash. - */ - dstBB.limit(dstBB.limit() + hash.length); - dstBB.put(hash); + /* + * Encrypt may pad, so again the limit may have changed. + */ + dstBB.limit(dstBB.position()); + dstBB.position(dstData); + encrypt(writeCipher, dstBB); - // reset the position and limit - dstBB.limit(dstBB.position()); - dstBB.position(dstData); - } - } - - if (!writeCipher.isNullCipher()) { - /* - * Requires explicit IV/nonce for CBC/AEAD cipher suites for TLS 1.1 - * or later. - */ - if (protocolVersion.v >= ProtocolVersion.TLS11.v && - (writeCipher.isCBCMode() || writeCipher.isAEADMode())) { - byte[] nonce = writeCipher.createExplicitNonce( - authenticator, contentType(), dstBB.remaining()); - dstBB.position(dstPos + headerSize); - dstBB.put(nonce); - if (!writeCipher.isAEADMode()) { - // The explicit IV in TLS 1.1 and later can be encrypted. - dstBB.position(dstPos + headerSize); - } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode - } - - /* - * Encrypt may pad, so again the limit may have changed. - */ - writeCipher.encrypt(dstBB, dstLim); - - if ((debug != null) && (Debug.isOn("record") || - (Debug.isOn("handshake") && - (contentType() == ct_change_cipher_spec)))) { + if (debug != null + && (Debug.isOn("record") || Debug.isOn("handshake"))) { + if ((debug != null && Debug.isOn("record")) + || contentType() == ct_change_cipher_spec) System.out.println(Thread.currentThread().getName() // v3.0/v3.1 ... + ", WRITE: " + protocolVersion + " " + InputRecord.contentName(contentType()) + ", length = " + length); - } - } else { - dstBB.position(dstBB.limit()); } - int packetLength = dstBB.limit() - dstPos - headerSize; + int packetLength = dstBB.limit() - dstData; /* * Finish out the record header. @@ -327,5 +333,7 @@ final class EngineOutputRecord extends OutputRecord { * Position was already set by encrypt() above. */ dstBB.limit(dstLim); + + return; } } diff --git a/jdk/src/share/classes/sun/security/ssl/EngineWriter.java b/jdk/src/share/classes/sun/security/ssl/EngineWriter.java index c6a26562606..e08dbb06069 100644 --- a/jdk/src/share/classes/sun/security/ssl/EngineWriter.java +++ b/jdk/src/share/classes/sun/security/ssl/EngineWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2007, 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 @@ -99,8 +99,7 @@ final class EngineWriter { * other writeRecord. */ synchronized void writeRecord(EngineOutputRecord outputRecord, - Authenticator authenticator, - CipherBox writeCipher) throws IOException { + MAC writeMAC, CipherBox writeCipher) throws IOException { /* * Only output if we're still open. @@ -109,7 +108,7 @@ final class EngineWriter { throw new IOException("writer side was already closed."); } - outputRecord.write(authenticator, writeCipher); + outputRecord.write(writeMAC, writeCipher); /* * Did our handshakers notify that we just sent the @@ -152,8 +151,7 @@ final class EngineWriter { * Return any determined status. */ synchronized HandshakeStatus writeRecord( - EngineOutputRecord outputRecord, EngineArgs ea, - Authenticator authenticator, + EngineOutputRecord outputRecord, EngineArgs ea, MAC writeMAC, CipherBox writeCipher) throws IOException { /* @@ -183,7 +181,7 @@ final class EngineWriter { throw new IOException("The write side was already closed"); } - outputRecord.write(ea, authenticator, writeCipher); + outputRecord.write(ea, writeMAC, writeCipher); if (debug != null && Debug.isOn("packet")) { dumpPacket(ea, false); diff --git a/jdk/src/share/classes/sun/security/ssl/Handshaker.java b/jdk/src/share/classes/sun/security/ssl/Handshaker.java index d03b8f7e5ac..828b60bcab6 100644 --- a/jdk/src/share/classes/sun/security/ssl/Handshaker.java +++ b/jdk/src/share/classes/sun/security/ssl/Handshaker.java @@ -49,7 +49,6 @@ import sun.security.ssl.HandshakeMessage.*; import sun.security.ssl.CipherSuite.*; import static sun.security.ssl.CipherSuite.PRF.*; -import static sun.security.ssl.CipherSuite.CipherType.*; /** * Handshaker ... processes handshake records from an SSL V3.0 @@ -715,47 +714,33 @@ abstract class Handshaker { /** * Create a new read MAC and return it to caller. */ - Authenticator newReadAuthenticator() - throws NoSuchAlgorithmException, InvalidKeyException { - - Authenticator authenticator = null; - if (cipherSuite.cipher.cipherType == AEAD_CIPHER) { - authenticator = new Authenticator(protocolVersion); + MAC newReadMAC() throws NoSuchAlgorithmException, InvalidKeyException { + MacAlg macAlg = cipherSuite.macAlg; + MAC mac; + if (isClient) { + mac = macAlg.newMac(protocolVersion, svrMacSecret); + svrMacSecret = null; } else { - MacAlg macAlg = cipherSuite.macAlg; - if (isClient) { - authenticator = macAlg.newMac(protocolVersion, svrMacSecret); - svrMacSecret = null; - } else { - authenticator = macAlg.newMac(protocolVersion, clntMacSecret); - clntMacSecret = null; - } + mac = macAlg.newMac(protocolVersion, clntMacSecret); + clntMacSecret = null; } - - return authenticator; + return mac; } /** * Create a new write MAC and return it to caller. */ - Authenticator newWriteAuthenticator() - throws NoSuchAlgorithmException, InvalidKeyException { - - Authenticator authenticator = null; - if (cipherSuite.cipher.cipherType == AEAD_CIPHER) { - authenticator = new Authenticator(protocolVersion); + MAC newWriteMAC() throws NoSuchAlgorithmException, InvalidKeyException { + MacAlg macAlg = cipherSuite.macAlg; + MAC mac; + if (isClient) { + mac = macAlg.newMac(protocolVersion, clntMacSecret); + clntMacSecret = null; } else { - MacAlg macAlg = cipherSuite.macAlg; - if (isClient) { - authenticator = macAlg.newMac(protocolVersion, clntMacSecret); - clntMacSecret = null; - } else { - authenticator = macAlg.newMac(protocolVersion, svrMacSecret); - svrMacSecret = null; - } + mac = macAlg.newMac(protocolVersion, svrMacSecret); + svrMacSecret = null; } - - return authenticator; + return mac; } /* @@ -1204,23 +1189,11 @@ abstract class Handshaker { int prfHashLength = prf.getPRFHashLength(); int prfBlockSize = prf.getPRFBlockSize(); - // TLS v1.1 or later uses an explicit IV in CBC cipher suites to - // protect against the CBC attacks. AEAD/GCM cipher suites in TLS - // v1.2 or later use a fixed IV as the implicit part of the partially - // implicit nonce technique described in RFC 5116. - int ivSize = cipher.ivSize; - if (cipher.cipherType == AEAD_CIPHER) { - ivSize = cipher.fixedIvSize; - } else if (protocolVersion.v >= ProtocolVersion.TLS11.v && - cipher.cipherType == BLOCK_CIPHER) { - ivSize = 0; - } - TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec( masterKey, protocolVersion.major, protocolVersion.minor, clnt_random.random_bytes, svr_random.random_bytes, cipher.algorithm, cipher.keySize, expandedKeySize, - ivSize, hashSize, + cipher.ivSize, hashSize, prfHashAlg, prfHashLength, prfBlockSize); try { @@ -1228,15 +1201,14 @@ abstract class Handshaker { kg.init(spec); TlsKeyMaterialSpec keySpec = (TlsKeyMaterialSpec)kg.generateKey(); - // Return null if cipher keys are not supposed to be generated. clntWriteKey = keySpec.getClientCipherKey(); svrWriteKey = keySpec.getServerCipherKey(); // Return null if IVs are not supposed to be generated. + // e.g. TLS 1.1+. clntWriteIV = keySpec.getClientIv(); svrWriteIV = keySpec.getServerIv(); - // Return null if MAC keys are not supposed to be generated. clntMacSecret = keySpec.getClientMacKey(); svrMacSecret = keySpec.getServerMacKey(); } catch (GeneralSecurityException e) { @@ -1261,14 +1233,10 @@ abstract class Handshaker { printHex(dump, masterKey.getEncoded()); // Outputs: - if (clntMacSecret != null) { - System.out.println("Client MAC write Secret:"); - printHex(dump, clntMacSecret.getEncoded()); - System.out.println("Server MAC write Secret:"); - printHex(dump, svrMacSecret.getEncoded()); - } else { - System.out.println("... no MAC keys used for this cipher"); - } + System.out.println("Client MAC write Secret:"); + printHex(dump, clntMacSecret.getEncoded()); + System.out.println("Server MAC write Secret:"); + printHex(dump, svrMacSecret.getEncoded()); if (clntWriteKey != null) { System.out.println("Client write key:"); diff --git a/jdk/src/share/classes/sun/security/ssl/InputRecord.java b/jdk/src/share/classes/sun/security/ssl/InputRecord.java index 74d88f9b81b..78e866a07ca 100644 --- a/jdk/src/share/classes/sun/security/ssl/InputRecord.java +++ b/jdk/src/share/classes/sun/security/ssl/InputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2008, 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 @@ -77,17 +77,6 @@ class InputRecord extends ByteArrayInputStream implements Record { /* * Construct the record to hold the maximum sized input record. * Data will be filled in separately. - * - * The structure of the byte buffer looks like: - * - * |--------+---------+---------------------------------| - * | header | IV | content, MAC/TAG, padding, etc. | - * | headerPlusIVSize | - * - * header: the header of an SSL records - * IV: the optional IV/nonce field, it is only required for block - * (TLS 1.1 or later) and AEAD cipher suites. - * */ InputRecord() { super(new byte[maxRecordSize]); @@ -144,83 +133,44 @@ class InputRecord extends ByteArrayInputStream implements Record { return handshakeHash; } - void decrypt(Authenticator authenticator, - CipherBox box) throws BadPaddingException { + /* + * Verify and remove the MAC ... used for all records. + */ + boolean checkMAC(MAC signer) { + int len = signer.MAClen(); + if (len == 0) { // no mac + return true; + } - BadPaddingException bpe = null; - if (!box.isNullCipher()) { - try { - int cipheredLength = count - headerSize; + int offset = count - len; - // apply explicit nonce for AEAD/CBC cipher suites if needed - int nonceSize = box.applyExplicitNonce(authenticator, - contentType(), buf, headerSize, cipheredLength); - pos = headerSize + nonceSize; - lastHashed = pos; // don't digest the explicit nonce + if (offset < headerSize) { + // data length would be negative, something is wrong + return false; + } - // decrypt the content - int offset = headerSize; - if (box.isAEADMode()) { - // DON'T encrypt the nonce_explicit for AEAD mode - offset += nonceSize; - } // The explicit IV for CBC mode can be decrypted. + byte[] mac = signer.compute(contentType(), buf, + headerSize, offset - headerSize); - count = offset + box.decrypt(buf, offset, count - offset); + if (len != mac.length) { + throw new RuntimeException("Internal MAC error"); + } - // Note that we don't remove the nonce from the buffer. - } catch (BadPaddingException e) { - // RFC 2246 states that decryption_failed should be used - // for this purpose. However, that allows certain attacks, - // so we just send bad record MAC. We also need to make - // sure to always check the MAC to avoid a timing attack - // for the same issue. See paper by Vaudenay et al and the - // update in RFC 4346/5246. - // - // Failover to message authenticatoin code checking. - bpe = new BadPaddingException("invalid padding"); + for (int i = 0; i < len; i++) { + if (buf[offset + i] != mac[i]) { + return false; } } - - // Requires message authentication code for null, stream and block - // cipher suites. - if (authenticator instanceof MAC) { - MAC signer = (MAC)authenticator; - int macLen = signer.MAClen(); - if (macLen != 0) { - int macOffset = count - macLen; - int contentLen = macOffset - pos; - if (contentLen < 0) { - // negative data length, something is wrong - throw new BadPaddingException("bad record"); - } - - count -= macLen; // Set the count before any MAC checking - // exception occurs, so that the following - // process can read the actual decrypted - // content (minus the MAC) in the fragment - // if necessary. - byte[] hash = signer.compute(contentType(), - buf, pos, contentLen); - if (hash == null || macLen != hash.length) { - // something is wrong with MAC implementation - throw new RuntimeException("Internal MAC error"); - } - - int offset = macOffset; - for (byte b : hash) { - if (buf[offset++] != b) { - throw new BadPaddingException("bad record MAC"); - } - } - } - } - - // Is it a failover? - if (bpe != null) { - throw bpe; - } + count -= len; + return true; } + void decrypt(CipherBox box) throws BadPaddingException { + int len = count - headerSize; + count = headerSize + box.decrypt(buf, headerSize, len); + } + + /* * Well ... hello_request messages are _never_ hashed since we can't * know when they'd appear in the sequence. diff --git a/jdk/src/share/classes/sun/security/ssl/JsseJce.java b/jdk/src/share/classes/sun/security/ssl/JsseJce.java index 49e89c6028e..e22caece0e2 100644 --- a/jdk/src/share/classes/sun/security/ssl/JsseJce.java +++ b/jdk/src/share/classes/sun/security/ssl/JsseJce.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -154,11 +154,6 @@ final class JsseJce { * without padding. */ final static String CIPHER_AES = "AES/CBC/NoPadding"; - /** - * JCE transformation string for AES in GCM mode - * without padding. - */ - final static String CIPHER_AES_GCM = "AES/GCM/NoPadding"; /** * JCA identifier string for DSA, i.e. a DSA with SHA-1. */ diff --git a/jdk/src/share/classes/sun/security/ssl/MAC.java b/jdk/src/share/classes/sun/security/ssl/MAC.java index 30bf2e2e50f..753a8c57ac4 100644 --- a/jdk/src/share/classes/sun/security/ssl/MAC.java +++ b/jdk/src/share/classes/sun/security/ssl/MAC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,15 +39,19 @@ import static sun.security.ssl.CipherSuite.*; /** * This class computes the "Message Authentication Code" (MAC) for each - * SSL stream and block cipher message. This is essentially a shared-secret - * signature, used to provide integrity protection for SSL messages. The - * MAC is actually one of several keyed hashes, as associated with the cipher - * suite and protocol version. (SSL v3.0 uses one construct, TLS uses another.) + * SSL message. This is essentially a shared-secret signature, used to + * provide integrity protection for SSL messages. The MAC is actually + * one of several keyed hashes, as associated with the cipher suite and + * protocol version. (SSL v3.0 uses one construct, TLS uses another.) + * + * <P>NOTE: MAC computation is the only place in the SSL protocol that the + * sequence number is used. It's also reset to zero with each change of + * a cipher spec, so this is the only place this state is needed. * * @author David Brownell * @author Andreas Sterbenz */ -final class MAC extends Authenticator { +final class MAC { final static MAC NULL = new MAC(); @@ -60,9 +64,26 @@ final class MAC extends Authenticator { // JCE Mac object private final Mac mac; + // byte array containing the additional information we MAC in each record + // (see below) + private final byte[] block; + + // sequence number + record type + + record length + private static final int BLOCK_SIZE_SSL = 8 + 1 + 2; + + // sequence number + record type + protocol version + record length + private static final int BLOCK_SIZE_TLS = 8 + 1 + 2 + 2; + + // offset of record type in block + private static final int BLOCK_OFFSET_TYPE = 8; + + // offset of protocol version number in block (TLS only) + private static final int BLOCK_OFFSET_VERSION = 8 + 1; + private MAC() { macSize = 0; mac = null; + block = null; } /** @@ -70,8 +91,6 @@ final class MAC extends Authenticator { */ MAC(MacAlg macAlg, ProtocolVersion protocolVersion, SecretKey key) throws NoSuchAlgorithmException, InvalidKeyException { - super(protocolVersion); - this.macSize = macAlg.size; String algorithm; @@ -91,6 +110,14 @@ final class MAC extends Authenticator { mac = JsseJce.getMac(algorithm); mac.init(key); + + if (tls) { + block = new byte[BLOCK_SIZE_TLS]; + block[BLOCK_OFFSET_VERSION] = protocolVersion.major; + block[BLOCK_OFFSET_VERSION+1] = protocolVersion.minor; + } else { + block = new byte[BLOCK_SIZE_SSL]; + } } /** @@ -109,15 +136,7 @@ final class MAC extends Authenticator { * @param len the size of the compressed record */ final byte[] compute(byte type, byte buf[], int offset, int len) { - if (macSize == 0) { - return nullMAC; - } - - byte[] additional = acquireAuthenticationBytes(type, len); - mac.update(additional); - mac.update(buf, offset, len); - - return mac.doFinal(); + return compute(type, null, buf, offset, len); } /** @@ -132,13 +151,78 @@ final class MAC extends Authenticator { * demarcate the data to be MAC'd. */ final byte[] compute(byte type, ByteBuffer bb) { + return compute(type, bb, null, 0, bb.remaining()); + } + + /** + * Check whether the sequence number is close to wrap + * + * Sequence numbers are of type uint64 and may not exceed 2^64-1. + * Sequence numbers do not wrap. When the sequence number is near + * to wrap, we need to close the connection immediately. + */ + final boolean seqNumOverflow() { + /* + * Conservatively, we don't allow more records to be generated + * when there are only 2^8 sequence numbers left. + */ + return (block != null && mac != null && + block[0] == (byte)0xFF && block[1] == (byte)0xFF && + block[2] == (byte)0xFF && block[3] == (byte)0xFF && + block[4] == (byte)0xFF && block[5] == (byte)0xFF && + block[6] == (byte)0xFF); + } + + /* + * Check whether to renew the sequence number + * + * Sequence numbers are of type uint64 and may not exceed 2^64-1. + * Sequence numbers do not wrap. If a TLS + * implementation would need to wrap a sequence number, it must + * renegotiate instead. + */ + final boolean seqNumIsHuge() { + /* + * Conservatively, we should ask for renegotiation when there are + * only 2^48 sequence numbers left. + */ + return (block != null && mac != null && + block[0] == (byte)0xFF && block[1] == (byte)0xFF); + } + + // increment the sequence number in the block array + // it is a 64-bit number stored in big-endian format + private void incrementSequenceNumber() { + int k = 7; + while ((k >= 0) && (++block[k] == 0)) { + k--; + } + } + + /* + * Compute based on either buffer type, either bb.position/limit + * or buf/offset/len. + */ + private byte[] compute(byte type, ByteBuffer bb, byte[] buf, + int offset, int len) { + if (macSize == 0) { return nullMAC; } - byte[] additional = acquireAuthenticationBytes(type, bb.remaining()); - mac.update(additional); - mac.update(bb); + block[BLOCK_OFFSET_TYPE] = type; + block[block.length - 2] = (byte)(len >> 8); + block[block.length - 1] = (byte)(len ); + + mac.update(block); + incrementSequenceNumber(); + + // content + if (bb != null) { + mac.update(bb); + } else { + mac.update(buf, offset, len); + } return mac.doFinal(); } diff --git a/jdk/src/share/classes/sun/security/ssl/OutputRecord.java b/jdk/src/share/classes/sun/security/ssl/OutputRecord.java index d07c779f75e..900003dfd0f 100644 --- a/jdk/src/share/classes/sun/security/ssl/OutputRecord.java +++ b/jdk/src/share/classes/sun/security/ssl/OutputRecord.java @@ -54,7 +54,6 @@ class OutputRecord extends ByteArrayOutputStream implements Record { private int lastHashed; private boolean firstMessage; final private byte contentType; - private int headerOffset; // current protocol version, sent as record version ProtocolVersion protocolVersion; @@ -71,23 +70,6 @@ class OutputRecord extends ByteArrayOutputStream implements Record { * Default constructor makes a record supporting the maximum * SSL record size. It allocates the header bytes directly. * - * The structure of the byte buffer looks like: - * - * |---------+--------+-------+---------------------------------| - * | unused | header | IV | content, MAC/TAG, padding, etc. | - * | headerPlusMaxIVSize | - * - * unused: unused part of the buffer of size - * - * headerPlusMaxIVSize - header size - IV size - * - * When this object is created, we don't know the protocol - * version number, IV length, etc., so reserve space in front - * to avoid extra data movement (copies). - * header: the header of an SSL record - * IV: the optional IV/nonce field, it is only required for block - * (TLS 1.1 or later) and AEAD cipher suites. - * * @param type the content type for the record */ OutputRecord(byte type, int size) { @@ -95,10 +77,9 @@ class OutputRecord extends ByteArrayOutputStream implements Record { this.protocolVersion = ProtocolVersion.DEFAULT; this.helloVersion = ProtocolVersion.DEFAULT_HELLO; firstMessage = true; - count = headerPlusMaxIVSize; + count = headerSize; contentType = type; lastHashed = count; - headerOffset = headerPlusMaxIVSize - headerSize; } OutputRecord(byte type) { @@ -138,9 +119,8 @@ class OutputRecord extends ByteArrayOutputStream implements Record { @Override public synchronized void reset() { super.reset(); - count = headerPlusMaxIVSize; + count = headerSize; lastHashed = count; - headerOffset = headerPlusMaxIVSize - headerSize; } /* @@ -193,84 +173,58 @@ class OutputRecord extends ByteArrayOutputStream implements Record { * of sending empty records over the network. */ boolean isEmpty() { - return count == headerPlusMaxIVSize; + return count == headerSize; } /* - * Return true if the record is of an alert of the given description. - * - * Per SSL/TLS specifications, alert messages convey the severity of the - * message (warning or fatal) and a description of the alert. An alert - * is defined with a two bytes struct, {byte level, byte description}, - * following after the header bytes. + * Return true if the record is of a given alert. */ boolean isAlert(byte description) { - if ((count > (headerPlusMaxIVSize + 1)) && (contentType == ct_alert)) { - return buf[headerPlusMaxIVSize + 1] == description; + // An alert is defined with a two bytes struct, + // {byte level, byte description}, following after the header bytes. + if (count > (headerSize + 1) && contentType == ct_alert) { + return buf[headerSize + 1] == description; } return false; } /* - * Encrypt ... length may grow due to block cipher padding, or - * message authentication code or tag. + * Compute the MAC and append it to this record. In case we + * are automatically flushing a handshake stream, make sure we + * have hashed the message first. */ - void encrypt(Authenticator authenticator, CipherBox box) - throws IOException { - - // In case we are automatically flushing a handshake stream, make - // sure we have hashed the message first. + void addMAC(MAC signer) throws IOException { // // when we support compression, hashing can't go here // since it'll need to be done on the uncompressed data, // and the MAC applies to the compressed data. + // if (contentType == ct_handshake) { doHashes(); } - - // Requires message authentication code for stream and block - // cipher suites. - if (authenticator instanceof MAC) { - MAC signer = (MAC)authenticator; - if (signer.MAClen() != 0) { - byte[] hash = signer.compute(contentType, buf, - headerPlusMaxIVSize, count - headerPlusMaxIVSize); - write(hash); - } - } - - if (!box.isNullCipher()) { - // Requires explicit IV/nonce for CBC/AEAD cipher suites for - // TLS 1.1 or later. - if ((protocolVersion.v >= ProtocolVersion.TLS11.v) && - (box.isCBCMode() || box.isAEADMode())) { - byte[] nonce = box.createExplicitNonce(authenticator, - contentType, count - headerPlusMaxIVSize); - int offset = headerPlusMaxIVSize - nonce.length; - System.arraycopy(nonce, 0, buf, offset, nonce.length); - headerOffset = offset - headerSize; - } else { - headerOffset = headerPlusMaxIVSize - headerSize; - } - - // encrypt the content - int offset = headerPlusMaxIVSize; - if (!box.isAEADMode()) { - // The explicit IV can be encrypted. - offset = headerOffset + headerSize; - } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode - - count = offset + box.encrypt(buf, offset, count - offset); + if (signer.MAClen() != 0) { + byte[] hash = signer.compute(contentType, buf, + headerSize, count - headerSize); + write(hash); } } + /* + * Encrypt ... length may grow due to block cipher padding + */ + void encrypt(CipherBox box) { + int len = count - headerSize; + count = headerSize + box.encrypt(buf, headerSize, len); + } + + /* * Tell how full the buffer is ... for filling it with application or * handshake data. */ final int availableDataBytes() { - int dataSize = count - headerPlusMaxIVSize; + int dataSize = count - headerSize; return maxDataSize - dataSize; } @@ -316,11 +270,11 @@ class OutputRecord extends ByteArrayOutputStream implements Record { * Don't emit content-free records. (Even change cipher spec * messages have a byte of data!) */ - if (count == headerPlusMaxIVSize) { + if (count == headerSize) { return; } - int length = count - headerOffset - headerSize; + int length = count - headerSize; // "should" really never write more than about 14 Kb... if (length < 0) { throw new SSLException("output record size too small: " @@ -345,9 +299,7 @@ class OutputRecord extends ByteArrayOutputStream implements Record { */ if (firstMessage && useV2Hello()) { byte[] v3Msg = new byte[length - 4]; - System.arraycopy(buf, headerPlusMaxIVSize + 4, - v3Msg, 0, v3Msg.length); - headerOffset = 0; // reset the header offset + System.arraycopy(buf, headerSize + 4, v3Msg, 0, v3Msg.length); V3toV2ClientHello(v3Msg); handshakeHash.reset(); lastHashed = 2; @@ -362,11 +314,11 @@ class OutputRecord extends ByteArrayOutputStream implements Record { /* * Fill out the header, write it and the message. */ - buf[headerOffset + 0] = contentType; - buf[headerOffset + 1] = protocolVersion.major; - buf[headerOffset + 2] = protocolVersion.minor; - buf[headerOffset + 3] = (byte)(length >> 8); - buf[headerOffset + 4] = (byte)(length); + buf[0] = contentType; + buf[1] = protocolVersion.major; + buf[2] = protocolVersion.minor; + buf[3] = (byte)(length >> 8); + buf[4] = (byte)(length); } firstMessage = false; @@ -386,8 +338,7 @@ class OutputRecord extends ByteArrayOutputStream implements Record { * when holdRecord is true, the implementation in this class * will be used. */ - writeBuffer(heldRecordBuffer, - buf, headerOffset, count - headerOffset, debugOffset); + writeBuffer(heldRecordBuffer, buf, 0, count, debugOffset); } else { // It's time to send, do we have buffered data? // May or may not have a heldRecordBuffer. @@ -395,18 +346,15 @@ class OutputRecord extends ByteArrayOutputStream implements Record { int heldLen = heldRecordBuffer.size(); // Ensure the capacity of this buffer. - int newCount = count + heldLen - headerOffset; - ensureCapacity(newCount); + ensureCapacity(count + heldLen); // Slide everything in the buffer to the right. - System.arraycopy(buf, headerOffset, - buf, heldLen, count - headerOffset); + System.arraycopy(buf, 0, buf, heldLen, count); // Prepend the held record to the buffer. System.arraycopy( heldRecordBuffer.toByteArray(), 0, buf, 0, heldLen); - count = newCount; - headerOffset = 0; + count += heldLen; // Clear the held buffer. heldRecordBuffer.reset(); @@ -414,8 +362,7 @@ class OutputRecord extends ByteArrayOutputStream implements Record { // The held buffer has been dumped, set the debug dump offset. debugOffset = heldLen; } - writeBuffer(s, buf, headerOffset, - count - headerOffset, debugOffset); + writeBuffer(s, buf, 0, count, debugOffset); } reset(); @@ -435,11 +382,12 @@ class OutputRecord extends ByteArrayOutputStream implements Record { if (debug != null && Debug.isOn("packet")) { try { HexDumpEncoder hd = new HexDumpEncoder(); + ByteBuffer bb = ByteBuffer.wrap( + buf, off + debugOffset, len - debugOffset); System.out.println("[Raw write]: length = " + - (len - debugOffset)); - hd.encodeBuffer(new ByteArrayInputStream(buf, - off + debugOffset, len - debugOffset), System.out); + bb.remaining()); + hd.encodeBuffer(bb, System.out); } catch (IOException e) { } } } @@ -452,13 +400,8 @@ class OutputRecord extends ByteArrayOutputStream implements Record { return firstMessage && (helloVersion == ProtocolVersion.SSL20Hello) && (contentType == ct_handshake) - && (buf[headerOffset + 5] == HandshakeMessage.ht_client_hello) - // 5: recode header size - && (buf[headerPlusMaxIVSize + 4 + 2 + 32] == 0); - // V3 session ID is empty - // 4: handshake header size - // 2: client_version in ClientHello - // 32: random in ClientHello + && (buf[5] == HandshakeMessage.ht_client_hello) + && (buf[headerSize + 4+2+32] == 0); // V3 session ID is empty } /* diff --git a/jdk/src/share/classes/sun/security/ssl/Record.java b/jdk/src/share/classes/sun/security/ssl/Record.java index ca85a067ae3..0494d9a4583 100644 --- a/jdk/src/share/classes/sun/security/ssl/Record.java +++ b/jdk/src/share/classes/sun/security/ssl/Record.java @@ -52,29 +52,20 @@ interface Record { static final int trailerSize = 20; // SHA1 hash size static final int maxDataSize = 16384; // 2^14 bytes of data static final int maxPadding = 256; // block cipher padding - static final int maxIVLength = 256; // IV length - - /* - * The size of the header plus the max IV length - */ - static final int headerPlusMaxIVSize = - headerSize // header - + maxIVLength; // iv + static final int maxIVLength = 256; // block length /* * SSL has a maximum record size. It's header, (compressed) data, - * padding, and a trailer for the message authentication information (MAC - * for block and stream ciphers, and message authentication tag for AEAD - * ciphers). - * + * padding, and a trailer for the MAC. * Some compression algorithms have rare cases where they expand the data. * As we don't support compression at this time, leave that out. */ static final int maxRecordSize = - headerPlusMaxIVSize // header + iv - + maxDataSize // data - + maxPadding // padding - + trailerSize; // MAC or AEAD tag + headerSize // header + + maxIVLength // iv + + maxDataSize // data + + maxPadding // padding + + trailerSize; // MAC static final boolean enableCBCProtection = Debug.getBooleanProperty("jsse.enableCBCProtection", true); @@ -86,7 +77,8 @@ interface Record { static final int maxDataSizeMinusOneByteRecord = maxDataSize // max data size - ( // max one byte record size - headerPlusMaxIVSize // header + iv + headerSize // header + + maxIVLength // iv + 1 // one byte data + maxPadding // padding + trailerSize // MAC @@ -112,10 +104,11 @@ interface Record { * Allocate a smaller array. */ static final int maxAlertRecordSize = - headerPlusMaxIVSize // header + iv - + 2 // alert - + maxPadding // padding - + trailerSize; // MAC + headerSize // header + + maxIVLength // iv + + 2 // alert + + maxPadding // padding + + trailerSize; // MAC /* * The overflow values of integers of 8, 16 and 24 bits. diff --git a/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java index 2da58577c94..41415337ca1 100644 --- a/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java @@ -280,7 +280,7 @@ final public class SSLEngineImpl extends SSLEngine { /* * Crypto state that's reinitialized when the session changes. */ - private Authenticator readAuthenticator, writeAuthenticator; + private MAC readMAC, writeMAC; private CipherBox readCipher, writeCipher; // NOTE: compression state would be saved here @@ -377,9 +377,9 @@ final public class SSLEngineImpl extends SSLEngine { * Note: compression support would go here too */ readCipher = CipherBox.NULL; - readAuthenticator = MAC.NULL; + readMAC = MAC.NULL; writeCipher = CipherBox.NULL; - writeAuthenticator = MAC.NULL; + writeMAC = MAC.NULL; // default security parameters for secure renegotiation secureRenegotiation = false; @@ -586,7 +586,7 @@ final public class SSLEngineImpl extends SSLEngine { try { readCipher = handshaker.newReadCipher(); - readAuthenticator = handshaker.newReadAuthenticator(); + readMAC = handshaker.newReadMAC(); } catch (GeneralSecurityException e) { // "can't happen" throw new SSLException("Algorithm missing: ", e); @@ -622,7 +622,7 @@ final public class SSLEngineImpl extends SSLEngine { try { writeCipher = handshaker.newWriteCipher(); - writeAuthenticator = handshaker.newWriteAuthenticator(); + writeMAC = handshaker.newWriteMAC(); } catch (GeneralSecurityException e) { // "can't happen" throw new SSLException("Algorithm missing: ", e); @@ -958,15 +958,34 @@ final public class SSLEngineImpl extends SSLEngine { * throw a fatal alert if the integrity check fails. */ try { - decryptedBB = inputRecord.decrypt( - readAuthenticator, readCipher, readBB); + decryptedBB = inputRecord.decrypt(readCipher, readBB); } catch (BadPaddingException e) { + // RFC 2246 states that decryption_failed should be used + // for this purpose. However, that allows certain attacks, + // so we just send bad record MAC. We also need to make + // sure to always check the MAC to avoid a timing attack + // for the same issue. See paper by Vaudenay et al. + // + // rewind the BB if necessary. + readBB.rewind(); + + inputRecord.checkMAC(readMAC, readBB); + // use the same alert types as for MAC failure below byte alertType = (inputRecord.contentType() == Record.ct_handshake) ? Alerts.alert_handshake_failure : Alerts.alert_bad_record_mac; - fatal(alertType, e.getMessage(), e); + fatal(alertType, "Invalid padding", e); + } + + if (!inputRecord.checkMAC(readMAC, decryptedBB)) { + if (inputRecord.contentType() == Record.ct_handshake) { + fatal(Alerts.alert_handshake_failure, + "bad handshake record MAC"); + } else { + fatal(Alerts.alert_bad_record_mac, "bad record MAC"); + } } // if (!inputRecord.decompress(c)) @@ -1118,7 +1137,7 @@ final public class SSLEngineImpl extends SSLEngine { hsStatus = getHSStatus(hsStatus); if (connectionState < cs_ERROR && !isInboundDone() && (hsStatus == HandshakeStatus.NOT_HANDSHAKING)) { - if (checkSequenceNumber(readAuthenticator, + if (checkSequenceNumber(readMAC, inputRecord.contentType())) { hsStatus = getHSStatus(null); } @@ -1271,7 +1290,7 @@ final public class SSLEngineImpl extends SSLEngine { // eventually compress as well. HandshakeStatus hsStatus = - writer.writeRecord(eor, ea, writeAuthenticator, writeCipher); + writer.writeRecord(eor, ea, writeMAC, writeCipher); /* * We only need to check the sequence number state for @@ -1288,7 +1307,7 @@ final public class SSLEngineImpl extends SSLEngine { hsStatus = getHSStatus(hsStatus); if (connectionState < cs_ERROR && !isOutboundDone() && (hsStatus == HandshakeStatus.NOT_HANDSHAKING)) { - if (checkSequenceNumber(writeAuthenticator, eor.contentType())) { + if (checkSequenceNumber(writeMAC, eor.contentType())) { hsStatus = getHSStatus(null); } } @@ -1327,7 +1346,7 @@ final public class SSLEngineImpl extends SSLEngine { */ void writeRecord(EngineOutputRecord eor) throws IOException { // eventually compress as well. - writer.writeRecord(eor, writeAuthenticator, writeCipher); + writer.writeRecord(eor, writeMAC, writeCipher); /* * Check the sequence number state @@ -1341,7 +1360,7 @@ final public class SSLEngineImpl extends SSLEngine { * of the last record cannot be wrapped. */ if ((connectionState < cs_ERROR) && !isOutboundDone()) { - checkSequenceNumber(writeAuthenticator, eor.contentType()); + checkSequenceNumber(writeMAC, eor.contentType()); } } @@ -1359,14 +1378,14 @@ final public class SSLEngineImpl extends SSLEngine { * * Return true if the handshake status may be changed. */ - private boolean checkSequenceNumber(Authenticator authenticator, byte type) + private boolean checkSequenceNumber(MAC mac, byte type) throws IOException { /* * Don't bother to check the sequence number for error or * closed connections, or NULL MAC */ - if (connectionState >= cs_ERROR || authenticator == MAC.NULL) { + if (connectionState >= cs_ERROR || mac == MAC.NULL) { return false; } @@ -1374,7 +1393,7 @@ final public class SSLEngineImpl extends SSLEngine { * Conservatively, close the connection immediately when the * sequence number is close to overflow */ - if (authenticator.seqNumOverflow()) { + if (mac.seqNumOverflow()) { /* * TLS protocols do not define a error alert for sequence * number overflow. We use handshake_failure error alert @@ -1397,7 +1416,7 @@ final public class SSLEngineImpl extends SSLEngine { * Don't bother to kickstart the renegotiation when the local is * asking for it. */ - if ((type != Record.ct_handshake) && authenticator.seqNumIsHuge()) { + if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) { if (debug != null && Debug.isOn("ssl")) { System.out.println(Thread.currentThread().getName() + ", request renegotiation " + diff --git a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java index 9c8b43f17ad..f807c4c58ce 100644 --- a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -292,7 +292,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { /* * Crypto state that's reinitialized when the session changes. */ - private Authenticator readAuthenticator, writeAuthenticator; + private MAC readMAC, writeMAC; private CipherBox readCipher, writeCipher; // NOTE: compression state would be saved here @@ -586,9 +586,9 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * Note: compression support would go here too */ readCipher = CipherBox.NULL; - readAuthenticator = MAC.NULL; + readMAC = MAC.NULL; writeCipher = CipherBox.NULL; - writeAuthenticator = MAC.NULL; + writeMAC = MAC.NULL; // initial security parameters for secure renegotiation secureRenegotiation = false; @@ -829,7 +829,8 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { boolean holdRecord) throws IOException { // r.compress(c); - r.encrypt(writeAuthenticator, writeCipher); + r.addMAC(writeMAC); + r.encrypt(writeCipher); if (holdRecord) { // If we were requested to delay the record due to possibility @@ -860,7 +861,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * of the last record cannot be wrapped. */ if (connectionState < cs_ERROR) { - checkSequenceNumber(writeAuthenticator, r.contentType()); + checkSequenceNumber(writeMAC, r.contentType()); } // turn off the flag of the first application record @@ -985,14 +986,29 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * throw a fatal alert if the integrity check fails. */ try { - r.decrypt(readAuthenticator, readCipher); + r.decrypt(readCipher); } catch (BadPaddingException e) { + // RFC 2246 states that decryption_failed should be used + // for this purpose. However, that allows certain attacks, + // so we just send bad record MAC. We also need to make + // sure to always check the MAC to avoid a timing attack + // for the same issue. See paper by Vaudenay et al. + r.checkMAC(readMAC); // use the same alert types as for MAC failure below byte alertType = (r.contentType() == Record.ct_handshake) ? Alerts.alert_handshake_failure : Alerts.alert_bad_record_mac; - fatal(alertType, e.getMessage(), e); + fatal(alertType, "Invalid padding", e); } + if (!r.checkMAC(readMAC)) { + if (r.contentType() == Record.ct_handshake) { + fatal(Alerts.alert_handshake_failure, + "bad handshake record MAC"); + } else { + fatal(Alerts.alert_bad_record_mac, "bad record MAC"); + } + } + // if (!r.decompress(c)) // fatal(Alerts.alert_decompression_failure, @@ -1143,7 +1159,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * of the last record cannot be wrapped. */ if (connectionState < cs_ERROR) { - checkSequenceNumber(readAuthenticator, r.contentType()); + checkSequenceNumber(readMAC, r.contentType()); } return; @@ -1166,14 +1182,14 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * implementation would need to wrap a sequence number, it must * renegotiate instead." */ - private void checkSequenceNumber(Authenticator authenticator, byte type) + private void checkSequenceNumber(MAC mac, byte type) throws IOException { /* * Don't bother to check the sequence number for error or * closed connections, or NULL MAC. */ - if (connectionState >= cs_ERROR || authenticator == MAC.NULL) { + if (connectionState >= cs_ERROR || mac == MAC.NULL) { return; } @@ -1181,7 +1197,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * Conservatively, close the connection immediately when the * sequence number is close to overflow */ - if (authenticator.seqNumOverflow()) { + if (mac.seqNumOverflow()) { /* * TLS protocols do not define a error alert for sequence * number overflow. We use handshake_failure error alert @@ -1203,7 +1219,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * Don't bother to kickstart the renegotiation when the local is * asking for it. */ - if ((type != Record.ct_handshake) && authenticator.seqNumIsHuge()) { + if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) { if (debug != null && Debug.isOn("ssl")) { System.out.println(Thread.currentThread().getName() + ", request renegotiation " + @@ -2065,7 +2081,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { try { readCipher = handshaker.newReadCipher(); - readAuthenticator = handshaker.newReadAuthenticator(); + readMAC = handshaker.newReadMAC(); } catch (GeneralSecurityException e) { // "can't happen" throw new SSLException("Algorithm missing: ", e); @@ -2096,7 +2112,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { try { writeCipher = handshaker.newWriteCipher(); - writeAuthenticator = handshaker.newWriteAuthenticator(); + writeMAC = handshaker.newWriteMAC(); } catch (GeneralSecurityException e) { // "can't happen" throw new SSLException("Algorithm missing: ", e); diff --git a/jdk/test/sun/security/ec/TestEC.java b/jdk/test/sun/security/ec/TestEC.java index 77217cae467..41d0f0361da 100644 --- a/jdk/test/sun/security/ec/TestEC.java +++ b/jdk/test/sun/security/ec/TestEC.java @@ -21,11 +21,6 @@ * questions. */ -// -// SunJSSE does not support dynamic system properties, no way to re-use -// system properties in samevm/agentvm mode. -// - /** * @test * @bug 6840752 @@ -35,7 +30,7 @@ * @library ../pkcs11/sslecc * @library ../../../java/security/testlibrary * @compile -XDignore.symbol.file TestEC.java - * @run main/othervm TestEC + * @run main TestEC */ import java.security.NoSuchProviderException; diff --git a/jdk/test/sun/security/pkcs11/fips/CipherTest.java b/jdk/test/sun/security/pkcs11/fips/CipherTest.java index 2fc81c49c54..32bc6df4e16 100644 --- a/jdk/test/sun/security/pkcs11/fips/CipherTest.java +++ b/jdk/test/sun/security/pkcs11/fips/CipherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -147,25 +147,6 @@ public class CipherTest { CS_16("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x0303, 0xFFFF), CS_17("TLS_RSA_WITH_NULL_SHA256", 0x0303, 0xFFFF), - CS_20("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_21("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_22("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_23("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_24("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_25("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_26("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_27("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - - CS_28("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_29("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_30("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_31("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_32("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_33("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - - CS_34("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_35("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - // cipher suites obsoleted since TLS 1.2 CS_50("SSL_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303), CS_51("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303), diff --git a/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java b/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java index 26ecec4df0f..64153f58d20 100644 --- a/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java +++ b/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -147,25 +147,6 @@ public class CipherTest { CS_16("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x0303, 0xFFFF), CS_17("TLS_RSA_WITH_NULL_SHA256", 0x0303, 0xFFFF), - CS_20("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_21("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_22("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_23("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_24("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_25("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_26("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_27("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - - CS_28("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_29("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_30("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_31("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_32("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_33("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - - CS_34("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_35("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - // cipher suites obsoleted since TLS 1.2 CS_50("SSL_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303), CS_51("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303), diff --git a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java index 564342b8ee6..aeaf5792cb9 100644 --- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java +++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java @@ -21,16 +21,14 @@ * questions. */ -// -// SunJSSE does not support dynamic system properties, no way to re-use -// system properties in samevm/agentvm mode. -// - /* * @test * @bug 7031830 * @summary bad_record_mac failure on TLSv1.2 enabled connection with SSLEngine * @run main/othervm SSLEngineBadBufferArrayAccess + * + * SunJSSE does not support dynamic system properties, no way to re-use + * system properties in samevm/agentvm mode. */ /** diff --git a/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKeyGCM.java b/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKeyGCM.java deleted file mode 100644 index ac78134f6d4..00000000000 --- a/jdk/test/sun/security/ssl/javax/net/ssl/TLSv12/ShortRSAKeyGCM.java +++ /dev/null @@ -1,445 +0,0 @@ -/* - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -// -// SunJSSE does not support dynamic system properties, no way to re-use -// system properties in samevm/agentvm mode. -// - -/* - * @test - * @bug 7030966 - * @summary Support AEAD CipherSuites - * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - * @run main/othervm ShortRSAKeyGCM PKIX TLS_RSA_WITH_AES_128_GCM_SHA256 - * @run main/othervm ShortRSAKeyGCM PKIX TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 - * @run main/othervm ShortRSAKeyGCM PKIX TLS_DH_anon_WITH_AES_128_GCM_SHA256 - */ - -/* - * Need additional key materials to run the following cases. - * - * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 - * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 - * - * Need unlimited JCE Unlimited Strength Jurisdiction Policy to run the - * following cases. - * - * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 - * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 - * @run main/othervm ShortRSAKeyGCM PKIX TLS_RSA_WITH_AES_256_GCM_SHA384 - * @run main/othervm ShortRSAKeyGCM PKIX TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 - * @run main/othervm ShortRSAKeyGCM PKIX TLS_DH_anon_WITH_AES_256_GCM_SHA384 - */ - -import java.net.*; -import java.util.*; -import java.io.*; -import javax.net.ssl.*; -import java.security.Security; -import java.security.KeyStore; -import java.security.KeyFactory; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.spec.*; -import java.security.interfaces.*; -import sun.misc.BASE64Decoder; - - -public class ShortRSAKeyGCM { - - /* - * ============================================================= - * Set the various variables needed for the tests, then - * specify what tests to run on each side. - */ - - /* - * Should we run the client or server in a separate thread? - * Both sides can throw exceptions, but do you have a preference - * as to which side should be the main thread. - */ - static boolean separateServerThread = true; - - /* - * Where do we find the keystores? - */ - // Certificates and key used in the test. - static String trustedCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTEwODE5MDE1MjE5WhcNMzIwNzI5MDE1MjE5WjA7MQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" + - "KoZIhvcNAQEBBQADgY0AMIGJAoGBAM8orG08DtF98TMSscjGsidd1ZoN4jiDpi8U\n" + - "ICz+9dMm1qM1d7O2T+KH3/mxyox7Rc2ZVSCaUD0a3CkhPMnlAx8V4u0H+E9sqso6\n" + - "iDW3JpOyzMExvZiRgRG/3nvp55RMIUV4vEHOZ1QbhuqG4ebN0Vz2DkRft7+flthf\n" + - "vDld6f5JAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLl81dnfp0wDrv0OJ1sxlWzH83Xh\n" + - "MGMGA1UdIwRcMFqAFLl81dnfp0wDrv0OJ1sxlWzH83XhoT+kPTA7MQswCQYDVQQG\n" + - "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" + - "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" + - "BQADgYEALlgaH1gWtoBZ84EW8Hu6YtGLQ/L9zIFmHonUPZwn3Pr//icR9Sqhc3/l\n" + - "pVTxOINuFHLRz4BBtEylzRIOPzK3tg8XwuLb1zd0db90x3KBCiAL6E6cklGEPwLe\n" + - "XYMHDn9eDsaq861Tzn6ZwzMgw04zotPMoZN0mVd/3Qca8UJFucE=\n" + - "-----END CERTIFICATE-----"; - - static String targetCertStr = - "-----BEGIN CERTIFICATE-----\n" + - "MIICNDCCAZ2gAwIBAgIBDDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" + - "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" + - "MTExMTA3MTM1NTUyWhcNMzEwNzI1MTM1NTUyWjBPMQswCQYDVQQGEwJVUzENMAsG\n" + - "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" + - "BAMTCWxvY2FsaG9zdDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3Pb49OSPfOD2G\n" + - "HSXFCFx1GJEZfqG9ZUf7xuIi/ra5dLjPGAaoY5QF2QOa8VnOriQCXDfyXHxsuRnE\n" + - "OomxL7EVAgMBAAGjeDB2MAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUXNCJK3/dtCIc\n" + - "xb+zlA/JINlvs/MwHwYDVR0jBBgwFoAUuXzV2d+nTAOu/Q4nWzGVbMfzdeEwJwYD\n" + - "VR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAzANBgkqhkiG9w0B\n" + - "AQQFAAOBgQB2qIDUxA2caMPpGtUACZAPRUtrGssCINIfItETXJZCx/cRuZ5sP4D9\n" + - "N1acoNDn0hCULe3lhXAeTC9NZ97680yJzregQMV5wATjo1FGsKY30Ma+sc/nfzQW\n" + - "+h/7RhYtoG0OTsiaDCvyhI6swkNJzSzrAccPY4+ZgU8HiDLzZTmM3Q==\n" + - "-----END CERTIFICATE-----"; - - // Private key in the format of PKCS#8, key size is 512 bits. - static String targetPrivateKey = - "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtz2+PTkj3zg9hh0l\n" + - "xQhcdRiRGX6hvWVH+8biIv62uXS4zxgGqGOUBdkDmvFZzq4kAlw38lx8bLkZxDqJ\n" + - "sS+xFQIDAQABAkByx/5Oo2hQ/w2q4L8z+NTRlJ3vdl8iIDtC/4XPnfYfnGptnpG6\n" + - "ZThQRvbMZiai0xHQPQMszvAHjZVme1eDl3EBAiEA3aKJHynPVCEJhpfCLWuMwX5J\n" + - "1LntwJO7NTOyU5m8rPECIQDTpzn5X44r2rzWBDna/Sx7HW9IWCxNgUD2Eyi2nA7W\n" + - "ZQIgJerEorw4aCAuzQPxiGu57PB6GRamAihEAtoRTBQlH0ECIQDN08FgTtnesgCU\n" + - "DFYLLcw1CiHvc7fZw4neBDHCrC8NtQIgA8TOUkGnpCZlQ0KaI8KfKWI+vxFcgFnH\n" + - "3fnqsTgaUs4="; - - static char passphrase[] = "passphrase".toCharArray(); - - /* - * Is the server ready to serve? - */ - volatile static boolean serverReady = false; - - /* - * Turn on SSL debugging? - */ - static boolean debug = false; - - /* - * Define the server side of the test. - * - * If the server prematurely exits, serverReady will be set to true - * to avoid infinite hangs. - */ - void doServerSide() throws Exception { - SSLContext context = generateSSLContext(null, targetCertStr, - targetPrivateKey); - SSLServerSocketFactory sslssf = context.getServerSocketFactory(); - SSLServerSocket sslServerSocket = - (SSLServerSocket)sslssf.createServerSocket(serverPort); - serverPort = sslServerSocket.getLocalPort(); - - /* - * Signal Client, we're ready for his connect. - */ - serverReady = true; - - SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept(); - sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites()); - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); - - sslIS.read(); - sslOS.write('A'); - sslOS.flush(); - - sslSocket.close(); - } - - /* - * Define the client side of the test. - * - * If the server prematurely exits, serverReady will be set to true - * to avoid infinite hangs. - */ - void doClientSide() throws Exception { - - /* - * Wait for server to get started. - */ - while (!serverReady) { - Thread.sleep(50); - } - - SSLContext context = generateSSLContext(trustedCertStr, null, null); - SSLSocketFactory sslsf = context.getSocketFactory(); - - SSLSocket sslSocket = - (SSLSocket)sslsf.createSocket("localhost", serverPort); - - // enable TLSv1.2 only - sslSocket.setEnabledProtocols(new String[] {"TLSv1.2"}); - - // enable a block cipher - sslSocket.setEnabledCipherSuites(new String[] {cipherSuite}); - - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); - - sslOS.write('B'); - sslOS.flush(); - sslIS.read(); - - sslSocket.close(); - } - - /* - * ============================================================= - * The remainder is just support stuff - */ - private static String tmAlgorithm; // trust manager - private static String cipherSuite; // cipher suite - - private static void parseArguments(String[] args) { - tmAlgorithm = args[0]; - cipherSuite = args[1]; - } - - private static SSLContext generateSSLContext(String trustedCertStr, - String keyCertStr, String keySpecStr) throws Exception { - - // generate certificate from cert string - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - - // create a key store - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(null, null); - - // import the trused cert - Certificate trusedCert = null; - ByteArrayInputStream is = null; - if (trustedCertStr != null) { - is = new ByteArrayInputStream(trustedCertStr.getBytes()); - trusedCert = cf.generateCertificate(is); - is.close(); - - ks.setCertificateEntry("RSA Export Signer", trusedCert); - } - - if (keyCertStr != null) { - // generate the private key. - PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec( - new BASE64Decoder().decodeBuffer(keySpecStr)); - KeyFactory kf = KeyFactory.getInstance("RSA"); - RSAPrivateKey priKey = - (RSAPrivateKey)kf.generatePrivate(priKeySpec); - - // generate certificate chain - is = new ByteArrayInputStream(keyCertStr.getBytes()); - Certificate keyCert = cf.generateCertificate(is); - is.close(); - - Certificate[] chain = null; - if (trusedCert != null) { - chain = new Certificate[2]; - chain[0] = keyCert; - chain[1] = trusedCert; - } else { - chain = new Certificate[1]; - chain[0] = keyCert; - } - - // import the key entry. - ks.setKeyEntry("Whatever", priKey, passphrase, chain); - } - - // create SSL context - TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm); - tmf.init(ks); - - SSLContext ctx = SSLContext.getInstance("TLS"); - if (keyCertStr != null && !keyCertStr.isEmpty()) { - KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509"); - kmf.init(ks, passphrase); - - ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - ks = null; - } else { - ctx.init(null, tmf.getTrustManagers(), null); - } - - return ctx; - } - - - // use any free port by default - volatile int serverPort = 0; - - volatile Exception serverException = null; - volatile Exception clientException = null; - - public static void main(String[] args) throws Exception { - // reset the security property to make sure that the algorithms - // and keys used in this test are not disabled. - Security.setProperty("jdk.certpath.disabledAlgorithms", "MD2"); - - if (debug) { - System.setProperty("javax.net.debug", "all"); - } - - /* - * Get the customized arguments. - */ - parseArguments(args); - - /* - * Start the tests. - */ - new ShortRSAKeyGCM(); - } - - Thread clientThread = null; - Thread serverThread = null; - - /* - * Primary constructor, used to drive remainder of the test. - * - * Fork off the other side, then do your work. - */ - ShortRSAKeyGCM() throws Exception { - try { - if (separateServerThread) { - startServer(true); - startClient(false); - } else { - startClient(true); - startServer(false); - } - } catch (Exception e) { - // swallow for now. Show later - } - - /* - * Wait for other side to close down. - */ - if (separateServerThread) { - serverThread.join(); - } else { - clientThread.join(); - } - - /* - * When we get here, the test is pretty much over. - * Which side threw the error? - */ - Exception local; - Exception remote; - String whichRemote; - - if (separateServerThread) { - remote = serverException; - local = clientException; - whichRemote = "server"; - } else { - remote = clientException; - local = serverException; - whichRemote = "client"; - } - - /* - * If both failed, return the curthread's exception, but also - * print the remote side Exception - */ - if ((local != null) && (remote != null)) { - System.out.println(whichRemote + " also threw:"); - remote.printStackTrace(); - System.out.println(); - throw local; - } - - if (remote != null) { - throw remote; - } - - if (local != null) { - throw local; - } - } - - void startServer(boolean newThread) throws Exception { - if (newThread) { - serverThread = new Thread() { - public void run() { - try { - doServerSide(); - } catch (Exception e) { - /* - * Our server thread just died. - * - * Release the client, if not active already... - */ - System.err.println("Server died..." + e); - serverReady = true; - serverException = e; - } - } - }; - serverThread.start(); - } else { - try { - doServerSide(); - } catch (Exception e) { - serverException = e; - } finally { - serverReady = true; - } - } - } - - void startClient(boolean newThread) throws Exception { - if (newThread) { - clientThread = new Thread() { - public void run() { - try { - doClientSide(); - } catch (Exception e) { - /* - * Our client thread just died. - */ - System.err.println("Client died..." + e); - clientException = e; - } - } - }; - clientThread.start(); - } else { - try { - doClientSide(); - } catch (Exception e) { - clientException = e; - } - } - } -} diff --git a/jdk/test/sun/security/ssl/sanity/ciphersuites/CipherSuitesInOrder.java b/jdk/test/sun/security/ssl/sanity/ciphersuites/CipherSuitesInOrder.java index 9dc1a923dc9..3d081c1bd40 100644 --- a/jdk/test/sun/security/ssl/sanity/ciphersuites/CipherSuitesInOrder.java +++ b/jdk/test/sun/security/ssl/sanity/ciphersuites/CipherSuitesInOrder.java @@ -21,15 +21,13 @@ * questions. */ -// -// SunJSSE does not support dynamic system properties, no way to re-use -// system properties in samevm/agentvm mode. -// - /* * @test * @bug 7174244 * @summary NPE in Krb5ProxyImpl.getServerKeys() + * + * SunJSSE does not support dynamic system properties, no way to re-use + * system properties in samevm/agentvm mode. * @run main/othervm CipherSuitesInOrder */ @@ -74,22 +72,6 @@ public class CipherSuitesInOrder { "SSL_RSA_WITH_RC4_128_SHA", "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", "TLS_ECDH_RSA_WITH_RC4_128_SHA", - - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", - "TLS_RSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", - "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", - "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - "TLS_RSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", - "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", - "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA", @@ -101,9 +83,6 @@ public class CipherSuitesInOrder { "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", - "TLS_DH_anon_WITH_AES_256_GCM_SHA384", - "TLS_DH_anon_WITH_AES_128_GCM_SHA256", - "TLS_DH_anon_WITH_AES_256_CBC_SHA256", "TLS_ECDH_anon_WITH_AES_256_CBC_SHA", "TLS_DH_anon_WITH_AES_256_CBC_SHA", diff --git a/jdk/test/sun/security/ssl/sanity/interop/CipherTest.java b/jdk/test/sun/security/ssl/sanity/interop/CipherTest.java index 106d4a75e53..9c5af7eda4a 100644 --- a/jdk/test/sun/security/ssl/sanity/interop/CipherTest.java +++ b/jdk/test/sun/security/ssl/sanity/interop/CipherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,25 +148,6 @@ public class CipherTest { CS_16("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x0303, 0xFFFF), CS_17("TLS_RSA_WITH_NULL_SHA256", 0x0303, 0xFFFF), - CS_20("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_21("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_22("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_23("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_24("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_25("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_26("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_27("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - - CS_28("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_29("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_30("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_31("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_32("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - CS_33("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - - CS_34("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF), - CS_35("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF), - // cipher suites obsoleted since TLS 1.2 CS_50("SSL_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303), CS_51("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303), diff --git a/jdk/test/sun/security/ssl/templates/SSLSocketSSLEngineTemplate.java b/jdk/test/sun/security/ssl/templates/SSLSocketSSLEngineTemplate.java index 6bd63ae7104..e31409a0f74 100644 --- a/jdk/test/sun/security/ssl/templates/SSLSocketSSLEngineTemplate.java +++ b/jdk/test/sun/security/ssl/templates/SSLSocketSSLEngineTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,15 +21,14 @@ * questions. */ -// -// SunJSSE does not support dynamic system properties, no way to re-use -// system properties in samevm/agentvm mode. -// - /* * @test * @bug 7105780 * @summary Add SSLSocket client/SSLEngine server to templates directory. + * + * SunJSSE does not support dynamic system properties, no way to re-use + * system properties in samevm/agentvm mode. + * * @run main/othervm SSLSocketSSLEngineTemplate */ From 70b26044ba6130ab3b7fc17d7ac7abe116e204ed Mon Sep 17 00:00:00 2001 From: Coleen Phillimore <coleenp@openjdk.org> Date: Wed, 13 Mar 2013 09:10:35 -0400 Subject: [PATCH 169/180] 8009836: nsk/regression/b4222717 fails with empty stack trace Some zeroing was missed for bug 8003553, causing empty stack traces and Xcom crashes, add back zeroing to metablock Reviewed-by: dholmes, rbackman --- hotspot/src/share/vm/memory/metablock.cpp | 5 +++-- hotspot/src/share/vm/oops/constMethod.cpp | 3 ++- hotspot/src/share/vm/oops/method.cpp | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/memory/metablock.cpp b/hotspot/src/share/vm/memory/metablock.cpp index 7ffaec57f71..450d2c3193d 100644 --- a/hotspot/src/share/vm/memory/metablock.cpp +++ b/hotspot/src/share/vm/memory/metablock.cpp @@ -65,9 +65,10 @@ Metablock* Metablock::initialize(MetaWord* p, size_t word_size) { } Metablock* result = (Metablock*) p; + + // Clear the memory + Copy::fill_to_aligned_words((HeapWord*)result, word_size); #ifdef ASSERT - // Add just to catch missing initializations - Copy::fill_to_words((HeapWord*) result, word_size, 0xf1f1f1f1); result->set_word_size(word_size); #endif return result; diff --git a/hotspot/src/share/vm/oops/constMethod.cpp b/hotspot/src/share/vm/oops/constMethod.cpp index ad02e5df35b..dfee4244920 100644 --- a/hotspot/src/share/vm/oops/constMethod.cpp +++ b/hotspot/src/share/vm/oops/constMethod.cpp @@ -55,7 +55,7 @@ ConstMethod::ConstMethod(int byte_code_size, set_stackmap_data(NULL); set_code_size(byte_code_size); set_constMethod_size(size); - set_inlined_tables_length(sizes); + set_inlined_tables_length(sizes); // sets _flags set_method_type(method_type); assert(this->size() == size, "wrong size for object"); set_name_index(0); @@ -64,6 +64,7 @@ ConstMethod::ConstMethod(int byte_code_size, set_max_stack(0); set_max_locals(0); set_method_idnum(0); + set_size_of_parameters(0); } diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index da19ccaad31..0ee78f17605 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -87,6 +87,9 @@ Method::Method(ConstMethod* xconst, AccessFlags access_flags, int size) { #endif set_intrinsic_id(vmIntrinsics::_none); set_jfr_towrite(false); + set_force_inline(false); + set_hidden(false); + set_dont_inline(false); set_method_data(NULL); set_interpreter_throwout_count(0); set_vtable_index(Method::garbage_vtable_index); From b243475fd27dbb37d9def8075a4adc1815545606 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore <coleenp@openjdk.org> Date: Wed, 13 Mar 2013 15:15:56 -0400 Subject: [PATCH 170/180] 8009829: CDS: JDK JPRT test fails crash in Symbol::equals() -Xshare:dump was creating a Symbol in C_heap. There's an assert there that jdk jprt wasn't hitting because it was only done in product Reviewed-by: dholmes, hseigel, iklam --- hotspot/src/share/vm/classfile/symbolTable.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp index 87de232d7a5..fc19dd55564 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.cpp +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, 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 @@ -49,18 +49,17 @@ Symbol* SymbolTable::allocate_symbol(const u1* name, int len, bool c_heap, TRAPS Symbol* sym; - if (c_heap) { + if (DumpSharedSpaces) { + // Allocate all symbols to CLD shared metaspace + sym = new (len, ClassLoaderData::the_null_class_loader_data(), THREAD) Symbol(name, len, -1); + } else if (c_heap) { // refcount starts as 1 - assert(!DumpSharedSpaces, "never allocate to C heap"); sym = new (len, THREAD) Symbol(name, len, 1); assert(sym != NULL, "new should call vm_exit_out_of_memory if C_HEAP is exhausted"); } else { - if (DumpSharedSpaces) { - sym = new (len, ClassLoaderData::the_null_class_loader_data(), THREAD) Symbol(name, len, -1); - } else { + // Allocate to global arena sym = new (len, arena(), THREAD) Symbol(name, len, -1); } - } return sym; } From c5867cb71b375e548b7c72339172833e07867af0 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore <coleenp@openjdk.org> Date: Wed, 13 Mar 2013 17:34:29 -0400 Subject: [PATCH 171/180] 8003419: NPG: Clean up metadata created during class loading if failure Store metadata on ClassFileParser instance to be cleaned up by destructor. This enabled some refactoring of the enormous parseClassFile function. Reviewed-by: jmasa, acorn --- .../share/vm/classfile/classFileParser.cpp | 1958 ++++++++--------- .../share/vm/classfile/classFileParser.hpp | 164 +- hotspot/src/share/vm/oops/constMethod.cpp | 6 + hotspot/src/share/vm/oops/constMethod.hpp | 1 + hotspot/src/share/vm/oops/instanceKlass.cpp | 110 +- hotspot/src/share/vm/oops/instanceKlass.hpp | 21 +- 6 files changed, 1155 insertions(+), 1105 deletions(-) diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index 005bda61bd3..9f2a9f419a4 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -90,8 +90,7 @@ // Extension method support. #define JAVA_8_VERSION 52 - -void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, constantPoolHandle cp, int length, TRAPS) { +void ClassFileParser::parse_constant_pool_entries(int length, TRAPS) { // Use a local copy of ClassFileStream. It helps the C++ compiler to optimize // this function (_current can be allocated in a register, with scalar // replacement of aggregates). The _current pointer is copied back to @@ -104,7 +103,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, assert(cfs->allocated_on_stack(),"should be local"); u1* old_current = cfs0->current(); #endif - Handle class_loader(THREAD, loader_data->class_loader()); + Handle class_loader(THREAD, _loader_data->class_loader()); // Used for batching symbol allocations. const char* names[SymbolTable::symbol_alloc_batch_size]; @@ -124,7 +123,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, { cfs->guarantee_more(3, CHECK); // name_index, tag/access_flags u2 name_index = cfs->get_u2_fast(); - cp->klass_index_at_put(index, name_index); + _cp->klass_index_at_put(index, name_index); } break; case JVM_CONSTANT_Fieldref : @@ -132,7 +131,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags u2 class_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast(); - cp->field_at_put(index, class_index, name_and_type_index); + _cp->field_at_put(index, class_index, name_and_type_index); } break; case JVM_CONSTANT_Methodref : @@ -140,7 +139,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags u2 class_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast(); - cp->method_at_put(index, class_index, name_and_type_index); + _cp->method_at_put(index, class_index, name_and_type_index); } break; case JVM_CONSTANT_InterfaceMethodref : @@ -148,14 +147,14 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags u2 class_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast(); - cp->interface_method_at_put(index, class_index, name_and_type_index); + _cp->interface_method_at_put(index, class_index, name_and_type_index); } break; case JVM_CONSTANT_String : { cfs->guarantee_more(3, CHECK); // string_index, tag/access_flags u2 string_index = cfs->get_u2_fast(); - cp->string_index_at_put(index, string_index); + _cp->string_index_at_put(index, string_index); } break; case JVM_CONSTANT_MethodHandle : @@ -174,11 +173,11 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs->guarantee_more(4, CHECK); // ref_kind, method_index, tag/access_flags u1 ref_kind = cfs->get_u1_fast(); u2 method_index = cfs->get_u2_fast(); - cp->method_handle_index_at_put(index, ref_kind, method_index); + _cp->method_handle_index_at_put(index, ref_kind, method_index); } else if (tag == JVM_CONSTANT_MethodType) { cfs->guarantee_more(3, CHECK); // signature_index, tag/access_flags u2 signature_index = cfs->get_u2_fast(); - cp->method_type_index_at_put(index, signature_index); + _cp->method_type_index_at_put(index, signature_index); } else { ShouldNotReachHere(); } @@ -200,21 +199,21 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, u2 name_and_type_index = cfs->get_u2_fast(); if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index) _max_bootstrap_specifier_index = (int) bootstrap_specifier_index; // collect for later - cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index); + _cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index); } break; case JVM_CONSTANT_Integer : { cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags u4 bytes = cfs->get_u4_fast(); - cp->int_at_put(index, (jint) bytes); + _cp->int_at_put(index, (jint) bytes); } break; case JVM_CONSTANT_Float : { cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags u4 bytes = cfs->get_u4_fast(); - cp->float_at_put(index, *(jfloat*)&bytes); + _cp->float_at_put(index, *(jfloat*)&bytes); } break; case JVM_CONSTANT_Long : @@ -225,7 +224,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, { cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags u8 bytes = cfs->get_u8_fast(); - cp->long_at_put(index, bytes); + _cp->long_at_put(index, bytes); } index++; // Skip entry following eigth-byte constant, see JVM book p. 98 break; @@ -237,7 +236,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, { cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags u8 bytes = cfs->get_u8_fast(); - cp->double_at_put(index, *(jdouble*)&bytes); + _cp->double_at_put(index, *(jdouble*)&bytes); } index++; // Skip entry following eigth-byte constant, see JVM book p. 98 break; @@ -246,7 +245,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs->guarantee_more(5, CHECK); // name_index, signature_index, tag/access_flags u2 name_index = cfs->get_u2_fast(); u2 signature_index = cfs->get_u2_fast(); - cp->name_and_type_at_put(index, name_index, signature_index); + _cp->name_and_type_at_put(index, name_index, signature_index); } break; case JVM_CONSTANT_Utf8 : @@ -283,11 +282,11 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, indices[names_count] = index; hashValues[names_count++] = hash; if (names_count == SymbolTable::symbol_alloc_batch_size) { - SymbolTable::new_symbols(loader_data, cp, names_count, names, lengths, indices, hashValues, CHECK); + SymbolTable::new_symbols(_loader_data, _cp, names_count, names, lengths, indices, hashValues, CHECK); names_count = 0; } } else { - cp->symbol_at_put(index, result); + _cp->symbol_at_put(index, result); } } break; @@ -300,7 +299,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, // Allocate the remaining symbols if (names_count > 0) { - SymbolTable::new_symbols(loader_data, cp, names_count, names, lengths, indices, hashValues, CHECK); + SymbolTable::new_symbols(_loader_data, _cp, names_count, names, lengths, indices, hashValues, CHECK); } // Copy _current pointer of local copy back to stream(). @@ -310,23 +309,6 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs0->set_current(cfs1.current()); } -// This class unreferences constant pool symbols if an error has occurred -// while parsing the class before it is assigned into the class. -// If it gets an error after that it is unloaded and the constant pool will -// be cleaned up then. -class ConstantPoolCleaner : public StackObj { - constantPoolHandle _cphandle; - bool _in_error; - public: - ConstantPoolCleaner(constantPoolHandle cp) : _cphandle(cp), _in_error(true) {} - ~ConstantPoolCleaner() { - if (_in_error && _cphandle.not_null()) { - _cphandle->unreference_symbols(); - } - } - void set_in_error(bool clean) { _in_error = clean; } -}; - bool inline valid_cp_range(int index, int length) { return (index > 0 && index < length); } inline Symbol* check_symbol_at(constantPoolHandle cp, int index) { @@ -336,7 +318,7 @@ inline Symbol* check_symbol_at(constantPoolHandle cp, int index) { return NULL; } -constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_data, TRAPS) { +constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) { ClassFileStream* cfs = stream(); constantPoolHandle nullHandle; @@ -345,16 +327,13 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ guarantee_property( length >= 1, "Illegal constant pool size %u in class file %s", length, CHECK_(nullHandle)); - ConstantPool* constant_pool = - ConstantPool::allocate(loader_data, - length, - CHECK_(nullHandle)); + ConstantPool* constant_pool = ConstantPool::allocate(_loader_data, length, + CHECK_(nullHandle)); + _cp = constant_pool; // save in case of errors constantPoolHandle cp (THREAD, constant_pool); - ConstantPoolCleaner cp_in_error(cp); // set constant pool to be cleaned up. - // parsing constant pool entries - parse_constant_pool_entries(loader_data, cp, length, CHECK_(nullHandle)); + parse_constant_pool_entries(length, CHECK_(nullHandle)); int index = 1; // declared outside of loops for portability @@ -373,8 +352,7 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ if (!_need_verify) break; int klass_ref_index = cp->klass_ref_index_at(index); int name_and_type_ref_index = cp->name_and_type_ref_index_at(index); - check_property(valid_cp_range(klass_ref_index, length) && - is_klass_reference(cp, klass_ref_index), + check_property(valid_klass_reference_at(klass_ref_index), "Invalid constant pool index %u in class file %s", klass_ref_index, CHECK_(nullHandle)); @@ -404,16 +382,12 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ if (!_need_verify) break; int name_ref_index = cp->name_ref_index_at(index); int signature_ref_index = cp->signature_ref_index_at(index); - check_property( - valid_cp_range(name_ref_index, length) && - cp->tag_at(name_ref_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - name_ref_index, CHECK_(nullHandle)); - check_property( - valid_cp_range(signature_ref_index, length) && - cp->tag_at(signature_ref_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - signature_ref_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(name_ref_index), + "Invalid constant pool index %u in class file %s", + name_ref_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(signature_ref_index), + "Invalid constant pool index %u in class file %s", + signature_ref_index, CHECK_(nullHandle)); break; } case JVM_CONSTANT_Utf8 : @@ -425,22 +399,18 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ case JVM_CONSTANT_ClassIndex : { int class_index = cp->klass_index_at(index); - check_property( - valid_cp_range(class_index, length) && - cp->tag_at(class_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - class_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(class_index), + "Invalid constant pool index %u in class file %s", + class_index, CHECK_(nullHandle)); cp->unresolved_klass_at_put(index, cp->symbol_at(class_index)); } break; case JVM_CONSTANT_StringIndex : { int string_index = cp->string_index_at(index); - check_property( - valid_cp_range(string_index, length) && - cp->tag_at(string_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - string_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(string_index), + "Invalid constant pool index %u in class file %s", + string_index, CHECK_(nullHandle)); Symbol* sym = cp->symbol_at(string_index); cp->unresolved_string_at_put(index, sym); } @@ -491,12 +461,9 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ case JVM_CONSTANT_MethodType : { int ref_index = cp->method_type_index_at(index); - check_property( - valid_cp_range(ref_index, length) && - cp->tag_at(ref_index).is_utf8() && - EnableInvokeDynamic, - "Invalid constant pool index %u in class file %s", - ref_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(ref_index) && EnableInvokeDynamic, + "Invalid constant pool index %u in class file %s", + ref_index, CHECK_(nullHandle)); } break; case JVM_CONSTANT_InvokeDynamic : @@ -541,7 +508,6 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ } if (!_need_verify) { - cp_in_error.set_in_error(false); return cp; } @@ -664,7 +630,6 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ } // end of switch } // end of for - cp_in_error.set_in_error(false); return cp; } @@ -786,93 +751,92 @@ bool put_after_lookup(Symbol* name, Symbol* sig, NameSigHash** table) { } -Array<Klass*>* ClassFileParser::parse_interfaces(constantPoolHandle cp, - int length, - ClassLoaderData* loader_data, +Array<Klass*>* ClassFileParser::parse_interfaces(int length, Handle protection_domain, Symbol* class_name, bool* has_default_methods, TRAPS) { - ClassFileStream* cfs = stream(); - assert(length > 0, "only called for length>0"); - // FIXME: Leak at later OOM. - Array<Klass*>* interfaces = MetadataFactory::new_array<Klass*>(loader_data, length, NULL, CHECK_NULL); + if (length == 0) { + _local_interfaces = Universe::the_empty_klass_array(); + } else { + ClassFileStream* cfs = stream(); + assert(length > 0, "only called for length>0"); + _local_interfaces = MetadataFactory::new_array<Klass*>(_loader_data, length, NULL, CHECK_NULL); - int index; - for (index = 0; index < length; index++) { - u2 interface_index = cfs->get_u2(CHECK_NULL); - KlassHandle interf; - check_property( - valid_cp_range(interface_index, cp->length()) && - is_klass_reference(cp, interface_index), - "Interface name has bad constant pool index %u in class file %s", - interface_index, CHECK_NULL); - if (cp->tag_at(interface_index).is_klass()) { - interf = KlassHandle(THREAD, cp->resolved_klass_at(interface_index)); - } else { - Symbol* unresolved_klass = cp->klass_name_at(interface_index); - - // Don't need to check legal name because it's checked when parsing constant pool. - // But need to make sure it's not an array type. - guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY, - "Bad interface name in class file %s", CHECK_NULL); - Handle class_loader(THREAD, loader_data->class_loader()); - - // Call resolve_super so classcircularity is checked - Klass* k = SystemDictionary::resolve_super_or_fail(class_name, - unresolved_klass, class_loader, protection_domain, - false, CHECK_NULL); - interf = KlassHandle(THREAD, k); - } - - if (!interf()->is_interface()) { - THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", NULL); - } - if (InstanceKlass::cast(interf())->has_default_methods()) { - *has_default_methods = true; - } - interfaces->at_put(index, interf()); - } - - if (!_need_verify || length <= 1) { - return interfaces; - } - - // Check if there's any duplicates in interfaces - ResourceMark rm(THREAD); - NameSigHash** interface_names = NEW_RESOURCE_ARRAY_IN_THREAD( - THREAD, NameSigHash*, HASH_ROW_SIZE); - initialize_hashtable(interface_names); - bool dup = false; - { - debug_only(No_Safepoint_Verifier nsv;) + int index; for (index = 0; index < length; index++) { - Klass* k = interfaces->at(index); - Symbol* name = InstanceKlass::cast(k)->name(); - // If no duplicates, add (name, NULL) in hashtable interface_names. - if (!put_after_lookup(name, NULL, interface_names)) { - dup = true; - break; + u2 interface_index = cfs->get_u2(CHECK_NULL); + KlassHandle interf; + check_property( + valid_klass_reference_at(interface_index), + "Interface name has bad constant pool index %u in class file %s", + interface_index, CHECK_NULL); + if (_cp->tag_at(interface_index).is_klass()) { + interf = KlassHandle(THREAD, _cp->resolved_klass_at(interface_index)); + } else { + Symbol* unresolved_klass = _cp->klass_name_at(interface_index); + + // Don't need to check legal name because it's checked when parsing constant pool. + // But need to make sure it's not an array type. + guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY, + "Bad interface name in class file %s", CHECK_NULL); + Handle class_loader(THREAD, _loader_data->class_loader()); + + // Call resolve_super so classcircularity is checked + Klass* k = SystemDictionary::resolve_super_or_fail(class_name, + unresolved_klass, class_loader, protection_domain, + false, CHECK_NULL); + interf = KlassHandle(THREAD, k); + } + + if (!interf()->is_interface()) { + THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", NULL); + } + if (InstanceKlass::cast(interf())->has_default_methods()) { + *has_default_methods = true; + } + _local_interfaces->at_put(index, interf()); + } + + if (!_need_verify || length <= 1) { + return _local_interfaces; + } + + // Check if there's any duplicates in interfaces + ResourceMark rm(THREAD); + NameSigHash** interface_names = NEW_RESOURCE_ARRAY_IN_THREAD( + THREAD, NameSigHash*, HASH_ROW_SIZE); + initialize_hashtable(interface_names); + bool dup = false; + { + debug_only(No_Safepoint_Verifier nsv;) + for (index = 0; index < length; index++) { + Klass* k = _local_interfaces->at(index); + Symbol* name = InstanceKlass::cast(k)->name(); + // If no duplicates, add (name, NULL) in hashtable interface_names. + if (!put_after_lookup(name, NULL, interface_names)) { + dup = true; + break; + } } } + if (dup) { + classfile_parse_error("Duplicate interface name in class file %s", CHECK_NULL); + } } - if (dup) { - classfile_parse_error("Duplicate interface name in class file %s", CHECK_NULL); - } - - return interfaces; + return _local_interfaces; } -void ClassFileParser::verify_constantvalue(int constantvalue_index, int signature_index, constantPoolHandle cp, TRAPS) { +void ClassFileParser::verify_constantvalue(int constantvalue_index, int signature_index, TRAPS) { // Make sure the constant pool entry is of a type appropriate to this field guarantee_property( (constantvalue_index > 0 && - constantvalue_index < cp->length()), + constantvalue_index < _cp->length()), "Bad initial value index %u in ConstantValue attribute in class file %s", constantvalue_index, CHECK); - constantTag value_type = cp->tag_at(constantvalue_index); - switch ( cp->basic_type_for_signature_at(signature_index) ) { + constantTag value_type = _cp->tag_at(constantvalue_index); + switch ( _cp->basic_type_for_signature_at(signature_index) ) { case T_LONG: guarantee_property(value_type.is_long(), "Inconsistent constant value type in class file %s", CHECK); break; @@ -886,7 +850,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;") + guarantee_property((_cp->symbol_at(signature_index)->equals("Ljava/lang/String;") && value_type.is_string()), "Bad string initial value in class file %s", CHECK); break; @@ -899,15 +863,11 @@ void ClassFileParser::verify_constantvalue(int constantvalue_index, int signatur // Parse attributes for a field. -void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, - u2 attributes_count, +void ClassFileParser::parse_field_attributes(u2 attributes_count, bool is_static, u2 signature_index, u2* constantvalue_index_addr, bool* is_synthetic_addr, u2* generic_signature_index_addr, - AnnotationArray** field_annotations, - AnnotationArray** field_type_annotations, ClassFileParser::FieldAnnotationCollector* parsed_annotations, TRAPS) { ClassFileStream* cfs = stream(); @@ -927,12 +887,11 @@ void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length u2 attribute_name_index = cfs->get_u2_fast(); u4 attribute_length = cfs->get_u4_fast(); - check_property(valid_cp_range(attribute_name_index, cp->length()) && - cp->tag_at(attribute_name_index).is_utf8(), + check_property(valid_symbol_at(attribute_name_index), "Invalid field attribute index %u in class file %s", attribute_name_index, CHECK); - Symbol* attribute_name = cp->symbol_at(attribute_name_index); + Symbol* attribute_name = _cp->symbol_at(attribute_name_index); if (is_static && attribute_name == vmSymbols::tag_constant_value()) { // ignore if non-static if (constantvalue_index != 0) { @@ -944,7 +903,7 @@ void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, attribute_length, CHECK); constantvalue_index = cfs->get_u2(CHECK); if (_need_verify) { - verify_constantvalue(constantvalue_index, signature_index, cp, CHECK); + verify_constantvalue(constantvalue_index, signature_index, CHECK); } } else if (attribute_name == vmSymbols::tag_synthetic()) { if (attribute_length != 0) { @@ -971,10 +930,8 @@ void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, runtime_visible_annotations_length = attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); - parse_annotations(loader_data, - runtime_visible_annotations, + parse_annotations(runtime_visible_annotations, runtime_visible_annotations_length, - cp, parsed_annotations, CHECK); cfs->skip_u1(runtime_visible_annotations_length, CHECK); @@ -1004,18 +961,18 @@ void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, *constantvalue_index_addr = constantvalue_index; *is_synthetic_addr = is_synthetic; *generic_signature_index_addr = generic_signature_index; - *field_annotations = assemble_annotations(loader_data, - runtime_visible_annotations, + AnnotationArray* a = assemble_annotations(runtime_visible_annotations, runtime_visible_annotations_length, runtime_invisible_annotations, runtime_invisible_annotations_length, CHECK); - *field_type_annotations = assemble_annotations(loader_data, - runtime_visible_type_annotations, - runtime_visible_type_annotations_length, - runtime_invisible_type_annotations, - runtime_invisible_type_annotations_length, - CHECK); + parsed_annotations->set_field_annotations(a); + a = assemble_annotations(runtime_visible_type_annotations, + runtime_visible_type_annotations_length, + runtime_invisible_type_annotations, + runtime_invisible_type_annotations_length, + CHECK); + parsed_annotations->set_field_type_annotations(a); return; } @@ -1106,13 +1063,9 @@ class FieldAllocationCount: public ResourceObj { } }; -Array<u2>* ClassFileParser::parse_fields(ClassLoaderData* loader_data, - Symbol* class_name, - constantPoolHandle cp, +Array<u2>* ClassFileParser::parse_fields(Symbol* class_name, bool is_interface, FieldAllocationCount *fac, - Array<AnnotationArray*>** fields_annotations, - Array<AnnotationArray*>** fields_type_annotations, u2* java_fields_count_ptr, TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK_NULL); // length @@ -1147,8 +1100,6 @@ Array<u2>* ClassFileParser::parse_fields(ClassLoaderData* loader_data, u2* fa = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2, total_fields * (FieldInfo::field_slots + 1)); - AnnotationArray* field_annotations = NULL; - AnnotationArray* field_type_annotations = NULL; // The generic signature slots start after all other fields' data. int generic_signature_slot = total_fields * FieldInfo::field_slots; int num_generic_signature = 0; @@ -1161,53 +1112,52 @@ Array<u2>* ClassFileParser::parse_fields(ClassLoaderData* loader_data, access_flags.set_flags(flags); u2 name_index = cfs->get_u2_fast(); - int cp_size = cp->length(); - check_property( - valid_cp_range(name_index, cp_size) && cp->tag_at(name_index).is_utf8(), + int cp_size = _cp->length(); + check_property(valid_symbol_at(name_index), "Invalid constant pool index %u for field name in class file %s", - name_index, CHECK_NULL); - Symbol* name = cp->symbol_at(name_index); + name_index, + CHECK_NULL); + Symbol* name = _cp->symbol_at(name_index); verify_legal_field_name(name, CHECK_NULL); u2 signature_index = cfs->get_u2_fast(); - check_property( - valid_cp_range(signature_index, cp_size) && - cp->tag_at(signature_index).is_utf8(), + check_property(valid_symbol_at(signature_index), "Invalid constant pool index %u for field signature in class file %s", signature_index, CHECK_NULL); - Symbol* sig = cp->symbol_at(signature_index); + Symbol* sig = _cp->symbol_at(signature_index); verify_legal_field_signature(name, sig, CHECK_NULL); u2 constantvalue_index = 0; bool is_synthetic = false; u2 generic_signature_index = 0; bool is_static = access_flags.is_static(); - FieldAnnotationCollector parsed_annotations; + FieldAnnotationCollector parsed_annotations(_loader_data); u2 attributes_count = cfs->get_u2_fast(); if (attributes_count > 0) { - parse_field_attributes(loader_data, - cp, attributes_count, is_static, signature_index, + parse_field_attributes(attributes_count, is_static, signature_index, &constantvalue_index, &is_synthetic, - &generic_signature_index, &field_annotations, - &field_type_annotations, &parsed_annotations, + &generic_signature_index, &parsed_annotations, CHECK_NULL); - if (field_annotations != NULL) { - if (*fields_annotations == NULL) { - *fields_annotations = MetadataFactory::new_array<AnnotationArray*>( - loader_data, length, NULL, + if (parsed_annotations.field_annotations() != NULL) { + if (_fields_annotations == NULL) { + _fields_annotations = MetadataFactory::new_array<AnnotationArray*>( + _loader_data, length, NULL, CHECK_NULL); } - (*fields_annotations)->at_put(n, field_annotations); + _fields_annotations->at_put(n, parsed_annotations.field_annotations()); + parsed_annotations.set_field_annotations(NULL); } - if (field_type_annotations != NULL) { - if (*fields_type_annotations == NULL) { - *fields_type_annotations = MetadataFactory::new_array<AnnotationArray*>( - loader_data, length, NULL, + if (parsed_annotations.field_type_annotations() != NULL) { + if (_fields_type_annotations == NULL) { + _fields_type_annotations = MetadataFactory::new_array<AnnotationArray*>( + _loader_data, length, NULL, CHECK_NULL); } - (*fields_type_annotations)->at_put(n, field_type_annotations); + _fields_type_annotations->at_put(n, parsed_annotations.field_type_annotations()); + parsed_annotations.set_field_type_annotations(NULL); } + if (is_synthetic) { access_flags.set_is_synthetic(); } @@ -1224,7 +1174,7 @@ Array<u2>* ClassFileParser::parse_fields(ClassLoaderData* loader_data, name_index, signature_index, constantvalue_index); - BasicType type = cp->basic_type_for_signature_at(signature_index); + BasicType type = _cp->basic_type_for_signature_at(signature_index); // Remember how many oops we encountered and compute allocation type FieldAllocationType atype = fac->update(is_static, type); @@ -1245,8 +1195,8 @@ Array<u2>* ClassFileParser::parse_fields(ClassLoaderData* loader_data, bool duplicate = false; for (int i = 0; i < length; i++) { FieldInfo* f = FieldInfo::from_field_array(fa, i); - if (name == cp->symbol_at(f->name_index()) && - signature == cp->symbol_at(f->signature_index())) { + if (name == _cp->symbol_at(f->name_index()) && + signature == _cp->symbol_at(f->signature_index())) { // Symbol is desclared in Java so skip this one duplicate = true; break; @@ -1280,8 +1230,9 @@ Array<u2>* ClassFileParser::parse_fields(ClassLoaderData* loader_data, // fields array is trimed. Also unused slots that were reserved // for generic signature indexes are discarded. Array<u2>* fields = MetadataFactory::new_array<u2>( - loader_data, index * FieldInfo::field_slots + num_generic_signature, + _loader_data, index * FieldInfo::field_slots + num_generic_signature, CHECK_NULL); + _fields = fields; // save in case of error { int i = 0; for (; i < index * FieldInfo::field_slots; i++) { @@ -1303,7 +1254,7 @@ Array<u2>* ClassFileParser::parse_fields(ClassLoaderData* loader_data, bool dup = false; { debug_only(No_Safepoint_Verifier nsv;) - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { + for (AllFieldStream fs(fields, _cp); !fs.done(); fs.next()) { Symbol* name = fs.name(); Symbol* sig = fs.signature(); // If no duplicates, add name/signature in hashtable names_and_sigs. @@ -1330,10 +1281,8 @@ static void copy_u2_with_conversion(u2* dest, u2* src, int length) { } -u2* ClassFileParser::parse_exception_table(ClassLoaderData* loader_data, - u4 code_length, +u2* ClassFileParser::parse_exception_table(u4 code_length, u4 exception_table_length, - constantPoolHandle cp, TRAPS) { ClassFileStream* cfs = stream(); @@ -1354,8 +1303,7 @@ u2* ClassFileParser::parse_exception_table(ClassLoaderData* loader_data, "Illegal exception table handler in class file %s", CHECK_NULL); if (catch_type_index != 0) { - guarantee_property(valid_cp_range(catch_type_index, cp->length()) && - is_klass_reference(cp, catch_type_index), + guarantee_property(valid_klass_reference_at(catch_type_index), "Catch type in exception table has bad constant type in class file %s", CHECK_NULL); } } @@ -1506,7 +1454,6 @@ void copy_lvt_element(Classfile_LVT_Element *src, LocalVariableTableElement *lvt u2* ClassFileParser::parse_localvariable_table(u4 code_length, u2 max_locals, u4 code_attribute_length, - constantPoolHandle cp, u2* localvariable_table_length, bool isLVTT, TRAPS) { @@ -1544,20 +1491,16 @@ u2* ClassFileParser::parse_localvariable_table(u4 code_length, "Invalid length %u in %s in class file %s", length, tbl_name, CHECK_NULL); } - int cp_size = cp->length(); - guarantee_property( - valid_cp_range(name_index, cp_size) && - cp->tag_at(name_index).is_utf8(), + int cp_size = _cp->length(); + guarantee_property(valid_symbol_at(name_index), "Name index %u in %s has bad constant type in class file %s", name_index, tbl_name, CHECK_NULL); - guarantee_property( - valid_cp_range(descriptor_index, cp_size) && - cp->tag_at(descriptor_index).is_utf8(), + guarantee_property(valid_symbol_at(descriptor_index), "Signature index %u in %s has bad constant type in class file %s", descriptor_index, tbl_name, CHECK_NULL); - Symbol* name = cp->symbol_at(name_index); - Symbol* sig = cp->symbol_at(descriptor_index); + Symbol* name = _cp->symbol_at(name_index); + Symbol* sig = _cp->symbol_at(descriptor_index); verify_legal_field_name(name, CHECK_NULL); u2 extra_slot = 0; if (!isLVTT) { @@ -1579,7 +1522,7 @@ u2* ClassFileParser::parse_localvariable_table(u4 code_length, void ClassFileParser::parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index, - u1* u1_array, u2* u2_array, constantPoolHandle cp, TRAPS) { + u1* u1_array, u2* u2_array, TRAPS) { ClassFileStream* cfs = stream(); u2 index = 0; // index in the array with long/double occupying two slots u4 i1 = *u1_index; @@ -1591,8 +1534,7 @@ void ClassFileParser::parse_type_array(u2 array_length, u4 code_length, u4* u1_i index++; } else if (tag == ITEM_Object) { u2 class_index = u2_array[i2++] = cfs->get_u2(CHECK); - guarantee_property(valid_cp_range(class_index, cp->length()) && - is_klass_reference(cp, class_index), + guarantee_property(valid_klass_reference_at(class_index), "Bad class index %u in StackMap in class file %s", class_index, CHECK); } else if (tag == ITEM_Uninitialized) { @@ -1613,8 +1555,7 @@ void ClassFileParser::parse_type_array(u2 array_length, u4 code_length, u4* u1_i *u2_index = i2; } -Array<u1>* ClassFileParser::parse_stackmap_table( - ClassLoaderData* loader_data, +u1* ClassFileParser::parse_stackmap_table( u4 code_attribute_length, TRAPS) { if (code_attribute_length == 0) return NULL; @@ -1629,18 +1570,12 @@ Array<u1>* ClassFileParser::parse_stackmap_table( if (!_need_verify && !DumpSharedSpaces) { return NULL; } - - Array<u1>* stackmap_data = - MetadataFactory::new_array<u1>(loader_data, code_attribute_length, 0, CHECK_NULL); - - memcpy((void*)stackmap_data->adr_at(0), - (void*)stackmap_table_start, code_attribute_length); - return stackmap_data; + return stackmap_table_start; } u2* ClassFileParser::parse_checked_exceptions(u2* checked_exceptions_length, u4 method_attribute_length, - constantPoolHandle cp, TRAPS) { + TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK_NULL); // checked_exceptions_length *checked_exceptions_length = cfs->get_u2_fast(); @@ -1657,8 +1592,7 @@ u2* ClassFileParser::parse_checked_exceptions(u2* checked_exceptions_length, for (int i = 0; i < len; i++) { checked_exception = cfs->get_u2_fast(); check_property( - valid_cp_range(checked_exception, cp->length()) && - is_klass_reference(cp, checked_exception), + valid_klass_reference_at(checked_exception), "Exception name has bad type at constant pool %u in class file %s", checked_exception, CHECK_NULL); } @@ -1735,9 +1669,7 @@ int ClassFileParser::skip_annotation_value(u1* buffer, int limit, int index) { } // Sift through annotations, looking for those significant to the VM: -void ClassFileParser::parse_annotations(ClassLoaderData* loader_data, - u1* buffer, int limit, - constantPoolHandle cp, +void ClassFileParser::parse_annotations(u1* buffer, int limit, ClassFileParser::AnnotationCollector* coll, TRAPS) { // annotations := do(nann:u2) {annotation} @@ -1767,17 +1699,17 @@ void ClassFileParser::parse_annotations(ClassLoaderData* loader_data, u1* abase = buffer + index0; int atype = Bytes::get_Java_u2(abase + atype_off); int count = Bytes::get_Java_u2(abase + count_off); - Symbol* aname = check_symbol_at(cp, atype); + Symbol* aname = check_symbol_at(_cp, atype); if (aname == NULL) break; // invalid annotation name Symbol* member = NULL; if (count >= 1) { int member_index = Bytes::get_Java_u2(abase + member_off); - member = check_symbol_at(cp, member_index); + member = check_symbol_at(_cp, member_index); if (member == NULL) break; // invalid member name } // Here is where parsing particular annotations will take place. - AnnotationCollector::ID id = coll->annotation_index(loader_data, aname); + AnnotationCollector::ID id = coll->annotation_index(_loader_data, aname); if (id == AnnotationCollector::_unknown) continue; coll->set_annotation(id); @@ -1836,6 +1768,12 @@ void ClassFileParser::FieldAnnotationCollector::apply_to(FieldInfo* f) { f->set_contended_group(contended_group()); } +ClassFileParser::FieldAnnotationCollector::~FieldAnnotationCollector() { + // If there's an error deallocate metadata for field annotations + MetadataFactory::free_array<u1>(_loader_data, _field_annotations); + MetadataFactory::free_array<u1>(_loader_data, _field_type_annotations); +} + void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m) { if (has_annotation(_method_ForceInline)) m->set_force_inline(true); @@ -1894,10 +1832,9 @@ void ClassFileParser::copy_localvariable_table(ConstMethod* cm, && _need_verify && _major_version >= JAVA_1_5_VERSION) { clear_hashtable(lvt_Hash); - ConstantPool* cp = cm->constants(); classfile_parse_error("Duplicated LocalVariableTable attribute " "entry for '%s' in class file %s", - cp->symbol_at(lvt->name_cp_index)->as_utf8(), + _cp->symbol_at(lvt->name_cp_index)->as_utf8(), CHECK); } } @@ -1916,18 +1853,16 @@ void ClassFileParser::copy_localvariable_table(ConstMethod* cm, if (entry == NULL) { if (_need_verify) { clear_hashtable(lvt_Hash); - ConstantPool* cp = cm->constants(); classfile_parse_error("LVTT entry for '%s' in class file %s " "does not match any LVT entry", - cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), + _cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), CHECK); } } else if (entry->_elem->signature_cp_index != 0 && _need_verify) { clear_hashtable(lvt_Hash); - ConstantPool* cp = cm->constants(); classfile_parse_error("Duplicated LocalVariableTypeTable attribute " "entry for '%s' in class file %s", - cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), + _cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), CHECK); } else { // to add generic signatures into LocalVariableTable @@ -1939,8 +1874,7 @@ void ClassFileParser::copy_localvariable_table(ConstMethod* cm, } -void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, - ConstMethod* cm, +void ClassFileParser::copy_method_annotations(ConstMethod* cm, u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, @@ -1961,8 +1895,7 @@ void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, if (runtime_visible_annotations_length + runtime_invisible_annotations_length > 0) { - a = assemble_annotations(loader_data, - runtime_visible_annotations, + a = assemble_annotations(runtime_visible_annotations, runtime_visible_annotations_length, runtime_invisible_annotations, runtime_invisible_annotations_length, @@ -1972,8 +1905,7 @@ void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, if (runtime_visible_parameter_annotations_length + runtime_invisible_parameter_annotations_length > 0) { - a = assemble_annotations(loader_data, - runtime_visible_parameter_annotations, + a = assemble_annotations(runtime_visible_parameter_annotations, runtime_visible_parameter_annotations_length, runtime_invisible_parameter_annotations, runtime_invisible_parameter_annotations_length, @@ -1982,8 +1914,7 @@ void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, } if (annotation_default_length > 0) { - a = assemble_annotations(loader_data, - annotation_default, + a = assemble_annotations(annotation_default, annotation_default_length, NULL, 0, @@ -1993,8 +1924,7 @@ void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, if (runtime_visible_type_annotations_length + runtime_invisible_type_annotations_length > 0) { - a = assemble_annotations(loader_data, - runtime_visible_type_annotations, + a = assemble_annotations(runtime_visible_type_annotations, runtime_visible_type_annotations_length, runtime_invisible_type_annotations, runtime_invisible_type_annotations_length, @@ -2013,9 +1943,7 @@ void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, // from the method back up to the containing klass. These flag values // are added to klass's access_flags. -methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, +methodHandle ClassFileParser::parse_method(bool is_interface, AccessFlags *promoted_flags, TRAPS) { ClassFileStream* cfs = stream(); @@ -2026,22 +1954,20 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, int flags = cfs->get_u2_fast(); u2 name_index = cfs->get_u2_fast(); - int cp_size = cp->length(); + int cp_size = _cp->length(); check_property( - valid_cp_range(name_index, cp_size) && - cp->tag_at(name_index).is_utf8(), + valid_symbol_at(name_index), "Illegal constant pool index %u for method name in class file %s", name_index, CHECK_(nullHandle)); - Symbol* name = cp->symbol_at(name_index); + Symbol* name = _cp->symbol_at(name_index); verify_legal_method_name(name, CHECK_(nullHandle)); u2 signature_index = cfs->get_u2_fast(); guarantee_property( - valid_cp_range(signature_index, cp_size) && - cp->tag_at(signature_index).is_utf8(), + valid_symbol_at(signature_index), "Illegal constant pool index %u for method signature in class file %s", signature_index, CHECK_(nullHandle)); - Symbol* signature = cp->symbol_at(signature_index); + Symbol* signature = _cp->symbol_at(signature_index); AccessFlags access_flags; if (name == vmSymbols::class_initializer_name()) { @@ -2097,7 +2023,8 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, bool parsed_checked_exceptions_attribute = false; bool parsed_stackmap_attribute = false; // stackmap attribute - JDK1.5 - Array<u1>* stackmap_data = NULL; + u1* stackmap_data = NULL; + int stackmap_data_length = 0; u2 generic_signature_index = 0; MethodAnnotationCollector parsed_annotations; u1* runtime_visible_annotations = NULL; @@ -2122,12 +2049,11 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, u2 method_attribute_name_index = cfs->get_u2_fast(); u4 method_attribute_length = cfs->get_u4_fast(); check_property( - valid_cp_range(method_attribute_name_index, cp_size) && - cp->tag_at(method_attribute_name_index).is_utf8(), + valid_symbol_at(method_attribute_name_index), "Invalid method attribute name index %u in class file %s", method_attribute_name_index, CHECK_(nullHandle)); - Symbol* method_attribute_name = cp->symbol_at(method_attribute_name_index); + Symbol* method_attribute_name = _cp->symbol_at(method_attribute_name_index); if (method_attribute_name == vmSymbols::tag_code()) { // Parse Code attribute if (_need_verify) { @@ -2171,7 +2097,7 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, exception_table_length = cfs->get_u2_fast(); if (exception_table_length > 0) { exception_table_start = - parse_exception_table(loader_data, code_length, exception_table_length, cp, CHECK_(nullHandle)); + parse_exception_table(code_length, exception_table_length, CHECK_(nullHandle)); } // Parse additional attributes in code attribute @@ -2204,19 +2130,18 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, calculated_attribute_length += code_attribute_length + sizeof(code_attribute_name_index) + sizeof(code_attribute_length); - check_property(valid_cp_range(code_attribute_name_index, cp_size) && - cp->tag_at(code_attribute_name_index).is_utf8(), + check_property(valid_symbol_at(code_attribute_name_index), "Invalid code attribute name index %u in class file %s", code_attribute_name_index, CHECK_(nullHandle)); if (LoadLineNumberTables && - cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) { + _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) { // Parse and compress line number table parse_linenumber_table(code_attribute_length, code_length, &linenumber_table, CHECK_(nullHandle)); } else if (LoadLocalVariableTables && - cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_table()) { + _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_table()) { // Parse local variable table if (!lvt_allocated) { localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD( @@ -2238,7 +2163,6 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, parse_localvariable_table(code_length, max_locals, code_attribute_length, - cp, &localvariable_table_length[lvt_cnt], false, // is not LVTT CHECK_(nullHandle)); @@ -2246,7 +2170,7 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, lvt_cnt++; } else if (LoadLocalVariableTypeTables && _major_version >= JAVA_1_5_VERSION && - cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_type_table()) { + _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_type_table()) { if (!lvt_allocated) { localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2, INITIAL_MAX_LVT_NUMBER); @@ -2268,19 +2192,19 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, parse_localvariable_table(code_length, max_locals, code_attribute_length, - cp, &localvariable_type_table_length[lvtt_cnt], true, // is LVTT CHECK_(nullHandle)); lvtt_cnt++; } else if (UseSplitVerifier && _major_version >= Verifier::STACKMAP_ATTRIBUTE_MAJOR_VERSION && - cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_stack_map_table()) { + _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_stack_map_table()) { // Stack map is only needed by the new verifier in JDK1.5. if (parsed_stackmap_attribute) { classfile_parse_error("Multiple StackMapTable attributes in class file %s", CHECK_(nullHandle)); } - stackmap_data = parse_stackmap_table(loader_data, code_attribute_length, CHECK_(nullHandle)); + stackmap_data = parse_stackmap_table(code_attribute_length, CHECK_(nullHandle)); + stackmap_data_length = code_attribute_length; parsed_stackmap_attribute = true; } else { // Skip unknown attributes @@ -2301,7 +2225,7 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, checked_exceptions_start = parse_checked_exceptions(&checked_exceptions_length, method_attribute_length, - cp, CHECK_(nullHandle)); + CHECK_(nullHandle)); } else if (method_attribute_name == vmSymbols::tag_method_parameters()) { // reject multiple method parameters if (method_parameters_seen) { @@ -2359,9 +2283,8 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, runtime_visible_annotations_length = method_attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); - parse_annotations(loader_data, - runtime_visible_annotations, - runtime_visible_annotations_length, cp, &parsed_annotations, + parse_annotations(runtime_visible_annotations, + runtime_visible_annotations_length, &parsed_annotations, CHECK_(nullHandle)); cfs->skip_u1(runtime_visible_annotations_length, CHECK_(nullHandle)); } else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) { @@ -2434,18 +2357,18 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, 0); Method* m = Method::allocate( - loader_data, code_length, access_flags, &sizes, + _loader_data, code_length, access_flags, &sizes, ConstMethod::NORMAL, CHECK_(nullHandle)); ClassLoadingService::add_class_method_size(m->size()*HeapWordSize); // Fill in information from fixed part (access_flags already set) - m->set_constants(cp()); + m->set_constants(_cp); m->set_name_index(name_index); m->set_signature_index(signature_index); #ifdef CC_INTERP // hmm is there a gc issue here?? - ResultTypeFinder rtf(cp->symbol_at(signature_index)); + ResultTypeFinder rtf(_cp->symbol_at(signature_index)); m->set_result_index(rtf.type()); #endif @@ -2464,7 +2387,10 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, // Fill in code attribute information m->set_max_stack(max_stack); m->set_max_locals(max_locals); - m->constMethod()->set_stackmap_data(stackmap_data); + if (stackmap_data != NULL) { + m->constMethod()->copy_stackmap_data(_loader_data, stackmap_data, + stackmap_data_length, CHECK_NULL); + } // Copy byte codes m->set_code(code_start); @@ -2520,7 +2446,7 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, parsed_annotations.apply_to(m); // Copy annotations - copy_method_annotations(loader_data, m->constMethod(), + copy_method_annotations(m->constMethod(), runtime_visible_annotations, runtime_visible_annotations_length, runtime_invisible_annotations, @@ -2560,9 +2486,7 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, // from the methods back up to the containing klass. These flag values // are added to klass's access_flags. -Array<Method*>* ClassFileParser::parse_methods(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, +Array<Method*>* ClassFileParser::parse_methods(bool is_interface, AccessFlags* promoted_flags, bool* has_final_method, bool* has_default_methods, @@ -2571,15 +2495,13 @@ Array<Method*>* ClassFileParser::parse_methods(ClassLoaderData* loader_data, cfs->guarantee_more(2, CHECK_NULL); // length u2 length = cfs->get_u2_fast(); if (length == 0) { - return Universe::the_empty_method_array(); + _methods = Universe::the_empty_method_array(); } else { - // FIXME: Handle leaks at later failures. - Array<Method*>* methods = MetadataFactory::new_array<Method*>(loader_data, length, NULL, CHECK_NULL); + _methods = MetadataFactory::new_array<Method*>(_loader_data, length, NULL, CHECK_NULL); HandleMark hm(THREAD); for (int index = 0; index < length; index++) { - methodHandle method = parse_method(loader_data, - cp, is_interface, + methodHandle method = parse_method(is_interface, promoted_flags, CHECK_NULL); @@ -2590,7 +2512,7 @@ Array<Method*>* ClassFileParser::parse_methods(ClassLoaderData* loader_data, // default method *has_default_methods = true; } - methods->at_put(index, method()); + _methods->at_put(index, method()); } if (_need_verify && length > 1) { @@ -2603,7 +2525,7 @@ Array<Method*>* ClassFileParser::parse_methods(ClassLoaderData* loader_data, { debug_only(No_Safepoint_Verifier nsv;) for (int i = 0; i < length; i++) { - Method* m = methods->at(i); + Method* m = _methods->at(i); // If no duplicates, add name/signature in hashtable names_and_sigs. if (!put_after_lookup(m->name(), m->signature(), names_and_sigs)) { dup = true; @@ -2616,14 +2538,12 @@ Array<Method*>* ClassFileParser::parse_methods(ClassLoaderData* loader_data, CHECK_NULL); } } - return methods; } + return _methods; } -Array<int>* ClassFileParser::sort_methods(ClassLoaderData* loader_data, - Array<Method*>* methods, - TRAPS) { +intArray* ClassFileParser::sort_methods(Array<Method*>* methods) { int length = methods->length(); // If JVMTI original method ordering or sharing is enabled we have to // remember the original class file ordering. @@ -2641,10 +2561,11 @@ Array<int>* ClassFileParser::sort_methods(ClassLoaderData* loader_data, // Note that the ordering is not alphabetical, see Symbol::fast_compare Method::sort_methods(methods); + intArray* method_ordering = NULL; // If JVMTI original method ordering or sharing is enabled construct int // array remembering the original ordering if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) { - Array<int>* method_ordering = MetadataFactory::new_array<int>(loader_data, length, CHECK_NULL); + method_ordering = new intArray(length); for (int index = 0; index < length; index++) { Method* m = methods->at(index); int old_index = m->vtable_index(); @@ -2652,29 +2573,25 @@ Array<int>* ClassFileParser::sort_methods(ClassLoaderData* loader_data, method_ordering->at_put(index, old_index); m->set_vtable_index(Method::invalid_vtable_index); } - return method_ordering; - } else { - return Universe::the_empty_int_array(); } + return method_ordering; } -void ClassFileParser::parse_classfile_sourcefile_attribute(constantPoolHandle cp, TRAPS) { +void ClassFileParser::parse_classfile_sourcefile_attribute(TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK); // sourcefile_index u2 sourcefile_index = cfs->get_u2_fast(); check_property( - valid_cp_range(sourcefile_index, cp->length()) && - cp->tag_at(sourcefile_index).is_utf8(), + valid_symbol_at(sourcefile_index), "Invalid SourceFile attribute at constant pool index %u in class file %s", sourcefile_index, CHECK); - set_class_sourcefile(cp->symbol_at(sourcefile_index)); + set_class_sourcefile(_cp->symbol_at(sourcefile_index)); } -void ClassFileParser::parse_classfile_source_debug_extension_attribute(constantPoolHandle cp, - int length, TRAPS) { +void ClassFileParser::parse_classfile_source_debug_extension_attribute(int length, TRAPS) { ClassFileStream* cfs = stream(); u1* sde_buffer = cfs->get_u1_buffer(); assert(sde_buffer != NULL, "null sde buffer"); @@ -2698,12 +2615,10 @@ void ClassFileParser::parse_classfile_source_debug_extension_attribute(constantP #define RECOGNIZED_INNER_CLASS_MODIFIERS (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED | JVM_ACC_STATIC) // Return number of classes in the inner classes attribute table -u2 ClassFileParser::parse_classfile_inner_classes_attribute(ClassLoaderData* loader_data, - u1* inner_classes_attribute_start, +u2 ClassFileParser::parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start, bool parsed_enclosingmethod_attribute, u2 enclosing_method_class_index, u2 enclosing_method_method_index, - constantPoolHandle cp, TRAPS) { ClassFileStream* cfs = stream(); u1* current_mark = cfs->current(); @@ -2724,33 +2639,31 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(ClassLoaderData* loa // enclosing_method_class_index, // enclosing_method_method_index] int size = length * 4 + (parsed_enclosingmethod_attribute ? 2 : 0); - // FIXME: Will leak on exceptions. - Array<u2>* inner_classes = MetadataFactory::new_array<u2>(loader_data, size, CHECK_0); + Array<u2>* inner_classes = MetadataFactory::new_array<u2>(_loader_data, size, CHECK_0); + _inner_classes = inner_classes; + int index = 0; - int cp_size = cp->length(); + int cp_size = _cp->length(); cfs->guarantee_more(8 * length, CHECK_0); // 4-tuples of u2 for (int n = 0; n < length; n++) { // Inner class index u2 inner_class_info_index = cfs->get_u2_fast(); check_property( inner_class_info_index == 0 || - (valid_cp_range(inner_class_info_index, cp_size) && - is_klass_reference(cp, inner_class_info_index)), + valid_klass_reference_at(inner_class_info_index), "inner_class_info_index %u has bad constant type in class file %s", inner_class_info_index, CHECK_0); // Outer class index u2 outer_class_info_index = cfs->get_u2_fast(); check_property( outer_class_info_index == 0 || - (valid_cp_range(outer_class_info_index, cp_size) && - is_klass_reference(cp, outer_class_info_index)), + valid_klass_reference_at(outer_class_info_index), "outer_class_info_index %u has bad constant type in class file %s", outer_class_info_index, CHECK_0); // Inner class name u2 inner_name_index = cfs->get_u2_fast(); check_property( - inner_name_index == 0 || (valid_cp_range(inner_name_index, cp_size) && - cp->tag_at(inner_name_index).is_utf8()), + inner_name_index == 0 || valid_symbol_at(inner_name_index), "inner_name_index %u has bad constant type in class file %s", inner_name_index, CHECK_0); if (_need_verify) { @@ -2794,33 +2707,27 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(ClassLoaderData* loa } assert(index == size, "wrong size"); - // Update InstanceKlass with inner class info. - set_class_inner_classes(inner_classes); - // Restore buffer's current position. cfs->set_current(current_mark); return length; } -void ClassFileParser::parse_classfile_synthetic_attribute(constantPoolHandle cp, TRAPS) { +void ClassFileParser::parse_classfile_synthetic_attribute(TRAPS) { set_class_synthetic_flag(true); } -void ClassFileParser::parse_classfile_signature_attribute(constantPoolHandle cp, TRAPS) { +void ClassFileParser::parse_classfile_signature_attribute(TRAPS) { ClassFileStream* cfs = stream(); u2 signature_index = cfs->get_u2(CHECK); check_property( - valid_cp_range(signature_index, cp->length()) && - cp->tag_at(signature_index).is_utf8(), + valid_symbol_at(signature_index), "Invalid constant pool index %u in Signature attribute in class file %s", signature_index, CHECK); - set_class_generic_signature(cp->symbol_at(signature_index)); + set_class_generic_signature(_cp->symbol_at(signature_index)); } -void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderData* loader_data, - constantPoolHandle cp, - u4 attribute_byte_length, TRAPS) { +void ClassFileParser::parse_classfile_bootstrap_methods_attribute(u4 attribute_byte_length, TRAPS) { ClassFileStream* cfs = stream(); u1* current_start = cfs->current(); @@ -2841,10 +2748,14 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderDat // The array begins with a series of short[2] pairs, one for each tuple. int index_size = (attribute_array_length * 2); - Array<u2>* operands = MetadataFactory::new_array<u2>(loader_data, index_size + operand_count, CHECK); + Array<u2>* operands = MetadataFactory::new_array<u2>(_loader_data, index_size + operand_count, CHECK); + + // Eagerly assign operands so they will be deallocated with the constant + // pool if there is an error. + _cp->set_operands(operands); int operand_fill_index = index_size; - int cp_size = cp->length(); + int cp_size = _cp->length(); for (int n = 0; n < attribute_array_length; n++) { // Store a 32-bit offset into the header of the operand array. @@ -2856,7 +2767,7 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderDat u2 argument_count = cfs->get_u2_fast(); check_property( valid_cp_range(bootstrap_method_index, cp_size) && - cp->tag_at(bootstrap_method_index).is_method_handle(), + _cp->tag_at(bootstrap_method_index).is_method_handle(), "bootstrap_method_index %u has bad constant type in class file %s", bootstrap_method_index, CHECK); @@ -2868,7 +2779,7 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderDat u2 argument_index = cfs->get_u2_fast(); check_property( valid_cp_range(argument_index, cp_size) && - cp->tag_at(argument_index).is_loadable_constant(), + _cp->tag_at(argument_index).is_loadable_constant(), "argument_index %u has bad constant type in class file %s", argument_index, CHECK); @@ -2883,17 +2794,13 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderDat guarantee_property(current_end == current_start + attribute_byte_length, "Bad length on BootstrapMethods in class file %s", CHECK); - - cp->set_operands(operands); } -void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, - ClassFileParser::ClassAnnotationCollector* parsed_annotations, +void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotationCollector* parsed_annotations, TRAPS) { ClassFileStream* cfs = stream(); // Set inner classes attribute to default sentinel - set_class_inner_classes(Universe::the_empty_short_array()); + _inner_classes = Universe::the_empty_short_array(); cfs->guarantee_more(2, CHECK); // attributes_count u2 attributes_count = cfs->get_u2_fast(); bool parsed_sourcefile_attribute = false; @@ -2918,11 +2825,10 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, u2 attribute_name_index = cfs->get_u2_fast(); u4 attribute_length = cfs->get_u4_fast(); check_property( - valid_cp_range(attribute_name_index, cp->length()) && - cp->tag_at(attribute_name_index).is_utf8(), + valid_symbol_at(attribute_name_index), "Attribute name has bad constant pool index %u in class file %s", attribute_name_index, CHECK); - Symbol* tag = cp->symbol_at(attribute_name_index); + Symbol* tag = _cp->symbol_at(attribute_name_index); if (tag == vmSymbols::tag_source_file()) { // Check for SourceFile tag if (_need_verify) { @@ -2933,10 +2839,10 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, } else { parsed_sourcefile_attribute = true; } - parse_classfile_sourcefile_attribute(cp, CHECK); + parse_classfile_sourcefile_attribute(CHECK); } else if (tag == vmSymbols::tag_source_debug_extension()) { // Check for SourceDebugExtension tag - parse_classfile_source_debug_extension_attribute(cp, (int)attribute_length, CHECK); + parse_classfile_source_debug_extension_attribute((int)attribute_length, CHECK); } else if (tag == vmSymbols::tag_inner_classes()) { // Check for InnerClasses tag if (parsed_innerclasses_attribute) { @@ -2955,7 +2861,7 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, "Invalid Synthetic classfile attribute length %u in class file %s", attribute_length, CHECK); } - parse_classfile_synthetic_attribute(cp, CHECK); + parse_classfile_synthetic_attribute(CHECK); } else if (tag == vmSymbols::tag_deprecated()) { // Check for Deprecatd tag - 4276120 if (attribute_length != 0) { @@ -2970,15 +2876,13 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, "Wrong Signature attribute length %u in class file %s", attribute_length, CHECK); } - parse_classfile_signature_attribute(cp, CHECK); + parse_classfile_signature_attribute(CHECK); } else if (tag == vmSymbols::tag_runtime_visible_annotations()) { runtime_visible_annotations_length = attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); - parse_annotations(loader_data, - runtime_visible_annotations, + parse_annotations(runtime_visible_annotations, runtime_visible_annotations_length, - cp, parsed_annotations, CHECK); cfs->skip_u1(runtime_visible_annotations_length, CHECK); @@ -3000,13 +2904,11 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, classfile_parse_error("Invalid class index in EnclosingMethod attribute in class file %s", CHECK); } // Validate the constant pool indices and types - if (!cp->is_within_bounds(enclosing_method_class_index) || - !is_klass_reference(cp, enclosing_method_class_index)) { - classfile_parse_error("Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK); - } + check_property(valid_klass_reference_at(enclosing_method_class_index), + "Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK); if (enclosing_method_method_index != 0 && - (!cp->is_within_bounds(enclosing_method_method_index) || - !cp->tag_at(enclosing_method_method_index).is_name_and_type())) { + (!_cp->is_within_bounds(enclosing_method_method_index) || + !_cp->tag_at(enclosing_method_method_index).is_name_and_type())) { classfile_parse_error("Invalid or out-of-bounds method index in EnclosingMethod attribute in class file %s", CHECK); } } else if (tag == vmSymbols::tag_bootstrap_methods() && @@ -3014,7 +2916,7 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, if (parsed_bootstrap_methods_attribute) classfile_parse_error("Multiple BootstrapMethods attributes in class file %s", CHECK); parsed_bootstrap_methods_attribute = true; - parse_classfile_bootstrap_methods_attribute(loader_data, cp, attribute_length, CHECK); + parse_classfile_bootstrap_methods_attribute(attribute_length, CHECK); } else if (tag == vmSymbols::tag_runtime_visible_type_annotations()) { runtime_visible_type_annotations_length = attribute_length; runtime_visible_type_annotations = cfs->get_u1_buffer(); @@ -3035,29 +2937,24 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, cfs->skip_u1(attribute_length, CHECK); } } - AnnotationArray* annotations = assemble_annotations(loader_data, - runtime_visible_annotations, - runtime_visible_annotations_length, - runtime_invisible_annotations, - runtime_invisible_annotations_length, - CHECK); - set_class_annotations(annotations); - AnnotationArray* type_annotations = assemble_annotations(loader_data, - runtime_visible_type_annotations, - runtime_visible_type_annotations_length, - runtime_invisible_type_annotations, - runtime_invisible_type_annotations_length, - CHECK); - set_class_type_annotations(type_annotations); + _annotations = assemble_annotations(runtime_visible_annotations, + runtime_visible_annotations_length, + runtime_invisible_annotations, + runtime_invisible_annotations_length, + CHECK); + _type_annotations = assemble_annotations(runtime_visible_type_annotations, + runtime_visible_type_annotations_length, + runtime_invisible_type_annotations, + runtime_invisible_type_annotations_length, + CHECK); if (parsed_innerclasses_attribute || parsed_enclosingmethod_attribute) { u2 num_of_classes = parse_classfile_inner_classes_attribute( - loader_data, inner_classes_attribute_start, parsed_innerclasses_attribute, enclosing_method_class_index, enclosing_method_method_index, - cp, CHECK); + CHECK); if (parsed_innerclasses_attribute &&_need_verify && _major_version >= JAVA_1_5_VERSION) { guarantee_property( inner_classes_attribute_length == sizeof(num_of_classes) + 4 * sizeof(u2) * num_of_classes, @@ -3085,18 +2982,43 @@ void ClassFileParser::apply_parsed_class_attributes(instanceKlassHandle k) { if (_sde_buffer != NULL) { k->set_source_debug_extension(_sde_buffer, _sde_length); } - k->set_inner_classes(_inner_classes); } -AnnotationArray* ClassFileParser::assemble_annotations(ClassLoaderData* loader_data, - u1* runtime_visible_annotations, +// Transfer ownership of metadata allocated to the InstanceKlass. +void ClassFileParser::apply_parsed_class_metadata( + instanceKlassHandle this_klass, + int java_fields_count, TRAPS) { + // Assign annotations if needed + if (_annotations != NULL || _type_annotations != NULL || + _fields_annotations != NULL || _fields_type_annotations != NULL) { + Annotations* annotations = Annotations::allocate(_loader_data, CHECK); + annotations->set_class_annotations(_annotations); + annotations->set_class_type_annotations(_type_annotations); + annotations->set_fields_annotations(_fields_annotations); + annotations->set_fields_type_annotations(_fields_type_annotations); + this_klass->set_annotations(annotations); + } + + _cp->set_pool_holder(this_klass()); + this_klass->set_constants(_cp); + this_klass->set_fields(_fields, java_fields_count); + this_klass->set_methods(_methods); + this_klass->set_inner_classes(_inner_classes); + this_klass->set_local_interfaces(_local_interfaces); + this_klass->set_transitive_interfaces(_transitive_interfaces); + + // Clear out these fields so they don't get deallocated by the destructor + clear_class_metadata(); +} + +AnnotationArray* ClassFileParser::assemble_annotations(u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, int runtime_invisible_annotations_length, TRAPS) { AnnotationArray* annotations = NULL; if (runtime_visible_annotations != NULL || runtime_invisible_annotations != NULL) { - annotations = MetadataFactory::new_array<u1>(loader_data, + annotations = MetadataFactory::new_array<u1>(_loader_data, runtime_visible_annotations_length + runtime_invisible_annotations_length, CHECK_(annotations)); @@ -3144,6 +3066,581 @@ static void parseAndPrintGenericSignatures( #endif // ndef PRODUCT +instanceKlassHandle ClassFileParser::parse_super_class(int super_class_index, + TRAPS) { + instanceKlassHandle super_klass; + if (super_class_index == 0) { + check_property(_class_name == vmSymbols::java_lang_Object(), + "Invalid superclass index %u in class file %s", + super_class_index, + CHECK_NULL); + } else { + check_property(valid_klass_reference_at(super_class_index), + "Invalid superclass index %u in class file %s", + super_class_index, + CHECK_NULL); + // The class name should be legal because it is checked when parsing constant pool. + // However, make sure it is not an array type. + bool is_array = false; + if (_cp->tag_at(super_class_index).is_klass()) { + super_klass = instanceKlassHandle(THREAD, _cp->resolved_klass_at(super_class_index)); + if (_need_verify) + is_array = super_klass->oop_is_array(); + } else if (_need_verify) { + is_array = (_cp->unresolved_klass_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY); + } + if (_need_verify) { + guarantee_property(!is_array, + "Bad superclass name in class file %s", CHECK_NULL); + } + } + return super_klass; +} + + +// Values needed for oopmap and InstanceKlass creation +class FieldLayoutInfo : public StackObj { + public: + int* nonstatic_oop_offsets; + unsigned int* nonstatic_oop_counts; + unsigned int nonstatic_oop_map_count; + unsigned int total_oop_map_count; + int instance_size; + int nonstatic_field_size; + int static_field_size; + bool has_nonstatic_fields; +}; + +// Layout fields and fill in FieldLayoutInfo. Could use more refactoring! +void ClassFileParser::layout_fields(Handle class_loader, + FieldAllocationCount* fac, + ClassAnnotationCollector* parsed_annotations, + FieldLayoutInfo* info, + TRAPS) { + + // get the padding width from the option + // TODO: Ask VM about specific CPU we are running on + int pad_size = ContendedPaddingWidth; + + // Field size and offset computation + int nonstatic_field_size = _super_klass() == NULL ? 0 : _super_klass()->nonstatic_field_size(); +#ifndef PRODUCT + int orig_nonstatic_field_size = 0; +#endif + int next_static_oop_offset; + int next_static_double_offset; + int next_static_word_offset; + int next_static_short_offset; + int next_static_byte_offset; + int next_nonstatic_oop_offset; + int next_nonstatic_double_offset; + int next_nonstatic_word_offset; + int next_nonstatic_short_offset; + int next_nonstatic_byte_offset; + int next_nonstatic_type_offset; + int first_nonstatic_oop_offset; + int first_nonstatic_field_offset; + int next_nonstatic_field_offset; + int next_nonstatic_padded_offset; + + // Count the contended fields by type. + int nonstatic_contended_count = 0; + FieldAllocationCount fac_contended; + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + if (fs.is_contended()) { + fac_contended.count[atype]++; + if (!fs.access_flags().is_static()) { + nonstatic_contended_count++; + } + } + } + int contended_count = nonstatic_contended_count; + + + // Calculate the starting byte offsets + next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields(); + next_static_double_offset = next_static_oop_offset + + ((fac->count[STATIC_OOP]) * heapOopSize); + if ( fac->count[STATIC_DOUBLE] && + (Universe::field_type_should_be_aligned(T_DOUBLE) || + Universe::field_type_should_be_aligned(T_LONG)) ) { + next_static_double_offset = align_size_up(next_static_double_offset, BytesPerLong); + } + + next_static_word_offset = next_static_double_offset + + ((fac->count[STATIC_DOUBLE]) * BytesPerLong); + next_static_short_offset = next_static_word_offset + + ((fac->count[STATIC_WORD]) * BytesPerInt); + next_static_byte_offset = next_static_short_offset + + ((fac->count[STATIC_SHORT]) * BytesPerShort); + + first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + + nonstatic_field_size * heapOopSize; + + // class is contended, pad before all the fields + if (parsed_annotations->is_contended()) { + first_nonstatic_field_offset += pad_size; + } + + next_nonstatic_field_offset = first_nonstatic_field_offset; + + unsigned int nonstatic_double_count = fac->count[NONSTATIC_DOUBLE] - fac_contended.count[NONSTATIC_DOUBLE]; + unsigned int nonstatic_word_count = fac->count[NONSTATIC_WORD] - fac_contended.count[NONSTATIC_WORD]; + unsigned int nonstatic_short_count = fac->count[NONSTATIC_SHORT] - fac_contended.count[NONSTATIC_SHORT]; + unsigned int nonstatic_byte_count = fac->count[NONSTATIC_BYTE] - fac_contended.count[NONSTATIC_BYTE]; + unsigned int nonstatic_oop_count = fac->count[NONSTATIC_OOP] - fac_contended.count[NONSTATIC_OOP]; + + bool super_has_nonstatic_fields = + (_super_klass() != NULL && _super_klass->has_nonstatic_fields()); + bool has_nonstatic_fields = super_has_nonstatic_fields || + ((nonstatic_double_count + nonstatic_word_count + + nonstatic_short_count + nonstatic_byte_count + + nonstatic_oop_count) != 0); + + + // Prepare list of oops for oop map generation. + int* nonstatic_oop_offsets; + unsigned int* nonstatic_oop_counts; + unsigned int nonstatic_oop_map_count = 0; + + nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD( + THREAD, int, nonstatic_oop_count + 1); + nonstatic_oop_counts = NEW_RESOURCE_ARRAY_IN_THREAD( + THREAD, unsigned int, nonstatic_oop_count + 1); + + first_nonstatic_oop_offset = 0; // will be set for first oop field + +#ifndef PRODUCT + if( PrintCompactFieldsSavings ) { + next_nonstatic_double_offset = next_nonstatic_field_offset + + (nonstatic_oop_count * heapOopSize); + if ( nonstatic_double_count > 0 ) { + next_nonstatic_double_offset = align_size_up(next_nonstatic_double_offset, BytesPerLong); + } + next_nonstatic_word_offset = next_nonstatic_double_offset + + (nonstatic_double_count * BytesPerLong); + next_nonstatic_short_offset = next_nonstatic_word_offset + + (nonstatic_word_count * BytesPerInt); + next_nonstatic_byte_offset = next_nonstatic_short_offset + + (nonstatic_short_count * BytesPerShort); + next_nonstatic_type_offset = align_size_up((next_nonstatic_byte_offset + + nonstatic_byte_count ), heapOopSize ); + orig_nonstatic_field_size = nonstatic_field_size + + ((next_nonstatic_type_offset - first_nonstatic_field_offset)/heapOopSize); + } +#endif + bool compact_fields = CompactFields; + int allocation_style = FieldsAllocationStyle; + if( allocation_style < 0 || allocation_style > 2 ) { // Out of range? + assert(false, "0 <= FieldsAllocationStyle <= 2"); + allocation_style = 1; // Optimistic + } + + // The next classes have predefined hard-coded fields offsets + // (see in JavaClasses::compute_hard_coded_offsets()). + // Use default fields allocation order for them. + if( (allocation_style != 0 || compact_fields ) && class_loader.is_null() && + (_class_name == vmSymbols::java_lang_AssertionStatusDirectives() || + _class_name == vmSymbols::java_lang_Class() || + _class_name == vmSymbols::java_lang_ClassLoader() || + _class_name == vmSymbols::java_lang_ref_Reference() || + _class_name == vmSymbols::java_lang_ref_SoftReference() || + _class_name == vmSymbols::java_lang_StackTraceElement() || + _class_name == vmSymbols::java_lang_String() || + _class_name == vmSymbols::java_lang_Throwable() || + _class_name == vmSymbols::java_lang_Boolean() || + _class_name == vmSymbols::java_lang_Character() || + _class_name == vmSymbols::java_lang_Float() || + _class_name == vmSymbols::java_lang_Double() || + _class_name == vmSymbols::java_lang_Byte() || + _class_name == vmSymbols::java_lang_Short() || + _class_name == vmSymbols::java_lang_Integer() || + _class_name == vmSymbols::java_lang_Long())) { + allocation_style = 0; // Allocate oops first + compact_fields = false; // Don't compact fields + } + + if( allocation_style == 0 ) { + // Fields order: oops, longs/doubles, ints, shorts/chars, bytes, padded fields + next_nonstatic_oop_offset = next_nonstatic_field_offset; + next_nonstatic_double_offset = next_nonstatic_oop_offset + + (nonstatic_oop_count * heapOopSize); + } else if( allocation_style == 1 ) { + // Fields order: longs/doubles, ints, shorts/chars, bytes, oops, padded fields + next_nonstatic_double_offset = next_nonstatic_field_offset; + } else if( allocation_style == 2 ) { + // Fields allocation: oops fields in super and sub classes are together. + if( nonstatic_field_size > 0 && _super_klass() != NULL && + _super_klass->nonstatic_oop_map_size() > 0 ) { + unsigned int map_count = _super_klass->nonstatic_oop_map_count(); + OopMapBlock* first_map = _super_klass->start_of_nonstatic_oop_maps(); + OopMapBlock* last_map = first_map + map_count - 1; + int next_offset = last_map->offset() + (last_map->count() * heapOopSize); + if (next_offset == next_nonstatic_field_offset) { + allocation_style = 0; // allocate oops first + next_nonstatic_oop_offset = next_nonstatic_field_offset; + next_nonstatic_double_offset = next_nonstatic_oop_offset + + (nonstatic_oop_count * heapOopSize); + } + } + if( allocation_style == 2 ) { + allocation_style = 1; // allocate oops last + next_nonstatic_double_offset = next_nonstatic_field_offset; + } + } else { + ShouldNotReachHere(); + } + + int nonstatic_oop_space_count = 0; + int nonstatic_word_space_count = 0; + int nonstatic_short_space_count = 0; + int nonstatic_byte_space_count = 0; + int nonstatic_oop_space_offset; + int nonstatic_word_space_offset; + int nonstatic_short_space_offset; + int nonstatic_byte_space_offset; + + if( nonstatic_double_count > 0 ) { + int offset = next_nonstatic_double_offset; + next_nonstatic_double_offset = align_size_up(offset, BytesPerLong); + if( compact_fields && offset != next_nonstatic_double_offset ) { + // Allocate available fields into the gap before double field. + int length = next_nonstatic_double_offset - offset; + assert(length == BytesPerInt, ""); + nonstatic_word_space_offset = offset; + if( nonstatic_word_count > 0 ) { + nonstatic_word_count -= 1; + nonstatic_word_space_count = 1; // Only one will fit + length -= BytesPerInt; + offset += BytesPerInt; + } + nonstatic_short_space_offset = offset; + while( length >= BytesPerShort && nonstatic_short_count > 0 ) { + nonstatic_short_count -= 1; + nonstatic_short_space_count += 1; + length -= BytesPerShort; + offset += BytesPerShort; + } + nonstatic_byte_space_offset = offset; + while( length > 0 && nonstatic_byte_count > 0 ) { + nonstatic_byte_count -= 1; + nonstatic_byte_space_count += 1; + length -= 1; + } + // Allocate oop field in the gap if there are no other fields for that. + nonstatic_oop_space_offset = offset; + if( length >= heapOopSize && nonstatic_oop_count > 0 && + allocation_style != 0 ) { // when oop fields not first + nonstatic_oop_count -= 1; + nonstatic_oop_space_count = 1; // Only one will fit + length -= heapOopSize; + offset += heapOopSize; + } + } + } + + next_nonstatic_word_offset = next_nonstatic_double_offset + + (nonstatic_double_count * BytesPerLong); + next_nonstatic_short_offset = next_nonstatic_word_offset + + (nonstatic_word_count * BytesPerInt); + next_nonstatic_byte_offset = next_nonstatic_short_offset + + (nonstatic_short_count * BytesPerShort); + next_nonstatic_padded_offset = next_nonstatic_byte_offset + + nonstatic_byte_count; + + // let oops jump before padding with this allocation style + if( allocation_style == 1 ) { + next_nonstatic_oop_offset = next_nonstatic_padded_offset; + if( nonstatic_oop_count > 0 ) { + next_nonstatic_oop_offset = align_size_up(next_nonstatic_oop_offset, heapOopSize); + } + next_nonstatic_padded_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize); + } + + // Iterate over fields again and compute correct offsets. + // The field allocation type was temporarily stored in the offset slot. + // oop fields are located before non-oop fields (static and non-static). + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + + // skip already laid out fields + if (fs.is_offset_set()) continue; + + // contended instance fields are handled below + if (fs.is_contended() && !fs.access_flags().is_static()) continue; + + int real_offset; + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + + // pack the rest of the fields + switch (atype) { + case STATIC_OOP: + real_offset = next_static_oop_offset; + next_static_oop_offset += heapOopSize; + break; + case STATIC_BYTE: + real_offset = next_static_byte_offset; + next_static_byte_offset += 1; + break; + case STATIC_SHORT: + real_offset = next_static_short_offset; + next_static_short_offset += BytesPerShort; + break; + case STATIC_WORD: + real_offset = next_static_word_offset; + next_static_word_offset += BytesPerInt; + break; + case STATIC_DOUBLE: + real_offset = next_static_double_offset; + next_static_double_offset += BytesPerLong; + break; + case NONSTATIC_OOP: + if( nonstatic_oop_space_count > 0 ) { + real_offset = nonstatic_oop_space_offset; + nonstatic_oop_space_offset += heapOopSize; + nonstatic_oop_space_count -= 1; + } else { + real_offset = next_nonstatic_oop_offset; + next_nonstatic_oop_offset += heapOopSize; + } + // Update oop maps + if( nonstatic_oop_map_count > 0 && + nonstatic_oop_offsets[nonstatic_oop_map_count - 1] == + real_offset - + int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) * + heapOopSize ) { + // Extend current oop map + nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1; + } else { + // Create new oop map + nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; + nonstatic_oop_counts [nonstatic_oop_map_count] = 1; + nonstatic_oop_map_count += 1; + if( first_nonstatic_oop_offset == 0 ) { // Undefined + first_nonstatic_oop_offset = real_offset; + } + } + break; + case NONSTATIC_BYTE: + if( nonstatic_byte_space_count > 0 ) { + real_offset = nonstatic_byte_space_offset; + nonstatic_byte_space_offset += 1; + nonstatic_byte_space_count -= 1; + } else { + real_offset = next_nonstatic_byte_offset; + next_nonstatic_byte_offset += 1; + } + break; + case NONSTATIC_SHORT: + if( nonstatic_short_space_count > 0 ) { + real_offset = nonstatic_short_space_offset; + nonstatic_short_space_offset += BytesPerShort; + nonstatic_short_space_count -= 1; + } else { + real_offset = next_nonstatic_short_offset; + next_nonstatic_short_offset += BytesPerShort; + } + break; + case NONSTATIC_WORD: + if( nonstatic_word_space_count > 0 ) { + real_offset = nonstatic_word_space_offset; + nonstatic_word_space_offset += BytesPerInt; + nonstatic_word_space_count -= 1; + } else { + real_offset = next_nonstatic_word_offset; + next_nonstatic_word_offset += BytesPerInt; + } + break; + case NONSTATIC_DOUBLE: + real_offset = next_nonstatic_double_offset; + next_nonstatic_double_offset += BytesPerLong; + break; + default: + ShouldNotReachHere(); + } + fs.set_offset(real_offset); + } + + + // Handle the contended cases. + // + // Each contended field should not intersect the cache line with another contended field. + // In the absence of alignment information, we end up with pessimistically separating + // the fields with full-width padding. + // + // Additionally, this should not break alignment for the fields, so we round the alignment up + // for each field. + if (contended_count > 0) { + + // if there is at least one contended field, we need to have pre-padding for them + if (nonstatic_contended_count > 0) { + next_nonstatic_padded_offset += pad_size; + } + + // collect all contended groups + BitMap bm(_cp->size()); + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + // skip already laid out fields + if (fs.is_offset_set()) continue; + + if (fs.is_contended()) { + bm.set_bit(fs.contended_group()); + } + } + + int current_group = -1; + while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) { + + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + + // skip already laid out fields + if (fs.is_offset_set()) continue; + + // skip non-contended fields and fields from different group + if (!fs.is_contended() || (fs.contended_group() != current_group)) continue; + + // handle statics below + if (fs.access_flags().is_static()) continue; + + int real_offset; + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + + switch (atype) { + case NONSTATIC_BYTE: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, 1); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += 1; + break; + + case NONSTATIC_SHORT: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerShort); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += BytesPerShort; + break; + + case NONSTATIC_WORD: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerInt); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += BytesPerInt; + break; + + case NONSTATIC_DOUBLE: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerLong); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += BytesPerLong; + break; + + case NONSTATIC_OOP: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, heapOopSize); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += heapOopSize; + + // Create new oop map + nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; + nonstatic_oop_counts [nonstatic_oop_map_count] = 1; + nonstatic_oop_map_count += 1; + if( first_nonstatic_oop_offset == 0 ) { // Undefined + first_nonstatic_oop_offset = real_offset; + } + break; + + default: + ShouldNotReachHere(); + } + + if (fs.contended_group() == 0) { + // Contended group defines the equivalence class over the fields: + // the fields within the same contended group are not inter-padded. + // The only exception is default group, which does not incur the + // equivalence, and so requires intra-padding. + next_nonstatic_padded_offset += pad_size; + } + + fs.set_offset(real_offset); + } // for + + // Start laying out the next group. + // Note that this will effectively pad the last group in the back; + // this is expected to alleviate memory contention effects for + // subclass fields and/or adjacent object. + // If this was the default group, the padding is already in place. + if (current_group != 0) { + next_nonstatic_padded_offset += pad_size; + } + } + + // handle static fields + } + + // Size of instances + int notaligned_offset = next_nonstatic_padded_offset; + + // Entire class is contended, pad in the back. + // This helps to alleviate memory contention effects for subclass fields + // and/or adjacent object. + if (parsed_annotations->is_contended()) { + notaligned_offset += pad_size; + } + + int next_static_type_offset = align_size_up(next_static_byte_offset, wordSize); + int static_field_size = (next_static_type_offset - + InstanceMirrorKlass::offset_of_static_fields()) / wordSize; + + next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize ); + nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset + - first_nonstatic_field_offset)/heapOopSize); + + next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize ); + int instance_size = align_object_size(next_nonstatic_type_offset / wordSize); + + assert(instance_size == align_object_size(align_size_up( + (instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize + ((parsed_annotations->is_contended()) ? pad_size : 0)), + wordSize) / wordSize), "consistent layout helper value"); + + // Number of non-static oop map blocks allocated at end of klass. + const unsigned int total_oop_map_count = + compute_oop_map_count(_super_klass, nonstatic_oop_map_count, + first_nonstatic_oop_offset); + +#ifndef PRODUCT + if( PrintCompactFieldsSavings ) { + ResourceMark rm; + if( nonstatic_field_size < orig_nonstatic_field_size ) { + tty->print("[Saved %d of %d bytes in %s]\n", + (orig_nonstatic_field_size - nonstatic_field_size)*heapOopSize, + orig_nonstatic_field_size*heapOopSize, + _class_name); + } else if( nonstatic_field_size > orig_nonstatic_field_size ) { + tty->print("[Wasted %d over %d bytes in %s]\n", + (nonstatic_field_size - orig_nonstatic_field_size)*heapOopSize, + orig_nonstatic_field_size*heapOopSize, + _class_name); + } + } + + if (PrintFieldLayout) { + print_field_layout(_class_name, + _fields, + _cp, + instance_size, + first_nonstatic_field_offset, + next_nonstatic_field_offset, + next_static_type_offset); + } + +#endif + // Pass back information needed for InstanceKlass creation + info->nonstatic_oop_offsets = nonstatic_oop_offsets; + info->nonstatic_oop_counts = nonstatic_oop_counts; + info->nonstatic_oop_map_count = nonstatic_oop_map_count; + info->total_oop_map_count = total_oop_map_count; + info->instance_size = instance_size; + info->static_field_size = static_field_size; + info->nonstatic_field_size = nonstatic_field_size; + info->has_nonstatic_fields = has_nonstatic_fields; +} + + instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, ClassLoaderData* loader_data, Handle protection_domain, @@ -3176,7 +3673,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, jt->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::PARSE_CLASS); - init_parsed_class_attributes(); + init_parsed_class_attributes(loader_data); if (JvmtiExport::should_post_class_file_load_hook()) { // Get the cached class file bytes (if any) from the class that @@ -3271,8 +3768,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, _relax_verify = Verifier::relax_verify_for(class_loader()); // Constant pool - constantPoolHandle cp = parse_constant_pool(loader_data, CHECK_(nullHandle)); - ConstantPoolCleaner error_handler(cp); // set constant pool to be cleaned up. + constantPoolHandle cp = parse_constant_pool(CHECK_(nullHandle)); int cp_size = cp->length(); @@ -3290,7 +3786,6 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, access_flags.set_flags(flags); // This class and superclass - instanceKlassHandle super_klass; u2 this_class_index = cfs->get_u2_fast(); check_property( valid_cp_range(this_class_index, cp_size) && @@ -3345,59 +3840,27 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } u2 super_class_index = cfs->get_u2_fast(); - if (super_class_index == 0) { - check_property(class_name == vmSymbols::java_lang_Object(), - "Invalid superclass index %u in class file %s", - super_class_index, - CHECK_(nullHandle)); - } else { - check_property(valid_cp_range(super_class_index, cp_size) && - is_klass_reference(cp, super_class_index), - "Invalid superclass index %u in class file %s", - super_class_index, - CHECK_(nullHandle)); - // The class name should be legal because it is checked when parsing constant pool. - // However, make sure it is not an array type. - bool is_array = false; - if (cp->tag_at(super_class_index).is_klass()) { - super_klass = instanceKlassHandle(THREAD, cp->resolved_klass_at(super_class_index)); - if (_need_verify) - is_array = super_klass->oop_is_array(); - } else if (_need_verify) { - is_array = (cp->unresolved_klass_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY); - } - if (_need_verify) { - guarantee_property(!is_array, - "Bad superclass name in class file %s", CHECK_(nullHandle)); - } - } + instanceKlassHandle super_klass = parse_super_class(super_class_index, + CHECK_NULL); // Interfaces u2 itfs_len = cfs->get_u2_fast(); - Array<Klass*>* local_interfaces; - if (itfs_len == 0) { - local_interfaces = Universe::the_empty_klass_array(); - } else { - local_interfaces = parse_interfaces( - cp, itfs_len, loader_data, protection_domain, _class_name, - &has_default_methods, CHECK_(nullHandle)); - } + Array<Klass*>* local_interfaces = + parse_interfaces(itfs_len, protection_domain, _class_name, + &has_default_methods, CHECK_(nullHandle)); u2 java_fields_count = 0; // Fields (offsets are filled in later) FieldAllocationCount fac; - Array<AnnotationArray*>* fields_annotations = NULL; - Array<AnnotationArray*>* fields_type_annotations = NULL; - Array<u2>* fields = parse_fields(loader_data, class_name, cp, access_flags.is_interface(), &fac, &fields_annotations, - &fields_type_annotations, - &java_fields_count, - CHECK_(nullHandle)); + Array<u2>* fields = parse_fields(class_name, + access_flags.is_interface(), + &fac, &java_fields_count, + CHECK_(nullHandle)); // Methods bool has_final_method = false; AccessFlags promoted_flags; promoted_flags.set_flags(0); - Array<Method*>* methods = parse_methods(loader_data, - cp, access_flags.is_interface(), + Array<Method*>* methods = parse_methods(access_flags.is_interface(), &promoted_flags, &has_final_method, &has_default_methods, @@ -3405,7 +3868,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, // Additional attributes ClassAnnotationCollector parsed_annotations; - parse_classfile_attributes(loader_data, cp, &parsed_annotations, CHECK_(nullHandle)); + parse_classfile_attributes(&parsed_annotations, CHECK_(nullHandle)); // Make sure this is the end of class file stream guarantee_property(cfs->at_eos(), "Extra bytes at the end of class file %s", CHECK_(nullHandle)); @@ -3452,13 +3915,15 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } } + // save super klass for error handling. + _super_klass = super_klass; + // Compute the transitive list of all unique interfaces implemented by this class - Array<Klass*>* transitive_interfaces = compute_transitive_interfaces(loader_data, super_klass, local_interfaces, CHECK_(nullHandle)); + _transitive_interfaces = + compute_transitive_interfaces(super_klass, local_interfaces, CHECK_(nullHandle)); // sort methods - Array<int>* method_ordering = sort_methods(loader_data, - methods, - CHECK_(nullHandle)); + intArray* method_ordering = sort_methods(methods); // promote flags from parse_methods() to the klass' flags access_flags.add_promoted_flags(promoted_flags.as_int()); @@ -3476,495 +3941,14 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, CHECK_(nullHandle)); // Size of Java itable (in words) - itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(transitive_interfaces); + itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(_transitive_interfaces); - // get the padding width from the option - // TODO: Ask VM about specific CPU we are running on - int pad_size = ContendedPaddingWidth; + FieldLayoutInfo info; + layout_fields(class_loader, &fac, &parsed_annotations, &info, CHECK_NULL); - // Field size and offset computation - int nonstatic_field_size = super_klass() == NULL ? 0 : super_klass->nonstatic_field_size(); -#ifndef PRODUCT - int orig_nonstatic_field_size = 0; -#endif - int next_static_oop_offset; - int next_static_double_offset; - int next_static_word_offset; - int next_static_short_offset; - int next_static_byte_offset; - int next_nonstatic_oop_offset; - int next_nonstatic_double_offset; - int next_nonstatic_word_offset; - int next_nonstatic_short_offset; - int next_nonstatic_byte_offset; - int next_nonstatic_type_offset; - int first_nonstatic_oop_offset; - int first_nonstatic_field_offset; - int next_nonstatic_field_offset; - int next_nonstatic_padded_offset; + int total_oop_map_size2 = + InstanceKlass::nonstatic_oop_map_size(info.total_oop_map_count); - // Count the contended fields by type. - int nonstatic_contended_count = 0; - FieldAllocationCount fac_contended; - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); - if (fs.is_contended()) { - fac_contended.count[atype]++; - if (!fs.access_flags().is_static()) { - nonstatic_contended_count++; - } - } - } - int contended_count = nonstatic_contended_count; - - - // Calculate the starting byte offsets - next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields(); - - next_static_double_offset = next_static_oop_offset + - ((fac.count[STATIC_OOP]) * heapOopSize); - if ( fac.count[STATIC_DOUBLE] && - (Universe::field_type_should_be_aligned(T_DOUBLE) || - Universe::field_type_should_be_aligned(T_LONG)) ) { - next_static_double_offset = align_size_up(next_static_double_offset, BytesPerLong); - } - - next_static_word_offset = next_static_double_offset + - ((fac.count[STATIC_DOUBLE]) * BytesPerLong); - next_static_short_offset = next_static_word_offset + - ((fac.count[STATIC_WORD]) * BytesPerInt); - next_static_byte_offset = next_static_short_offset + - ((fac.count[STATIC_SHORT]) * BytesPerShort); - - first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + - nonstatic_field_size * heapOopSize; - - // class is contended, pad before all the fields - if (parsed_annotations.is_contended()) { - first_nonstatic_field_offset += pad_size; - } - - next_nonstatic_field_offset = first_nonstatic_field_offset; - - unsigned int nonstatic_double_count = fac.count[NONSTATIC_DOUBLE] - fac_contended.count[NONSTATIC_DOUBLE]; - unsigned int nonstatic_word_count = fac.count[NONSTATIC_WORD] - fac_contended.count[NONSTATIC_WORD]; - unsigned int nonstatic_short_count = fac.count[NONSTATIC_SHORT] - fac_contended.count[NONSTATIC_SHORT]; - unsigned int nonstatic_byte_count = fac.count[NONSTATIC_BYTE] - fac_contended.count[NONSTATIC_BYTE]; - unsigned int nonstatic_oop_count = fac.count[NONSTATIC_OOP] - fac_contended.count[NONSTATIC_OOP]; - - bool super_has_nonstatic_fields = - (super_klass() != NULL && super_klass->has_nonstatic_fields()); - bool has_nonstatic_fields = super_has_nonstatic_fields || - ((nonstatic_double_count + nonstatic_word_count + - nonstatic_short_count + nonstatic_byte_count + - nonstatic_oop_count) != 0); - - - // Prepare list of oops for oop map generation. - int* nonstatic_oop_offsets; - unsigned int* nonstatic_oop_counts; - unsigned int nonstatic_oop_map_count = 0; - - nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD( - THREAD, int, nonstatic_oop_count + 1); - nonstatic_oop_counts = NEW_RESOURCE_ARRAY_IN_THREAD( - THREAD, unsigned int, nonstatic_oop_count + 1); - - first_nonstatic_oop_offset = 0; // will be set for first oop field - -#ifndef PRODUCT - if( PrintCompactFieldsSavings ) { - next_nonstatic_double_offset = next_nonstatic_field_offset + - (nonstatic_oop_count * heapOopSize); - if ( nonstatic_double_count > 0 ) { - next_nonstatic_double_offset = align_size_up(next_nonstatic_double_offset, BytesPerLong); - } - next_nonstatic_word_offset = next_nonstatic_double_offset + - (nonstatic_double_count * BytesPerLong); - next_nonstatic_short_offset = next_nonstatic_word_offset + - (nonstatic_word_count * BytesPerInt); - next_nonstatic_byte_offset = next_nonstatic_short_offset + - (nonstatic_short_count * BytesPerShort); - next_nonstatic_type_offset = align_size_up((next_nonstatic_byte_offset + - nonstatic_byte_count ), heapOopSize ); - orig_nonstatic_field_size = nonstatic_field_size + - ((next_nonstatic_type_offset - first_nonstatic_field_offset)/heapOopSize); - } -#endif - bool compact_fields = CompactFields; - int allocation_style = FieldsAllocationStyle; - if( allocation_style < 0 || allocation_style > 2 ) { // Out of range? - assert(false, "0 <= FieldsAllocationStyle <= 2"); - allocation_style = 1; // Optimistic - } - - // The next classes have predefined hard-coded fields offsets - // (see in JavaClasses::compute_hard_coded_offsets()). - // Use default fields allocation order for them. - if( (allocation_style != 0 || compact_fields ) && class_loader.is_null() && - (class_name == vmSymbols::java_lang_AssertionStatusDirectives() || - class_name == vmSymbols::java_lang_Class() || - class_name == vmSymbols::java_lang_ClassLoader() || - class_name == vmSymbols::java_lang_ref_Reference() || - class_name == vmSymbols::java_lang_ref_SoftReference() || - class_name == vmSymbols::java_lang_StackTraceElement() || - class_name == vmSymbols::java_lang_String() || - class_name == vmSymbols::java_lang_Throwable() || - class_name == vmSymbols::java_lang_Boolean() || - class_name == vmSymbols::java_lang_Character() || - class_name == vmSymbols::java_lang_Float() || - class_name == vmSymbols::java_lang_Double() || - class_name == vmSymbols::java_lang_Byte() || - class_name == vmSymbols::java_lang_Short() || - class_name == vmSymbols::java_lang_Integer() || - class_name == vmSymbols::java_lang_Long())) { - allocation_style = 0; // Allocate oops first - compact_fields = false; // Don't compact fields - } - - if( allocation_style == 0 ) { - // Fields order: oops, longs/doubles, ints, shorts/chars, bytes, padded fields - next_nonstatic_oop_offset = next_nonstatic_field_offset; - next_nonstatic_double_offset = next_nonstatic_oop_offset + - (nonstatic_oop_count * heapOopSize); - } else if( allocation_style == 1 ) { - // Fields order: longs/doubles, ints, shorts/chars, bytes, oops, padded fields - next_nonstatic_double_offset = next_nonstatic_field_offset; - } else if( allocation_style == 2 ) { - // Fields allocation: oops fields in super and sub classes are together. - if( nonstatic_field_size > 0 && super_klass() != NULL && - super_klass->nonstatic_oop_map_size() > 0 ) { - int map_count = super_klass->nonstatic_oop_map_count(); - OopMapBlock* first_map = super_klass->start_of_nonstatic_oop_maps(); - OopMapBlock* last_map = first_map + map_count - 1; - int next_offset = last_map->offset() + (last_map->count() * heapOopSize); - if (next_offset == next_nonstatic_field_offset) { - allocation_style = 0; // allocate oops first - next_nonstatic_oop_offset = next_nonstatic_field_offset; - next_nonstatic_double_offset = next_nonstatic_oop_offset + - (nonstatic_oop_count * heapOopSize); - } - } - if( allocation_style == 2 ) { - allocation_style = 1; // allocate oops last - next_nonstatic_double_offset = next_nonstatic_field_offset; - } - } else { - ShouldNotReachHere(); - } - - int nonstatic_oop_space_count = 0; - int nonstatic_word_space_count = 0; - int nonstatic_short_space_count = 0; - int nonstatic_byte_space_count = 0; - int nonstatic_oop_space_offset; - int nonstatic_word_space_offset; - int nonstatic_short_space_offset; - int nonstatic_byte_space_offset; - - if( nonstatic_double_count > 0 ) { - int offset = next_nonstatic_double_offset; - next_nonstatic_double_offset = align_size_up(offset, BytesPerLong); - if( compact_fields && offset != next_nonstatic_double_offset ) { - // Allocate available fields into the gap before double field. - int length = next_nonstatic_double_offset - offset; - assert(length == BytesPerInt, ""); - nonstatic_word_space_offset = offset; - if( nonstatic_word_count > 0 ) { - nonstatic_word_count -= 1; - nonstatic_word_space_count = 1; // Only one will fit - length -= BytesPerInt; - offset += BytesPerInt; - } - nonstatic_short_space_offset = offset; - while( length >= BytesPerShort && nonstatic_short_count > 0 ) { - nonstatic_short_count -= 1; - nonstatic_short_space_count += 1; - length -= BytesPerShort; - offset += BytesPerShort; - } - nonstatic_byte_space_offset = offset; - while( length > 0 && nonstatic_byte_count > 0 ) { - nonstatic_byte_count -= 1; - nonstatic_byte_space_count += 1; - length -= 1; - } - // Allocate oop field in the gap if there are no other fields for that. - nonstatic_oop_space_offset = offset; - if( length >= heapOopSize && nonstatic_oop_count > 0 && - allocation_style != 0 ) { // when oop fields not first - nonstatic_oop_count -= 1; - nonstatic_oop_space_count = 1; // Only one will fit - length -= heapOopSize; - offset += heapOopSize; - } - } - } - - next_nonstatic_word_offset = next_nonstatic_double_offset + - (nonstatic_double_count * BytesPerLong); - next_nonstatic_short_offset = next_nonstatic_word_offset + - (nonstatic_word_count * BytesPerInt); - next_nonstatic_byte_offset = next_nonstatic_short_offset + - (nonstatic_short_count * BytesPerShort); - next_nonstatic_padded_offset = next_nonstatic_byte_offset + - nonstatic_byte_count; - - // let oops jump before padding with this allocation style - if( allocation_style == 1 ) { - next_nonstatic_oop_offset = next_nonstatic_padded_offset; - if( nonstatic_oop_count > 0 ) { - next_nonstatic_oop_offset = align_size_up(next_nonstatic_oop_offset, heapOopSize); - } - next_nonstatic_padded_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize); - } - - // Iterate over fields again and compute correct offsets. - // The field allocation type was temporarily stored in the offset slot. - // oop fields are located before non-oop fields (static and non-static). - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - - // skip already laid out fields - if (fs.is_offset_set()) continue; - - // contended instance fields are handled below - if (fs.is_contended() && !fs.access_flags().is_static()) continue; - - int real_offset; - FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); - - // pack the rest of the fields - switch (atype) { - case STATIC_OOP: - real_offset = next_static_oop_offset; - next_static_oop_offset += heapOopSize; - break; - case STATIC_BYTE: - real_offset = next_static_byte_offset; - next_static_byte_offset += 1; - break; - case STATIC_SHORT: - real_offset = next_static_short_offset; - next_static_short_offset += BytesPerShort; - break; - case STATIC_WORD: - real_offset = next_static_word_offset; - next_static_word_offset += BytesPerInt; - break; - case STATIC_DOUBLE: - real_offset = next_static_double_offset; - next_static_double_offset += BytesPerLong; - break; - case NONSTATIC_OOP: - if( nonstatic_oop_space_count > 0 ) { - real_offset = nonstatic_oop_space_offset; - nonstatic_oop_space_offset += heapOopSize; - nonstatic_oop_space_count -= 1; - } else { - real_offset = next_nonstatic_oop_offset; - next_nonstatic_oop_offset += heapOopSize; - } - // Update oop maps - if( nonstatic_oop_map_count > 0 && - nonstatic_oop_offsets[nonstatic_oop_map_count - 1] == - real_offset - - int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) * - heapOopSize ) { - // Extend current oop map - nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1; - } else { - // Create new oop map - nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; - nonstatic_oop_counts [nonstatic_oop_map_count] = 1; - nonstatic_oop_map_count += 1; - if( first_nonstatic_oop_offset == 0 ) { // Undefined - first_nonstatic_oop_offset = real_offset; - } - } - break; - case NONSTATIC_BYTE: - if( nonstatic_byte_space_count > 0 ) { - real_offset = nonstatic_byte_space_offset; - nonstatic_byte_space_offset += 1; - nonstatic_byte_space_count -= 1; - } else { - real_offset = next_nonstatic_byte_offset; - next_nonstatic_byte_offset += 1; - } - break; - case NONSTATIC_SHORT: - if( nonstatic_short_space_count > 0 ) { - real_offset = nonstatic_short_space_offset; - nonstatic_short_space_offset += BytesPerShort; - nonstatic_short_space_count -= 1; - } else { - real_offset = next_nonstatic_short_offset; - next_nonstatic_short_offset += BytesPerShort; - } - break; - case NONSTATIC_WORD: - if( nonstatic_word_space_count > 0 ) { - real_offset = nonstatic_word_space_offset; - nonstatic_word_space_offset += BytesPerInt; - nonstatic_word_space_count -= 1; - } else { - real_offset = next_nonstatic_word_offset; - next_nonstatic_word_offset += BytesPerInt; - } - break; - case NONSTATIC_DOUBLE: - real_offset = next_nonstatic_double_offset; - next_nonstatic_double_offset += BytesPerLong; - break; - default: - ShouldNotReachHere(); - } - fs.set_offset(real_offset); - } - - - // Handle the contended cases. - // - // Each contended field should not intersect the cache line with another contended field. - // In the absence of alignment information, we end up with pessimistically separating - // the fields with full-width padding. - // - // Additionally, this should not break alignment for the fields, so we round the alignment up - // for each field. - if (contended_count > 0) { - - // if there is at least one contended field, we need to have pre-padding for them - if (nonstatic_contended_count > 0) { - next_nonstatic_padded_offset += pad_size; - } - - // collect all contended groups - BitMap bm(cp->size()); - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - // skip already laid out fields - if (fs.is_offset_set()) continue; - - if (fs.is_contended()) { - bm.set_bit(fs.contended_group()); - } - } - - int current_group = -1; - while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) { - - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - - // skip already laid out fields - if (fs.is_offset_set()) continue; - - // skip non-contended fields and fields from different group - if (!fs.is_contended() || (fs.contended_group() != current_group)) continue; - - // handle statics below - if (fs.access_flags().is_static()) continue; - - int real_offset; - FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); - - switch (atype) { - case NONSTATIC_BYTE: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, 1); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += 1; - break; - - case NONSTATIC_SHORT: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerShort); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += BytesPerShort; - break; - - case NONSTATIC_WORD: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerInt); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += BytesPerInt; - break; - - case NONSTATIC_DOUBLE: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerLong); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += BytesPerLong; - break; - - case NONSTATIC_OOP: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, heapOopSize); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += heapOopSize; - - // Create new oop map - nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; - nonstatic_oop_counts [nonstatic_oop_map_count] = 1; - nonstatic_oop_map_count += 1; - if( first_nonstatic_oop_offset == 0 ) { // Undefined - first_nonstatic_oop_offset = real_offset; - } - break; - - default: - ShouldNotReachHere(); - } - - if (fs.contended_group() == 0) { - // Contended group defines the equivalence class over the fields: - // the fields within the same contended group are not inter-padded. - // The only exception is default group, which does not incur the - // equivalence, and so requires intra-padding. - next_nonstatic_padded_offset += pad_size; - } - - fs.set_offset(real_offset); - } // for - - // Start laying out the next group. - // Note that this will effectively pad the last group in the back; - // this is expected to alleviate memory contention effects for - // subclass fields and/or adjacent object. - // If this was the default group, the padding is already in place. - if (current_group != 0) { - next_nonstatic_padded_offset += pad_size; - } - } - - // handle static fields - - } // handle contended - - // Size of instances - int instance_size; - - int notaligned_offset = next_nonstatic_padded_offset; - - // Entire class is contended, pad in the back. - // This helps to alleviate memory contention effects for subclass fields - // and/or adjacent object. - if (parsed_annotations.is_contended()) { - notaligned_offset += pad_size; - } - - int next_static_type_offset = align_size_up(next_static_byte_offset, wordSize); - int static_field_size = (next_static_type_offset - - InstanceMirrorKlass::offset_of_static_fields()) / wordSize; - - next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize ); - nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset - - first_nonstatic_field_offset)/heapOopSize); - - next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize ); - instance_size = align_object_size(next_nonstatic_type_offset / wordSize); - - assert(instance_size == align_object_size(align_size_up( - (instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize + ((parsed_annotations.is_contended()) ? pad_size : 0)), - wordSize) / wordSize), "consistent layout helper value"); - - // Number of non-static oop map blocks allocated at end of klass. - const unsigned int total_oop_map_count = - compute_oop_map_count(super_klass, nonstatic_oop_map_count, - first_nonstatic_oop_offset); // Compute reference type ReferenceType rt; if (super_klass() == NULL) { @@ -3974,53 +3958,42 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } // We can now create the basic Klass* for this klass - int total_oop_map_size2 = - InstanceKlass::nonstatic_oop_map_size(total_oop_map_count); + _klass = InstanceKlass::allocate_instance_klass(loader_data, + vtable_size, + itable_size, + info.static_field_size, + total_oop_map_size2, + rt, + access_flags, + name, + super_klass(), + !host_klass.is_null(), + CHECK_(nullHandle)); + instanceKlassHandle this_klass (THREAD, _klass); - Klass* ik = InstanceKlass::allocate_instance_klass(loader_data, - vtable_size, - itable_size, - static_field_size, - total_oop_map_size2, - rt, - access_flags, - name, - super_klass(), - !host_klass.is_null(), - CHECK_(nullHandle)); - - // Add all classes to our internal class loader list here, - // including classes in the bootstrap (NULL) class loader. - loader_data->add_class(ik); - - instanceKlassHandle this_klass (THREAD, ik); - - assert(this_klass->static_field_size() == static_field_size, "sanity"); - assert(this_klass->nonstatic_oop_map_count() == total_oop_map_count, + assert(this_klass->static_field_size() == info.static_field_size, "sanity"); + assert(this_klass->nonstatic_oop_map_count() == info.total_oop_map_count, "sanity"); // Fill in information already parsed this_klass->set_should_verify_class(verify); - jint lh = Klass::instance_layout_helper(instance_size, false); + jint lh = Klass::instance_layout_helper(info.instance_size, false); this_klass->set_layout_helper(lh); assert(this_klass->oop_is_instance(), "layout is correct"); - assert(this_klass->size_helper() == instance_size, "correct size_helper"); + assert(this_klass->size_helper() == info.instance_size, "correct size_helper"); // Not yet: supers are done below to support the new subtype-checking fields //this_klass->set_super(super_klass()); this_klass->set_class_loader_data(loader_data); - this_klass->set_nonstatic_field_size(nonstatic_field_size); - this_klass->set_has_nonstatic_fields(has_nonstatic_fields); + this_klass->set_nonstatic_field_size(info.nonstatic_field_size); + this_klass->set_has_nonstatic_fields(info.has_nonstatic_fields); this_klass->set_static_oop_field_count(fac.count[STATIC_OOP]); - cp->set_pool_holder(this_klass()); - error_handler.set_in_error(false); // turn off error handler for cp - this_klass->set_constants(cp()); - this_klass->set_local_interfaces(local_interfaces); - this_klass->set_fields(fields, java_fields_count); - this_klass->set_methods(methods); + + apply_parsed_class_metadata(this_klass, java_fields_count, CHECK_NULL); + if (has_final_method) { this_klass->set_has_final_method(); } - this_klass->set_method_ordering(method_ordering); + this_klass->copy_method_ordering(method_ordering, CHECK_NULL); // The InstanceKlass::_methods_jmethod_ids cache and the // InstanceKlass::_methods_cached_itable_indices cache are // both managed on the assumption that the initial cache @@ -4032,17 +4005,6 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, if (is_anonymous()) // I am well known to myself cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve - // Assign allocations if needed - if (_annotations != NULL || _type_annotations != NULL || - fields_annotations != NULL || fields_type_annotations != NULL) { - Annotations* annotations = Annotations::allocate(loader_data, CHECK_NULL); - annotations->set_class_annotations(_annotations); - annotations->set_class_type_annotations(_type_annotations); - annotations->set_fields_annotations(fields_annotations); - annotations->set_fields_type_annotations(fields_type_annotations); - this_klass->set_annotations(annotations); - } - this_klass->set_minor_version(minor_version); this_klass->set_major_version(major_version); this_klass->set_has_default_methods(has_default_methods); @@ -4077,8 +4039,6 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, this_klass->set_has_miranda_methods(); // then set a flag } - this_klass->set_transitive_interfaces(transitive_interfaces); - // Fill in information needed to compute superclasses. this_klass->initialize_supers(super_klass(), CHECK_(nullHandle)); @@ -4087,7 +4047,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, // Compute transitive closure of interfaces this class implements // Do final class setup - fill_oop_maps(this_klass, nonstatic_oop_map_count, nonstatic_oop_offsets, nonstatic_oop_counts); + fill_oop_maps(this_klass, info.nonstatic_oop_map_count, info.nonstatic_oop_offsets, info.nonstatic_oop_counts); // Fill in has_finalizer, has_vanilla_constructor, and layout_helper set_precomputed_flags(this_klass); @@ -4186,35 +4146,6 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } } -#ifndef PRODUCT - if( PrintCompactFieldsSavings ) { - ResourceMark rm; - if( nonstatic_field_size < orig_nonstatic_field_size ) { - tty->print("[Saved %d of %d bytes in %s]\n", - (orig_nonstatic_field_size - nonstatic_field_size)*heapOopSize, - orig_nonstatic_field_size*heapOopSize, - this_klass->external_name()); - } else if( nonstatic_field_size > orig_nonstatic_field_size ) { - tty->print("[Wasted %d over %d bytes in %s]\n", - (nonstatic_field_size - orig_nonstatic_field_size)*heapOopSize, - orig_nonstatic_field_size*heapOopSize, - this_klass->external_name()); - } - } -#endif - -#ifndef PRODUCT - if (PrintFieldLayout) { - print_field_layout(name, - fields, - cp, - instance_size, - first_nonstatic_field_offset, - next_nonstatic_field_offset, - next_static_type_offset); - } -#endif - // preserve result across HandleMark preserve_this_klass = this_klass(); } @@ -4224,9 +4155,40 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, instanceKlassHandle this_klass (THREAD, preserve_this_klass); debug_only(this_klass->verify();) + // Clear class if no error has occurred so destructor doesn't deallocate it + _klass = NULL; return this_klass; } +// Destructor to clean up if there's an error +ClassFileParser::~ClassFileParser() { + MetadataFactory::free_metadata(_loader_data, _cp); + MetadataFactory::free_array<u2>(_loader_data, _fields); + + // Free methods + InstanceKlass::deallocate_methods(_loader_data, _methods); + + // beware of the Universe::empty_blah_array!! + if (_inner_classes != Universe::the_empty_short_array()) { + MetadataFactory::free_array<u2>(_loader_data, _inner_classes); + } + + // Free interfaces + InstanceKlass::deallocate_interfaces(_loader_data, _super_klass(), + _local_interfaces, _transitive_interfaces); + + MetadataFactory::free_array<u1>(_loader_data, _annotations); + MetadataFactory::free_array<u1>(_loader_data, _type_annotations); + Annotations::free_contents(_loader_data, _fields_annotations); + Annotations::free_contents(_loader_data, _fields_type_annotations); + + clear_class_metadata(); + + // deallocate the klass if already created. + MetadataFactory::free_metadata(_loader_data, _klass); + _klass = NULL; +} + void ClassFileParser::print_field_layout(Symbol* name, Array<u2>* fields, constantPoolHandle cp, @@ -4418,7 +4380,7 @@ void ClassFileParser::record_defined_class_dependencies(instanceKlassHandle defi } } -// utility method for appending and array with check for duplicates +// utility methods for appending an array with check for duplicates void append_interfaces(GrowableArray<Klass*>* result, Array<Klass*>* ifs) { // iterate over new interfaces @@ -4430,8 +4392,9 @@ void append_interfaces(GrowableArray<Klass*>* result, Array<Klass*>* ifs) { } } - -Array<Klass*>* ClassFileParser::compute_transitive_interfaces(ClassLoaderData* loader_data, instanceKlassHandle super, Array<Klass*>* local_ifs, TRAPS) { +Array<Klass*>* ClassFileParser::compute_transitive_interfaces( + instanceKlassHandle super, + Array<Klass*>* local_ifs, TRAPS) { // Compute maximum size for transitive interfaces int max_transitive_size = 0; int super_size = 0; @@ -4478,7 +4441,7 @@ Array<Klass*>* ClassFileParser::compute_transitive_interfaces(ClassLoaderData* l // length will be less than the max_transitive_size if duplicates were removed int length = result->length(); assert(length <= max_transitive_size, "just checking"); - Array<Klass*>* new_result = MetadataFactory::new_array<Klass*>(loader_data, length, CHECK_NULL); + Array<Klass*>* new_result = MetadataFactory::new_array<Klass*>(_loader_data, length, CHECK_NULL); for (int i = 0; i < length; i++) { Klass* e = result->at(i); assert(e != NULL, "just checking"); @@ -4488,7 +4451,6 @@ Array<Klass*>* ClassFileParser::compute_transitive_interfaces(ClassLoaderData* l } } - void ClassFileParser::check_super_class_access(instanceKlassHandle this_klass, TRAPS) { Klass* super = this_klass->super(); if ((super != NULL) && diff --git a/hotspot/src/share/vm/classfile/classFileParser.hpp b/hotspot/src/share/vm/classfile/classFileParser.hpp index 7cedcefb3a4..0fd8830463d 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.hpp +++ b/hotspot/src/share/vm/classfile/classFileParser.hpp @@ -34,6 +34,7 @@ #include "classfile/symbolTable.hpp" class FieldAllocationCount; +class FieldLayoutInfo; // Parser for for .class files @@ -47,6 +48,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { u2 _major_version; u2 _minor_version; Symbol* _class_name; + ClassLoaderData* _loader_data; KlassHandle _host_klass; GrowableArray<Handle>* _cp_patches; // overrides for CP entries @@ -58,33 +60,59 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { // class attributes parsed before the instance klass is created: bool _synthetic_flag; + int _sde_length; + char* _sde_buffer; Symbol* _sourcefile; Symbol* _generic_signature; - char* _sde_buffer; - int _sde_length; - Array<u2>* _inner_classes; + + // Metadata created before the instance klass is created. Must be deallocated + // if not transferred to the InstanceKlass upon successful class loading + // in which case these pointers have been set to NULL. + instanceKlassHandle _super_klass; + ConstantPool* _cp; + Array<u2>* _fields; + Array<Method*>* _methods; + Array<u2>* _inner_classes; + Array<Klass*>* _local_interfaces; + Array<Klass*>* _transitive_interfaces; AnnotationArray* _annotations; AnnotationArray* _type_annotations; + Array<AnnotationArray*>* _fields_annotations; + Array<AnnotationArray*>* _fields_type_annotations; + InstanceKlass* _klass; // InstanceKlass once created. void set_class_synthetic_flag(bool x) { _synthetic_flag = x; } void set_class_sourcefile(Symbol* x) { _sourcefile = x; } void set_class_generic_signature(Symbol* x) { _generic_signature = x; } void set_class_sde_buffer(char* x, int len) { _sde_buffer = x; _sde_length = len; } - void set_class_inner_classes(Array<u2>* x) { _inner_classes = x; } - void set_class_annotations(AnnotationArray* x) { _annotations = x; } - void set_class_type_annotations(AnnotationArray* x) { _type_annotations = x; } - void init_parsed_class_attributes() { + + void init_parsed_class_attributes(ClassLoaderData* loader_data) { + _loader_data = loader_data; _synthetic_flag = false; _sourcefile = NULL; _generic_signature = NULL; _sde_buffer = NULL; _sde_length = 0; - _annotations = _type_annotations = NULL; // initialize the other flags too: _has_finalizer = _has_empty_finalizer = _has_vanilla_constructor = false; _max_bootstrap_specifier_index = -1; + clear_class_metadata(); + _klass = NULL; } void apply_parsed_class_attributes(instanceKlassHandle k); // update k + void apply_parsed_class_metadata(instanceKlassHandle k, int fields_count, TRAPS); + void clear_class_metadata() { + // metadata created before the instance klass is created. Must be + // deallocated if classfile parsing returns an error. + _cp = NULL; + _fields = NULL; + _methods = NULL; + _inner_classes = NULL; + _local_interfaces = NULL; + _transitive_interfaces = NULL; + _annotations = _type_annotations = NULL; + _fields_annotations = _fields_type_annotations = NULL; + } class AnnotationCollector { public: @@ -124,11 +152,27 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { void set_contended(bool contended) { set_annotation(_sun_misc_Contended); } bool is_contended() { return has_annotation(_sun_misc_Contended); } }; + + // This class also doubles as a holder for metadata cleanup. class FieldAnnotationCollector: public AnnotationCollector { + ClassLoaderData* _loader_data; + AnnotationArray* _field_annotations; + AnnotationArray* _field_type_annotations; public: - FieldAnnotationCollector() : AnnotationCollector(_in_field) { } + FieldAnnotationCollector(ClassLoaderData* loader_data) : + AnnotationCollector(_in_field), + _loader_data(loader_data), + _field_annotations(NULL), + _field_type_annotations(NULL) {} void apply_to(FieldInfo* f); + ~FieldAnnotationCollector(); + AnnotationArray* field_annotations() { return _field_annotations; } + AnnotationArray* field_type_annotations() { return _field_type_annotations; } + + void set_field_annotations(AnnotationArray* a) { _field_annotations = a; } + void set_field_type_annotations(AnnotationArray* a) { _field_type_annotations = a; } }; + class MethodAnnotationCollector: public AnnotationCollector { public: MethodAnnotationCollector() : AnnotationCollector(_in_method) { } @@ -152,38 +196,30 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { void set_stream(ClassFileStream* st) { _stream = st; } // Constant pool parsing - void parse_constant_pool_entries(ClassLoaderData* loader_data, - constantPoolHandle cp, int length, TRAPS); + void parse_constant_pool_entries(int length, TRAPS); - constantPoolHandle parse_constant_pool(ClassLoaderData* loader_data, TRAPS); + constantPoolHandle parse_constant_pool(TRAPS); // Interface parsing - Array<Klass*>* parse_interfaces(constantPoolHandle cp, - int length, - ClassLoaderData* loader_data, + Array<Klass*>* parse_interfaces(int length, Handle protection_domain, Symbol* class_name, bool* has_default_methods, TRAPS); void record_defined_class_dependencies(instanceKlassHandle defined_klass, TRAPS); + instanceKlassHandle parse_super_class(int super_class_index, TRAPS); // Field parsing - void parse_field_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, u2 attributes_count, + void parse_field_attributes(u2 attributes_count, bool is_static, u2 signature_index, u2* constantvalue_index_addr, bool* is_synthetic_addr, u2* generic_signature_index_addr, - AnnotationArray** field_annotations, - AnnotationArray** field_type_annotations, FieldAnnotationCollector* parsed_annotations, TRAPS); - Array<u2>* parse_fields(ClassLoaderData* loader_data, - Symbol* class_name, - constantPoolHandle cp, bool is_interface, + Array<u2>* parse_fields(Symbol* class_name, + bool is_interface, FieldAllocationCount *fac, - Array<AnnotationArray*>** fields_annotations, - Array<AnnotationArray*>** fields_type_annotations, u2* java_fields_count_ptr, TRAPS); void print_field_layout(Symbol* name, @@ -195,65 +231,52 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { int static_fields_end); // Method parsing - methodHandle parse_method(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, + methodHandle parse_method(bool is_interface, AccessFlags* promoted_flags, TRAPS); - Array<Method*>* parse_methods(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, + Array<Method*>* parse_methods(bool is_interface, AccessFlags* promoted_flags, bool* has_final_method, bool* has_default_method, TRAPS); - Array<int>* sort_methods(ClassLoaderData* loader_data, - Array<Method*>* methods, - TRAPS); - u2* parse_exception_table(ClassLoaderData* loader_data, - u4 code_length, u4 exception_table_length, - constantPoolHandle cp, TRAPS); + intArray* sort_methods(Array<Method*>* methods); + + u2* parse_exception_table(u4 code_length, u4 exception_table_length, + TRAPS); void parse_linenumber_table( u4 code_attribute_length, u4 code_length, CompressedLineNumberWriteStream** write_stream, TRAPS); u2* parse_localvariable_table(u4 code_length, u2 max_locals, u4 code_attribute_length, - constantPoolHandle cp, u2* localvariable_table_length, + u2* localvariable_table_length, bool isLVTT, TRAPS); u2* parse_checked_exceptions(u2* checked_exceptions_length, u4 method_attribute_length, - constantPoolHandle cp, TRAPS); + TRAPS); void parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index, - u1* u1_array, u2* u2_array, constantPoolHandle cp, TRAPS); - Array<u1>* parse_stackmap_table(ClassLoaderData* loader_data, u4 code_attribute_length, TRAPS); + u1* u1_array, u2* u2_array, TRAPS); + u1* parse_stackmap_table(u4 code_attribute_length, TRAPS); // Classfile attribute parsing - void parse_classfile_sourcefile_attribute(constantPoolHandle cp, TRAPS); - void parse_classfile_source_debug_extension_attribute(constantPoolHandle cp, - int length, TRAPS); - u2 parse_classfile_inner_classes_attribute(ClassLoaderData* loader_data, - u1* inner_classes_attribute_start, + void parse_classfile_sourcefile_attribute(TRAPS); + void parse_classfile_source_debug_extension_attribute(int length, TRAPS); + u2 parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start, bool parsed_enclosingmethod_attribute, u2 enclosing_method_class_index, u2 enclosing_method_method_index, - constantPoolHandle cp, TRAPS); - void parse_classfile_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, - ClassAnnotationCollector* parsed_annotations, + void parse_classfile_attributes(ClassAnnotationCollector* parsed_annotations, TRAPS); - void parse_classfile_synthetic_attribute(constantPoolHandle cp, TRAPS); - void parse_classfile_signature_attribute(constantPoolHandle cp, TRAPS); - void parse_classfile_bootstrap_methods_attribute(ClassLoaderData* loader_data, constantPoolHandle cp, u4 attribute_length, TRAPS); + void parse_classfile_synthetic_attribute(TRAPS); + void parse_classfile_signature_attribute(TRAPS); + void parse_classfile_bootstrap_methods_attribute(u4 attribute_length, TRAPS); // Annotations handling - AnnotationArray* assemble_annotations(ClassLoaderData* loader_data, - u1* runtime_visible_annotations, + AnnotationArray* assemble_annotations(u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, int runtime_invisible_annotations_length, TRAPS); int skip_annotation(u1* buffer, int limit, int index); int skip_annotation_value(u1* buffer, int limit, int index); - void parse_annotations(ClassLoaderData* loader_data, - u1* buffer, int limit, constantPoolHandle cp, + void parse_annotations(u1* buffer, int limit, /* Results (currently, only one result is supported): */ AnnotationCollector* result, TRAPS); @@ -267,8 +290,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { int* nonstatic_oop_offsets, unsigned int* nonstatic_oop_counts); void set_precomputed_flags(instanceKlassHandle k); - Array<Klass*>* compute_transitive_interfaces(ClassLoaderData* loader_data, - instanceKlassHandle super, + Array<Klass*>* compute_transitive_interfaces(instanceKlassHandle super, Array<Klass*>* local_ifs, TRAPS); // Format checker methods @@ -318,7 +340,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { bool is_supported_version(u2 major, u2 minor); bool has_illegal_visibility(jint flags); - void verify_constantvalue(int constantvalue_index, int signature_index, constantPoolHandle cp, TRAPS); + void verify_constantvalue(int constantvalue_index, int signature_index, TRAPS); void verify_legal_utf8(const unsigned char* buffer, int length, TRAPS); void verify_legal_class_name(Symbol* name, TRAPS); void verify_legal_field_name(Symbol* name, TRAPS); @@ -359,10 +381,17 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { // In older versions of the VM, Klass*s cannot sneak into early phases of // constant pool construction, but in later versions they can. // %%% Let's phase out the old is_klass_reference. - bool is_klass_reference(constantPoolHandle cp, int index) { - return (EnableInvokeDynamic - ? cp->tag_at(index).is_klass_or_reference() - : cp->tag_at(index).is_klass_reference()); + bool valid_klass_reference_at(int index) { + return _cp->is_within_bounds(index) && + (EnableInvokeDynamic + ? _cp->tag_at(index).is_klass_or_reference() + : _cp->tag_at(index).is_klass_reference()); + } + + // Checks that the cpool index is in range and is a utf8 + bool valid_symbol_at(int cpool_index) { + return (_cp->is_within_bounds(cpool_index) && + _cp->tag_at(cpool_index).is_utf8()); } void copy_localvariable_table(ConstMethod* cm, int lvt_cnt, @@ -373,8 +402,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { u2** localvariable_type_table_start, TRAPS); - void copy_method_annotations(ClassLoaderData* loader_data, - ConstMethod* cm, + void copy_method_annotations(ConstMethod* cm, u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, @@ -391,9 +419,15 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { int annotation_default_length, TRAPS); + // lays out fields in class and returns the total oopmap count + void layout_fields(Handle class_loader, FieldAllocationCount* fac, + ClassAnnotationCollector* parsed_annotations, + FieldLayoutInfo* info, TRAPS); + public: // Constructor ClassFileParser(ClassFileStream* st) { set_stream(st); } + ~ClassFileParser(); // Parse .class file and return new Klass*. The Klass* is not hooked up // to the system dictionary or any other structures, so a .class file can diff --git a/hotspot/src/share/vm/oops/constMethod.cpp b/hotspot/src/share/vm/oops/constMethod.cpp index dfee4244920..98a29a2e1dc 100644 --- a/hotspot/src/share/vm/oops/constMethod.cpp +++ b/hotspot/src/share/vm/oops/constMethod.cpp @@ -67,6 +67,12 @@ ConstMethod::ConstMethod(int byte_code_size, set_size_of_parameters(0); } +// Accessor that copies to metadata. +void ConstMethod::copy_stackmap_data(ClassLoaderData* loader_data, + u1* sd, int length, TRAPS) { + _stackmap_data = MetadataFactory::new_array<u1>(loader_data, length, CHECK); + memcpy((void*)_stackmap_data->adr_at(0), (void*)sd, length); +} // Deallocate metadata fields associated with ConstMethod* void ConstMethod::deallocate_contents(ClassLoaderData* loader_data) { diff --git a/hotspot/src/share/vm/oops/constMethod.hpp b/hotspot/src/share/vm/oops/constMethod.hpp index 21fa344bc9d..0c4212564b0 100644 --- a/hotspot/src/share/vm/oops/constMethod.hpp +++ b/hotspot/src/share/vm/oops/constMethod.hpp @@ -280,6 +280,7 @@ public: // stackmap table data Array<u1>* stackmap_data() const { return _stackmap_data; } void set_stackmap_data(Array<u1>* sd) { _stackmap_data = sd; } + void copy_stackmap_data(ClassLoaderData* loader_data, u1* sd, int length, TRAPS); bool has_stackmap_table() const { return _stackmap_data != NULL; } void init_fingerprint() { diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 89cf23a35c8..e296c501ccb 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -165,7 +165,8 @@ HS_DTRACE_PROBE_DECL5(hotspot, class__initialization__end, volatile int InstanceKlass::_total_instanceKlass_count = 0; -Klass* InstanceKlass::allocate_instance_klass(ClassLoaderData* loader_data, +InstanceKlass* InstanceKlass::allocate_instance_klass( + ClassLoaderData* loader_data, int vtable_len, int itable_len, int static_field_size, @@ -207,10 +208,35 @@ Klass* InstanceKlass::allocate_instance_klass(ClassLoaderData* loader_data, access_flags, is_anonymous); } + // Check for pending exception before adding to the loader data and incrementing + // class count. Can get OOM here. + if (HAS_PENDING_EXCEPTION) { + return NULL; + } + + // Add all classes to our internal class loader list here, + // including classes in the bootstrap (NULL) class loader. + loader_data->add_class(ik); + Atomic::inc(&_total_instanceKlass_count); return ik; } + +// copy method ordering from resource area to Metaspace +void InstanceKlass::copy_method_ordering(intArray* m, TRAPS) { + if (m != NULL) { + // allocate a new array and copy contents (memcpy?) + _method_ordering = MetadataFactory::new_array<int>(class_loader_data(), m->length(), CHECK); + for (int i = 0; i < m->length(); i++) { + _method_ordering->at_put(i, m->at(i)); + } + } else { + _method_ordering = Universe::the_empty_int_array(); + } +} + + InstanceKlass::InstanceKlass(int vtable_len, int itable_len, int static_field_size, @@ -223,9 +249,6 @@ InstanceKlass::InstanceKlass(int vtable_len, int iksize = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size, access_flags.is_interface(), is_anonymous); - // The sizes of these these three variables are used for determining the - // size of the instanceKlassOop. It is critical that these are set to the right - // sizes before the first GC, i.e., when we allocate the mirror. set_vtable_length(vtable_len); set_itable_length(itable_len); set_static_field_size(static_field_size); @@ -288,12 +311,51 @@ InstanceKlass::InstanceKlass(int vtable_len, } +void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data, + Array<Method*>* methods) { + if (methods != NULL && methods != Universe::the_empty_method_array()) { + for (int i = 0; i < methods->length(); i++) { + Method* method = methods->at(i); + if (method == NULL) continue; // maybe null if error processing + // Only want to delete methods that are not executing for RedefineClasses. + // The previous version will point to them so they're not totally dangling + assert (!method->on_stack(), "shouldn't be called with methods on stack"); + MetadataFactory::free_metadata(loader_data, method); + } + MetadataFactory::free_array<Method*>(loader_data, methods); + } +} + +void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data, + Klass* super_klass, + Array<Klass*>* local_interfaces, + Array<Klass*>* transitive_interfaces) { + // Only deallocate transitive interfaces if not empty, same as super class + // or same as local interfaces. See code in parseClassFile. + Array<Klass*>* ti = transitive_interfaces; + if (ti != Universe::the_empty_klass_array() && ti != local_interfaces) { + // check that the interfaces don't come from super class + Array<Klass*>* sti = (super_klass == NULL) ? NULL : + InstanceKlass::cast(super_klass)->transitive_interfaces(); + if (ti != sti) { + MetadataFactory::free_array<Klass*>(loader_data, ti); + } + } + + // local interfaces can be empty + if (local_interfaces != Universe::the_empty_klass_array()) { + MetadataFactory::free_array<Klass*>(loader_data, local_interfaces); + } +} + // This function deallocates the metadata and C heap pointers that the // InstanceKlass points to. void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // Orphan the mirror first, CMS thinks it's still live. - java_lang_Class::set_klass(java_mirror(), NULL); + if (java_mirror() != NULL) { + java_lang_Class::set_klass(java_mirror(), NULL); + } // Need to take this class off the class loader data list. loader_data->remove_class(this); @@ -308,17 +370,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // reference counting symbol names. release_C_heap_structures(); - Array<Method*>* ms = methods(); - if (ms != Universe::the_empty_method_array()) { - for (int i = 0; i <= methods()->length() -1 ; i++) { - Method* method = methods()->at(i); - // Only want to delete methods that are not executing for RedefineClasses. - // The previous version will point to them so they're not totally dangling - assert (!method->on_stack(), "shouldn't be called with methods on stack"); - MetadataFactory::free_metadata(loader_data, method); - } - MetadataFactory::free_array<Method*>(loader_data, methods()); - } + deallocate_methods(loader_data, methods()); set_methods(NULL); if (method_ordering() != Universe::the_empty_int_array()) { @@ -335,24 +387,8 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { } set_secondary_supers(NULL); - // Only deallocate transitive interfaces if not empty, same as super class - // or same as local interfaces. See code in parseClassFile. - Array<Klass*>* ti = transitive_interfaces(); - if (ti != Universe::the_empty_klass_array() && ti != local_interfaces()) { - // check that the interfaces don't come from super class - Array<Klass*>* sti = (super() == NULL) ? NULL : - InstanceKlass::cast(super())->transitive_interfaces(); - if (ti != sti) { - MetadataFactory::free_array<Klass*>(loader_data, ti); - } - } + deallocate_interfaces(loader_data, super(), local_interfaces(), transitive_interfaces()); set_transitive_interfaces(NULL); - - // local interfaces can be empty - Array<Klass*>* li = local_interfaces(); - if (li != Universe::the_empty_klass_array()) { - MetadataFactory::free_array<Klass*>(loader_data, li); - } set_local_interfaces(NULL); MetadataFactory::free_array<jushort>(loader_data, fields()); @@ -360,9 +396,11 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // If a method from a redefined class is using this constant pool, don't // delete it, yet. The new class's previous version will point to this. - assert (!constants()->on_stack(), "shouldn't be called if anything is onstack"); - MetadataFactory::free_metadata(loader_data, constants()); - set_constants(NULL); + if (constants() != NULL) { + assert (!constants()->on_stack(), "shouldn't be called if anything is onstack"); + MetadataFactory::free_metadata(loader_data, constants()); + set_constants(NULL); + } if (inner_classes() != Universe::the_empty_short_array()) { MetadataFactory::free_array<jushort>(loader_data, inner_classes()); diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index c4dffdcb602..9d94b2436d9 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -147,7 +147,8 @@ class InstanceKlass: public Klass { AccessFlags access_flags, bool is_anonymous); public: - static Klass* allocate_instance_klass(ClassLoaderData* loader_data, + static InstanceKlass* allocate_instance_klass( + ClassLoaderData* loader_data, int vtable_len, int itable_len, int static_field_size, @@ -266,7 +267,6 @@ class InstanceKlass: public Klass { u1 _init_state; // state of class u1 _reference_type; // reference type - JvmtiCachedClassFieldMap* _jvmti_cached_class_field_map; // JVMTI: used during heap iteration NOT_PRODUCT(int _verify_count;) // to avoid redundant verifies @@ -358,16 +358,19 @@ class InstanceKlass: public Klass { // method ordering Array<int>* method_ordering() const { return _method_ordering; } void set_method_ordering(Array<int>* m) { _method_ordering = m; } + void copy_method_ordering(intArray* m, TRAPS); // interfaces Array<Klass*>* local_interfaces() const { return _local_interfaces; } void set_local_interfaces(Array<Klass*>* a) { guarantee(_local_interfaces == NULL || a == NULL, "Just checking"); _local_interfaces = a; } + Array<Klass*>* transitive_interfaces() const { return _transitive_interfaces; } void set_transitive_interfaces(Array<Klass*>* a) { guarantee(_transitive_interfaces == NULL || a == NULL, "Just checking"); - _transitive_interfaces = a; } + _transitive_interfaces = a; + } private: friend class fieldDescriptor; @@ -383,10 +386,9 @@ class InstanceKlass: public Klass { int java_fields_count() const { return (int)_java_fields_count; } Array<u2>* fields() const { return _fields; } - void set_fields(Array<u2>* f, u2 java_fields_count) { guarantee(_fields == NULL || f == NULL, "Just checking"); - _fields = f; + _fields = f; _java_fields_count = java_fields_count; } @@ -916,8 +918,15 @@ class InstanceKlass: public Klass { void clean_method_data(BoolObjectClosure* is_alive); // Explicit metaspace deallocation of fields - // For RedefineClasses, we need to deallocate instanceKlasses + // For RedefineClasses and class file parsing errors, we need to deallocate + // instanceKlasses and the metadata they point to. void deallocate_contents(ClassLoaderData* loader_data); + static void deallocate_methods(ClassLoaderData* loader_data, + Array<Method*>* methods); + void static deallocate_interfaces(ClassLoaderData* loader_data, + Klass* super_klass, + Array<Klass*>* local_interfaces, + Array<Klass*>* transitive_interfaces); // The constant pool is on stack if any of the methods are executing or // referenced by handles. From 46a623ec88c0bf281016811e35d2c81c907c8272 Mon Sep 17 00:00:00 2001 From: Morris Meyer <morris@openjdk.org> Date: Thu, 14 Mar 2013 07:44:18 -0700 Subject: [PATCH 172/180] 8008560: [parfait] Null pointer deference in hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Add null pointer check in signal handler Reviewed-by: kvn --- hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp index 9eabc200bb8..aa36599ea2a 100644 --- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp +++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp @@ -516,7 +516,7 @@ JVM_handle_bsd_signal(int sig, // here if the underlying file has been truncated. // Do not crash the VM in such a case. CodeBlob* cb = CodeCache::find_blob_unsafe(pc); - nmethod* nm = cb->is_nmethod() ? (nmethod*)cb : NULL; + nmethod* nm = (cb != NULL && cb->is_nmethod()) ? (nmethod*)cb : NULL; if (nm != NULL && nm->has_unsafe_access()) { stub = StubRoutines::handler_for_unsafe_access(); } From 7866abdf81234b31596790493ec5545727ae994a Mon Sep 17 00:00:00 2001 From: David Katleman <katleman@openjdk.org> Date: Thu, 14 Mar 2013 15:00:05 -0700 Subject: [PATCH 173/180] Added tag jdk8-b81 for changeset 13e9af9186a2 --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index e869333243b..8376608abe9 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -202,3 +202,4 @@ b43aa5bd8ca5c8121336495382d35ecfa7a71536 jdk8-b74 fd1a5574cf68af24bfd52decc37ac6361afb278a jdk8-b78 91d35211e74464dca5edf9b66ab01d0d0d8cded7 jdk8-b79 907a926d3c96472f357617b48b6b968ea855c23c jdk8-b80 +145dbc56f931c134e837b675b9e6e7bf08902e93 jdk8-b81 From 4606c00f0dd4fb75ea0113b4fb41e3a597cf017a Mon Sep 17 00:00:00 2001 From: David Katleman <katleman@openjdk.org> Date: Thu, 14 Mar 2013 15:00:09 -0700 Subject: [PATCH 174/180] Added tag jdk8-b81 for changeset f2ef1e5c2955 --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index 7e7b0160fc2..edf54fe6b06 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -202,3 +202,4 @@ d4e68ce17795601017ac2f952baad7272942c36e jdk8-b75 27d6368ae8ba570c31c2f0e696d39c99fa2f4538 jdk8-b78 e41fb1aa0329767b2737303c994e38bede1baa07 jdk8-b79 5f3d4a6bdd027a1631d97e2dfff63fd5e46987a4 jdk8-b80 +2a00aeeb466b9dee22508f6261f63b70f9c696fe jdk8-b81 From 82f7d021b6394b1d01098d2e38ad2b8e5ad076de Mon Sep 17 00:00:00 2001 From: David Katleman <katleman@openjdk.org> Date: Thu, 14 Mar 2013 15:00:19 -0700 Subject: [PATCH 175/180] Added tag jdk8-b81 for changeset 25c319ff4cf4 --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 5bf8e9848bb..829f4cd65f4 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -322,3 +322,4 @@ d5e12e7d2f719144d84903d9151455661c47b476 jdk8-b78 df5396524152118535c36da5801d828b560d19a2 hs25-b21 4a198b201f3ce84433fa94a3ca65d061473e7c4c jdk8-b80 dd6350b4abc4a6c19c89dd982cc0e4f3d119885c hs25-b22 +65b797426a3bec6e91b64085a0cfb94adadb634a jdk8-b81 From 4e8c9ce3082e9d5d00d093a374d6c6ac32e18fd7 Mon Sep 17 00:00:00 2001 From: David Katleman <katleman@openjdk.org> Date: Thu, 14 Mar 2013 15:00:33 -0700 Subject: [PATCH 176/180] Added tag jdk8-b81 for changeset 86a86261de2b --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index fbd3f71e449..92fe10a1d9a 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -202,3 +202,4 @@ b2fc8e31cecc35b76188e821d4c5dc0e0b74ac24 jdk8-b77 00b7535d743f83eda763c10b3c9ea19ba4b67f55 jdk8-b78 c933505d75c2a0a671f06d6dac5d2237a9228d2d jdk8-b79 dfb40f066c6ce129822f0f5dc2ac89173808781a jdk8-b80 +c0f8022eba536dcdc8aae659005b33f3982b9368 jdk8-b81 From 943bd88ce1bf08fd45dcd8b82be21374f0e05e76 Mon Sep 17 00:00:00 2001 From: Alejandro Murillo <amurillo@openjdk.org> Date: Fri, 15 Mar 2013 11:18:40 -0700 Subject: [PATCH 177/180] Added tag hs25-b23 for changeset 57159db35c41 --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 829f4cd65f4..aa835932b92 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -323,3 +323,4 @@ df5396524152118535c36da5801d828b560d19a2 hs25-b21 4a198b201f3ce84433fa94a3ca65d061473e7c4c jdk8-b80 dd6350b4abc4a6c19c89dd982cc0e4f3d119885c hs25-b22 65b797426a3bec6e91b64085a0cfb94adadb634a jdk8-b81 +0631ebcc45f05c73b09a56c2586685af1f781c1d hs25-b23 From 35dc8be1bf33219b53f08a2a6e89d47c55d28a04 Mon Sep 17 00:00:00 2001 From: Omair Majid <omajid@openjdk.org> Date: Mon, 18 Mar 2013 10:46:49 -0400 Subject: [PATCH 178/180] 8010030: Allow configure to detect if EC implementation is present Reviewed-by: andrew, dholmes --- jdk/makefiles/CompileNativeLibraries.gmk | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/jdk/makefiles/CompileNativeLibraries.gmk b/jdk/makefiles/CompileNativeLibraries.gmk index 9df22fe8b6a..4c5d8dab855 100644 --- a/jdk/makefiles/CompileNativeLibraries.gmk +++ b/jdk/makefiles/CompileNativeLibraries.gmk @@ -2665,11 +2665,8 @@ BUILD_LIBRARIES += $(BUILD_LIBJ2PKCS11) ########################################################################################## -ifndef DISABLE_INTREE_EC -# -# TODO Set DISABLE_INTREE_EC in configure if src/share/native/sun/security/ec/impl -# is not present -# +ifeq ($(ENABLE_INTREE_EC),yes) + BUILD_LIBSUNEC_FLAGS:= -I$(JDK_TOPDIR)/src/share/native/sun/security/ec \ -I$(JDK_TOPDIR)/src/share/native/sun/security/ec/impl From 7b22402218b6eb377d3e07fc586ab3fedf988db8 Mon Sep 17 00:00:00 2001 From: Omair Majid <omajid@openjdk.org> Date: Mon, 18 Mar 2013 10:47:37 -0400 Subject: [PATCH 179/180] 8010030: Allow configure to detect if EC implementation is present Reviewed-by: andrew, dholmes --- common/autoconf/configure.ac | 1 + common/autoconf/generated-configure.sh | 25 ++++++++++++++++++++++++- common/autoconf/jdk-options.m4 | 19 +++++++++++++++++++ common/autoconf/spec.gmk.in | 1 + 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac index da9996f74d9..5e632c4ecb8 100644 --- a/common/autoconf/configure.ac +++ b/common/autoconf/configure.ac @@ -194,6 +194,7 @@ BASIC_COMPILE_FIXPATH ############################################################################### JDKOPT_SETUP_BUILD_TWEAKS +JDKOPT_DETECT_INTREE_EC ############################################################################### # diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index bb61656ff39..85a453c9d55 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -612,6 +612,7 @@ SJAVAC_SERVER_JAVA JOBS MEMORY_SIZE NUM_CORES +ENABLE_INTREE_EC SALIB_NAME HOTSPOT_MAKE_ARGS FIXPATH @@ -3752,7 +3753,7 @@ fi #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1363150186 +DATE_WHEN_GENERATED=1363617192 ############################################################################### # @@ -10784,6 +10785,12 @@ else fi +############################################################################### +# +# Enable or disable the elliptic curve crypto implementation +# + + ############################################################################### # # Compress jars @@ -31694,6 +31701,22 @@ fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if elliptic curve crypto implementation is present" >&5 +$as_echo_n "checking if elliptic curve crypto implementation is present... " >&6; } + +if test -d "${SRC_ROOT}/jdk/src/share/native/sun/security/ec/impl"; then + ENABLE_INTREE_EC=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + ENABLE_INTREE_EC=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + ############################################################################### # # Configure parts of the build that only affect the build performance, diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 index 48eb3f85c0e..d3d55e52952 100644 --- a/common/autoconf/jdk-options.m4 +++ b/common/autoconf/jdk-options.m4 @@ -364,6 +364,25 @@ else fi AC_SUBST(UNLIMITED_CRYPTO) +############################################################################### +# +# Enable or disable the elliptic curve crypto implementation +# +AC_DEFUN_ONCE([JDKOPT_DETECT_INTREE_EC], +[ +AC_MSG_CHECKING([if elliptic curve crypto implementation is present]) + +if test -d "${SRC_ROOT}/jdk/src/share/native/sun/security/ec/impl"; then + ENABLE_INTREE_EC=yes + AC_MSG_RESULT([yes]) +else + ENABLE_INTREE_EC=no + AC_MSG_RESULT([no]) +fi + +AC_SUBST(ENABLE_INTREE_EC) +]) + ############################################################################### # # Compress jars diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 92c6d9cb98e..bfba636a7b1 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -539,6 +539,7 @@ endif # Build setup ENABLE_JFR=@ENABLE_JFR@ +ENABLE_INTREE_EC=@ENABLE_INTREE_EC@ USE_EXTERNAL_LIBJPEG:=@USE_EXTERNAL_LIBJPEG@ USE_EXTERNAL_LIBGIF:=@USE_EXTERNAL_LIBGIF@ USE_EXTERNAL_LIBZ:=@USE_EXTERNAL_LIBZ@ From 2e4abcea23a6303795642a1cbf42653db1b97779 Mon Sep 17 00:00:00 2001 From: Omair Majid <omajid@openjdk.org> Date: Tue, 19 Mar 2013 11:25:05 -0400 Subject: [PATCH 180/180] 8010277: Configure doesn't fail when Xrender.h is missing Reviewed-by: andrew --- common/autoconf/generated-configure.sh | 4 ++-- common/autoconf/libraries.m4 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 85a453c9d55..4d9ec980421 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -3753,7 +3753,7 @@ fi #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1363617192 +DATE_WHEN_GENERATED=1363706268 ############################################################################### # @@ -29830,7 +29830,7 @@ if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : _ACEOF X11_A_OK=yes else - X11_A_OK=no + X11_A_OK=no; break fi done diff --git a/common/autoconf/libraries.m4 b/common/autoconf/libraries.m4 index 91b0a846e5f..6cc9d634b60 100644 --- a/common/autoconf/libraries.m4 +++ b/common/autoconf/libraries.m4 @@ -182,7 +182,7 @@ CFLAGS="$CFLAGS $X_CFLAGS" # Need to include Xlib.h and Xutil.h to avoid "present but cannot be compiled" warnings on Solaris 10 AC_CHECK_HEADERS([X11/extensions/shape.h X11/extensions/Xrender.h X11/extensions/XTest.h], [X11_A_OK=yes], - [X11_A_OK=no], + [X11_A_OK=no; break], [ # include <X11/Xlib.h> # include <X11/Xutil.h> ])