From db7a00335ad67a41bee9e201078a18a2ecc257f1 Mon Sep 17 00:00:00 2001 From: "J. Duke" Date: Sat, 1 Dec 2007 00:00:00 +0000 Subject: [PATCH 001/311] Initial load --- nashorn/.hgignore | 4 ++++ nashorn/.jcheck/conf | 1 + 2 files changed, 5 insertions(+) create mode 100644 nashorn/.hgignore create mode 100644 nashorn/.jcheck/conf diff --git a/nashorn/.hgignore b/nashorn/.hgignore new file mode 100644 index 00000000000..83cef213d48 --- /dev/null +++ b/nashorn/.hgignore @@ -0,0 +1,4 @@ +^build/ +^dist/ +/nbproject/private/ +^.hgtip diff --git a/nashorn/.jcheck/conf b/nashorn/.jcheck/conf new file mode 100644 index 00000000000..6d0dbe48e36 --- /dev/null +++ b/nashorn/.jcheck/conf @@ -0,0 +1 @@ +project=jdk8 From 69a6be0305772fbcba9bf0798e0f61445bf42083 Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Fri, 12 Oct 2012 15:51:44 +0400 Subject: [PATCH 002/311] 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 003/311] 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 004/311] 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 005/311] 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 006/311] 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 007/311] 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 008/311] 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 009/311] 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 010/311] 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 011/311] 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 012/311] 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 013/311] 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 014/311] 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 015/311] 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 016/311] 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 017/311] 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 018/311] 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 019/311] 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 020/311] 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 021/311] 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 022/311] 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 023/311] 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 024/311] 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 025/311] 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 026/311] 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 027/311] 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 028/311] 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 029/311] 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 030/311] 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 031/311] 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 032/311] 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 033/311] 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 034/311] 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 035/311] 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 036/311] 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 037/311] 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 038/311] 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 958099576a0d2161a18d59eb679eb1e2dd7aaa5c Mon Sep 17 00:00:00 2001 From: John Coomes Date: Thu, 20 Dec 2012 14:16:21 -0800 Subject: [PATCH 039/311] 8005364: initial hg tags for nashorn repo Reviewed-by: amurillo --- nashorn/.hgtags | 193 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 nashorn/.hgtags diff --git a/nashorn/.hgtags b/nashorn/.hgtags new file mode 100644 index 00000000000..4eb67ac90af --- /dev/null +++ b/nashorn/.hgtags @@ -0,0 +1,193 @@ +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b24 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b25 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b26 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b27 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b28 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b29 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b30 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b31 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b32 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b33 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b34 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b35 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b36 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b37 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b38 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b39 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b40 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b41 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b42 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b43 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b44 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b45 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b46 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b47 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b48 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b49 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b50 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b51 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b52 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b53 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b54 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b55 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b56 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b57 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b58 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b59 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b60 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b61 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b62 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b63 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b64 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b65 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b66 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b67 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b68 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b69 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b70 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b71 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b72 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b73 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b74 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b75 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b76 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b77 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b78 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b79 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b80 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b81 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b82 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b83 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b84 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b85 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b86 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b87 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b88 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b89 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b90 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b91 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b92 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b93 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b94 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b95 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b96 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b97 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b98 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b99 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b100 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b101 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b102 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b103 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b104 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b105 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b106 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b107 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b108 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b109 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b110 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b111 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b112 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b113 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b114 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b115 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b116 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b117 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b118 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b119 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b120 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b121 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b122 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b123 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b124 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b125 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b126 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b127 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b128 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b129 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b130 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b131 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b132 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b133 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b134 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b135 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b136 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b137 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b138 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b139 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b140 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b141 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b142 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b143 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b144 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b145 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b146 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk7-b147 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b01 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b02 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b03 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b04 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b05 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b06 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b07 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b08 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b09 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b10 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b11 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b12 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b13 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b14 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b15 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b17 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b16 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b18 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b19 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b20 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b21 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b22 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b23 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b24 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b25 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b26 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b27 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b28 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b29 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b30 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b31 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b32 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b33 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b34 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b35 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b36 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b37 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b38 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b39 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b40 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b41 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b42 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b43 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b44 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b45 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b46 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b47 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b48 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b49 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b50 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b51 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b52 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b53 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b54 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b55 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b56 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b57 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b58 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b59 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b60 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b61 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b62 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b63 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b64 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b65 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b66 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b67 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b68 +b8a1b238c77c7c00024daaa2cb7d10838e017b5f jdk8-b69 From 98762d6ee02e40111558f0e8502ad35f64d0fb22 Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Fri, 21 Dec 2012 16:36:24 -0400 Subject: [PATCH 040/311] 8005403: Open-source Nashorn Co-authored-by: Akhil Arora Co-authored-by: Andreas Woess Co-authored-by: Attila Szegedi Co-authored-by: Hannes Wallnoefer Co-authored-by: Henry Jen Co-authored-by: Marcus Lagergren Co-authored-by: Pavel Semenov Co-authored-by: Pavel Stepanov Co-authored-by: Petr Hejl Co-authored-by: Petr Pisl Co-authored-by: Sundararajan Athijegannathan Reviewed-by: attila, hannesw, lagergren, sundar --- nashorn/.hgignore | 23 +- nashorn/ASSEMBLY_EXCEPTION | 27 + nashorn/LICENSE | 347 + nashorn/README | 147 + nashorn/RELEASE_README | 20 + nashorn/THIRD_PARTY_README | 69 + nashorn/bin/checkintest.sh | 266 + nashorn/bin/fixorphantests.sh | 52 + nashorn/bin/fixwhitespace.sh | 30 + nashorn/bin/jjs | 29 + nashorn/bin/jjs.bat | 27 + nashorn/bin/jjssecure | 29 + nashorn/bin/jjssecure.bat | 27 + nashorn/bin/nashorn | 29 + nashorn/bin/nashorn.bat | 27 + nashorn/bin/rm-non-tracked.sh | 24 + nashorn/bin/verbose_octane.bat | 59 + nashorn/bin/verbose_octane.sh | 58 + nashorn/buildtools/nasgen/README | 34 + nashorn/buildtools/nasgen/build.xml | 60 + nashorn/buildtools/nasgen/nasgen.iml | 39 + nashorn/buildtools/nasgen/project.properties | 52 + .../nasgen/src/META-INF/MANIFEST.MF | 4 + .../internal/tools/nasgen/ClassGenerator.java | 334 + .../tools/nasgen/ConstructorGenerator.java | 276 + .../nashorn/internal/tools/nasgen/Main.java | 181 + .../internal/tools/nasgen/MemberInfo.java | 377 + .../tools/nasgen/MethodGenerator.java | 426 + .../internal/tools/nasgen/NullVisitor.java | 88 + .../tools/nasgen/PrototypeGenerator.java | 184 + .../tools/nasgen/ScriptClassInfo.java | 237 + .../nasgen/ScriptClassInfoCollector.java | 331 + .../tools/nasgen/ScriptClassInstrumentor.java | 309 + .../tools/nasgen/StringConstants.java | 113 + nashorn/docs/DEVELOPER_README | 445 + nashorn/docs/genshelldoc.js | 90 + nashorn/make/Makefile | 224 + nashorn/make/build-benchmark.xml | 348 + nashorn/make/build-nasgen.xml | 86 + nashorn/make/build.xml | 355 + nashorn/make/nbproject/ide-file-targets.xml | 59 + nashorn/make/nbproject/ide-targets.xml | 41 + nashorn/make/nbproject/jdk.xml | 179 + nashorn/make/nbproject/nbjdk.properties | 24 + nashorn/make/nbproject/nbjdk.xml | 48 + nashorn/make/nbproject/project.xml | 177 + nashorn/make/project.properties | 223 + nashorn/samples/counters.js | 39 + nashorn/samples/letter.js | 49 + nashorn/samples/parser.js | 43 + nashorn/samples/shell.js | 78 + nashorn/samples/test.js | 32 + nashorn/samples/uniq.js | 55 + nashorn/src/META-INF/MANIFEST.MF | 5 + .../services/javax.script.ScriptEngineFactory | 25 + .../api/scripting/NashornException.java | 121 + .../api/scripting/NashornScriptEngine.java | 521 + .../scripting/NashornScriptEngineFactory.java | 179 + .../api/scripting/ScriptObjectMirror.java | 323 + .../nashorn/api/scripting/package-info.java | 38 + .../nashorn/api/scripting/resources/engine.js | 58 + .../internal/codegen/AccessSpecializer.java | 428 + .../internal/codegen/BranchOptimizer.java | 199 + .../internal/codegen/ClassEmitter.java | 620 + .../internal/codegen/CodeGenerator.java | 3266 ++ .../nashorn/internal/codegen/CompileUnit.java | 95 + .../nashorn/internal/codegen/Compiler.java | 685 + .../internal/codegen/CompilerConstants.java | 687 + .../internal/codegen/ConstantData.java | 165 + .../jdk/nashorn/internal/codegen/Emitter.java | 49 + .../jdk/nashorn/internal/codegen/Frame.java | 196 + .../internal/codegen/FunctionSignature.java | 209 + .../jdk/nashorn/internal/codegen/Lower.java | 3057 ++ .../internal/codegen/MethodEmitter.java | 2349 ++ .../nashorn/internal/codegen/Namespace.java | 101 + .../internal/codegen/RuntimeCallSite.java | 701 + .../internal/codegen/SharedScopeCall.java | 192 + .../nashorn/internal/codegen/Splitter.java | 403 + .../nashorn/internal/codegen/Transform.java | 33 + .../nashorn/internal/codegen/WeighNodes.java | 308 + .../codegen/objects/FieldObjectCreator.java | 186 + .../objects/FunctionObjectCreator.java | 133 + .../internal/codegen/objects/MapCreator.java | 163 + .../codegen/objects/ObjectClassGenerator.java | 762 + .../codegen/objects/ObjectCreator.java | 175 + .../codegen/objects/ObjectMapCreator.java | 54 + .../internal/codegen/types/ArrayType.java | 107 + .../internal/codegen/types/BitwiseType.java | 44 + .../internal/codegen/types/BooleanType.java | 161 + .../codegen/types/BytecodeArrayOps.java | 78 + .../codegen/types/BytecodeBitwiseOps.java | 96 + .../codegen/types/BytecodeNumericOps.java | 93 + .../internal/codegen/types/BytecodeOps.java | 158 + .../internal/codegen/types/IntType.java | 260 + .../internal/codegen/types/LongType.java | 229 + .../internal/codegen/types/NumberType.java | 177 + .../internal/codegen/types/NumericType.java | 43 + .../internal/codegen/types/ObjectType.java | 174 + .../nashorn/internal/codegen/types/Type.java | 882 + .../jdk/nashorn/internal/ir/AccessNode.java | 166 + .../jdk/nashorn/internal/ir/Assignment.java | 63 + .../src/jdk/nashorn/internal/ir/BaseNode.java | 101 + .../jdk/nashorn/internal/ir/BinaryNode.java | 246 + .../src/jdk/nashorn/internal/ir/Block.java | 591 + .../jdk/nashorn/internal/ir/BreakNode.java | 97 + .../nashorn/internal/ir/BreakableNode.java | 68 + .../src/jdk/nashorn/internal/ir/CallNode.java | 271 + .../src/jdk/nashorn/internal/ir/CaseNode.java | 138 + .../jdk/nashorn/internal/ir/CatchNode.java | 161 + .../jdk/nashorn/internal/ir/ContinueNode.java | 90 + .../jdk/nashorn/internal/ir/DoWhileNode.java | 82 + .../jdk/nashorn/internal/ir/EmptyNode.java | 71 + .../jdk/nashorn/internal/ir/ExecuteNode.java | 108 + .../src/jdk/nashorn/internal/ir/ForNode.java | 213 + .../jdk/nashorn/internal/ir/FunctionCall.java | 39 + .../jdk/nashorn/internal/ir/FunctionNode.java | 1242 + .../jdk/nashorn/internal/ir/IdentNode.java | 221 + .../src/jdk/nashorn/internal/ir/IfNode.java | 131 + .../jdk/nashorn/internal/ir/IndexNode.java | 160 + .../jdk/nashorn/internal/ir/LabelNode.java | 155 + .../jdk/nashorn/internal/ir/LabeledNode.java | 124 + .../nashorn/internal/ir/LineNumberNode.java | 97 + .../jdk/nashorn/internal/ir/LiteralNode.java | 785 + .../src/jdk/nashorn/internal/ir/Location.java | 142 + nashorn/src/jdk/nashorn/internal/ir/Node.java | 432 + .../jdk/nashorn/internal/ir/ObjectNode.java | 135 + .../jdk/nashorn/internal/ir/PropertyKey.java | 39 + .../jdk/nashorn/internal/ir/PropertyNode.java | 190 + .../nashorn/internal/ir/ReferenceNode.java | 92 + .../jdk/nashorn/internal/ir/ReturnNode.java | 167 + .../jdk/nashorn/internal/ir/RuntimeNode.java | 395 + .../jdk/nashorn/internal/ir/SplitNode.java | 221 + .../jdk/nashorn/internal/ir/SwitchNode.java | 182 + .../src/jdk/nashorn/internal/ir/Symbol.java | 610 + .../jdk/nashorn/internal/ir/TernaryNode.java | 140 + .../jdk/nashorn/internal/ir/ThrowNode.java | 119 + .../src/jdk/nashorn/internal/ir/TryNode.java | 233 + .../jdk/nashorn/internal/ir/TypeOverride.java | 58 + .../jdk/nashorn/internal/ir/UnaryNode.java | 233 + .../src/jdk/nashorn/internal/ir/VarNode.java | 249 + .../jdk/nashorn/internal/ir/WhileNode.java | 164 + .../src/jdk/nashorn/internal/ir/WithNode.java | 124 + .../internal/ir/annotations/ChildNode.java | 42 + .../internal/ir/annotations/Ignore.java | 43 + .../internal/ir/annotations/ParentNode.java | 44 + .../internal/ir/annotations/Reference.java | 42 + .../nashorn/internal/ir/debug/ASTWriter.java | 244 + .../nashorn/internal/ir/debug/JSONWriter.java | 1012 + .../internal/ir/debug/PrintVisitor.java | 436 + .../ir/visitor/NodeOperatorVisitor.java | 1287 + .../internal/ir/visitor/NodeVisitor.java | 882 + .../objects/AccessorPropertyDescriptor.java | 210 + .../internal/objects/ArrayBufferView.java | 370 + .../objects/DataPropertyDescriptor.java | 197 + .../nashorn/internal/objects/DateParser.java | 705 + .../objects/GenericPropertyDescriptor.java | 169 + .../jdk/nashorn/internal/objects/Global.java | 1663 + .../internal/objects/NativeArguments.java | 625 + .../nashorn/internal/objects/NativeArray.java | 1281 + .../internal/objects/NativeArrayBuffer.java | 114 + .../internal/objects/NativeBoolean.java | 181 + .../nashorn/internal/objects/NativeDate.java | 1335 + .../nashorn/internal/objects/NativeDebug.java | 274 + .../nashorn/internal/objects/NativeError.java | 325 + .../internal/objects/NativeEvalError.java | 87 + .../internal/objects/NativeFloat32Array.java | 186 + .../internal/objects/NativeFloat64Array.java | 196 + .../internal/objects/NativeFunction.java | 252 + .../internal/objects/NativeInt16Array.java | 144 + .../internal/objects/NativeInt32Array.java | 148 + .../internal/objects/NativeInt8Array.java | 138 + .../internal/objects/NativeJSAdapter.java | 739 + .../nashorn/internal/objects/NativeJSON.java | 545 + .../nashorn/internal/objects/NativeJava.java | 385 + .../internal/objects/NativeJavaImporter.java | 151 + .../nashorn/internal/objects/NativeMath.java | 700 + .../internal/objects/NativeNumber.java | 388 + .../internal/objects/NativeObject.java | 412 + .../internal/objects/NativeRangeError.java | 86 + .../objects/NativeReferenceError.java | 86 + .../internal/objects/NativeRegExp.java | 772 + .../objects/NativeRegExpExecResult.java | 84 + .../objects/NativeStrictArguments.java | 147 + .../internal/objects/NativeString.java | 937 + .../internal/objects/NativeSyntaxError.java | 88 + .../internal/objects/NativeTypeError.java | 86 + .../internal/objects/NativeURIError.java | 85 + .../internal/objects/NativeUint16Array.java | 144 + .../internal/objects/NativeUint32Array.java | 162 + .../internal/objects/NativeUint8Array.java | 137 + .../objects/NativeUint8ClampedArray.java | 154 + .../internal/objects/PrototypeObject.java | 111 + .../internal/objects/ScriptFunctionImpl.java | 345 + .../objects/annotations/Attribute.java | 51 + .../objects/annotations/Constructor.java | 49 + .../objects/annotations/Function.java | 62 + .../internal/objects/annotations/Getter.java | 55 + .../objects/annotations/Property.java | 60 + .../objects/annotations/ScriptClass.java | 44 + .../internal/objects/annotations/Setter.java | 55 + .../annotations/SpecializedConstructor.java | 47 + .../annotations/SpecializedFunction.java | 46 + .../internal/objects/annotations/Where.java | 38 + .../internal/objects/package-info.java | 33 + .../internal/parser/AbstractParser.java | 458 + .../nashorn/internal/parser/JSONParser.java | 346 + .../jdk/nashorn/internal/parser/Lexer.java | 1647 + .../jdk/nashorn/internal/parser/Parser.java | 2981 ++ .../jdk/nashorn/internal/parser/RegExp.java | 180 + .../internal/parser/RegExpScanner.java | 1414 + .../jdk/nashorn/internal/parser/Scanner.java | 193 + .../jdk/nashorn/internal/parser/Token.java | 152 + .../nashorn/internal/parser/TokenKind.java | 50 + .../nashorn/internal/parser/TokenLookup.java | 222 + .../nashorn/internal/parser/TokenStream.java | 212 + .../nashorn/internal/parser/TokenType.java | 284 + .../internal/runtime/AccessorProperty.java | 353 + .../nashorn/internal/runtime/BitVector.java | 278 + .../internal/runtime/CodeInstaller.java | 47 + .../nashorn/internal/runtime/ConsString.java | 117 + .../jdk/nashorn/internal/runtime/Context.java | 872 + .../jdk/nashorn/internal/runtime/Debug.java | 120 + .../nashorn/internal/runtime/DebugLogger.java | 187 + .../runtime/DefaultPropertyAccess.java | 243 + .../nashorn/internal/runtime/ECMAErrors.java | 242 + .../internal/runtime/ECMAException.java | 326 + .../internal/runtime/ErrorManager.java | 236 + .../internal/runtime/FindProperty.java | 209 + .../internal/runtime/FunctionScope.java | 93 + .../internal/runtime/GlobalFunctions.java | 460 + .../internal/runtime/GlobalObject.java | 238 + .../nashorn/internal/runtime/JSErrorType.java | 46 + .../jdk/nashorn/internal/runtime/JSType.java | 928 + .../jdk/nashorn/internal/runtime/Logging.java | 151 + .../internal/runtime/NashornLoader.java | 138 + .../internal/runtime/NativeJavaPackage.java | 189 + .../internal/runtime/NumberToString.java | 786 + .../internal/runtime/ParserException.java | 138 + .../nashorn/internal/runtime/Property.java | 477 + .../internal/runtime/PropertyAccess.java | 365 + .../internal/runtime/PropertyDescriptor.java | 155 + .../internal/runtime/PropertyHashMap.java | 649 + .../internal/runtime/PropertyListener.java | 57 + .../runtime/PropertyListenerManager.java | 192 + .../nashorn/internal/runtime/PropertyMap.java | 919 + .../runtime/QuotedStringTokenizer.java | 156 + .../nashorn/internal/runtime/RegExpMatch.java | 80 + .../jdk/nashorn/internal/runtime/Scope.java | 55 + .../internal/runtime/ScriptFunction.java | 1002 + .../internal/runtime/ScriptLoader.java | 73 + .../internal/runtime/ScriptObject.java | 3427 ++ .../internal/runtime/ScriptRuntime.java | 876 + .../internal/runtime/ScriptingFunctions.java | 114 + .../jdk/nashorn/internal/runtime/Source.java | 436 + .../internal/runtime/SpillProperty.java | 118 + .../internal/runtime/StructureLoader.java | 145 + .../nashorn/internal/runtime/URIUtils.java | 297 + .../nashorn/internal/runtime/Undefined.java | 205 + .../runtime/UserAccessorProperty.java | 163 + .../jdk/nashorn/internal/runtime/Version.java | 73 + .../nashorn/internal/runtime/WithObject.java | 274 + .../internal/runtime/arrays/ArrayData.java | 507 + .../internal/runtime/arrays/ArrayFilter.java | 194 + .../internal/runtime/arrays/ArrayIndex.java | 247 + .../runtime/arrays/ArrayIterator.java | 88 + .../runtime/arrays/ArrayLikeIterator.java | 156 + .../runtime/arrays/DeletedArrayFilter.java | 182 + .../arrays/DeletedRangeArrayFilter.java | 245 + .../arrays/EmptyArrayLikeIterator.java | 51 + .../runtime/arrays/FrozenArrayFilter.java | 78 + .../internal/runtime/arrays/IntArrayData.java | 274 + .../arrays/InvalidArrayIndexException.java | 66 + .../runtime/arrays/IteratorAction.java | 139 + .../runtime/arrays/LongArrayData.java | 236 + .../internal/runtime/arrays/MapIterator.java | 76 + .../runtime/arrays/NoTypeArrayData.java | 181 + .../runtime/arrays/NumberArrayData.java | 219 + .../runtime/arrays/ObjectArrayData.java | 195 + .../runtime/arrays/ReverseArrayIterator.java | 59 + .../runtime/arrays/ReverseMapIterator.java | 55 + .../runtime/arrays/SealedArrayFilter.java | 64 + .../runtime/arrays/SparseArrayData.java | 336 + .../runtime/arrays/UndefinedArrayFilter.java | 210 + .../internal/runtime/linker/Bootstrap.java | 208 + .../internal/runtime/linker/InvokeByName.java | 116 + .../runtime/linker/JSObjectLinker.java | 232 + .../runtime/linker/JavaAdapterFactory.java | 1061 + .../linker/JavaArgumentConverters.java | 302 + .../runtime/linker/LinkerCallSite.java | 540 + .../internal/runtime/linker/Lookup.java | 214 + .../internal/runtime/linker/Mangler.java | 140 + .../runtime/linker/MethodHandleFactory.java | 633 + .../linker/MethodHandleFunctionality.java | 305 + .../runtime/linker/NashornBottomLinker.java | 172 + .../linker/NashornCallSiteDescriptor.java | 287 + .../linker/NashornGuardedInvocation.java | 68 + .../runtime/linker/NashornGuards.java | 131 + .../runtime/linker/NashornLinker.java | 141 + .../linker/NashornPrimitiveLinker.java | 228 + .../runtime/linker/PrimitiveLookup.java | 108 + .../runtime/options/KeyValueOption.java | 93 + .../internal/runtime/options/Option.java | 61 + .../runtime/options/OptionTemplate.java | 367 + .../internal/runtime/options/Options.java | 657 + .../internal/runtime/options/ValueOption.java | 59 + .../runtime/resources/Messages.properties | 137 + .../runtime/resources/Options.properties | 301 + .../runtime/resources/mozilla_compat.js | 301 + .../internal/runtime/resources/parser.js | 63 + .../resources/version.properties-template | 27 + .../src/jdk/nashorn/internal/scripts/JO$.java | 62 + .../src/jdk/nashorn/internal/scripts/JS$.java | 33 + nashorn/src/jdk/nashorn/tools/Shell.java | 396 + .../nashorn/tools/resources/Shell.properties | 32 + .../src/jdk/nashorn/tools/resources/shell.js | 72 + nashorn/src/netscape/javascript/JSObject.java | 101 + nashorn/src/overview.html | 113 + nashorn/test/README | 78 + nashorn/test/examples/dual-fields-micro.js | 48 + nashorn/test/examples/innerbench.js | 60 + nashorn/test/examples/typechain.js | 46 + nashorn/test/lib/benchmark.js | 52 + nashorn/test/opt/add.js | 58 + nashorn/test/opt/add_constant.js | 45 + nashorn/test/opt/add_reuse_callsite.js | 48 + nashorn/test/opt/add_revert2.js | 46 + nashorn/test/opt/cascade_specialize.js | 40 + nashorn/test/script/assert.js | 63 + nashorn/test/script/basic/NASHORN-100.js | 39 + .../test/script/basic/NASHORN-100.js.EXPECTED | 3 + nashorn/test/script/basic/NASHORN-101.js | 58 + .../test/script/basic/NASHORN-101.js.EXPECTED | 9 + nashorn/test/script/basic/NASHORN-102.js | 43 + .../test/script/basic/NASHORN-102.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-103.js | 39 + nashorn/test/script/basic/NASHORN-104.js | 35 + .../test/script/basic/NASHORN-104.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-105.js | 50 + .../test/script/basic/NASHORN-105.js.EXPECTED | 18 + nashorn/test/script/basic/NASHORN-106.js | 39 + .../test/script/basic/NASHORN-106.js.EXPECTED | 9 + nashorn/test/script/basic/NASHORN-107.js | 33 + nashorn/test/script/basic/NASHORN-108.js | 32 + .../test/script/basic/NASHORN-108.js.EXPECTED | 3 + nashorn/test/script/basic/NASHORN-109.js | 43 + .../test/script/basic/NASHORN-109.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-11.js | 38 + .../test/script/basic/NASHORN-11.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-111.js | 38 + .../test/script/basic/NASHORN-111.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-113.js | 34 + .../test/script/basic/NASHORN-113.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-114.js | 45 + nashorn/test/script/basic/NASHORN-115.js | 48 + .../test/script/basic/NASHORN-115.js.EXPECTED | 5 + nashorn/test/script/basic/NASHORN-117.js | 160 + nashorn/test/script/basic/NASHORN-118.js | 43 + .../test/script/basic/NASHORN-118.js.EXPECTED | 3 + nashorn/test/script/basic/NASHORN-119.js | 37 + .../test/script/basic/NASHORN-119.js.EXPECTED | 3 + nashorn/test/script/basic/NASHORN-12.js | 145 + nashorn/test/script/basic/NASHORN-120.js | 59 + nashorn/test/script/basic/NASHORN-122.js | 36 + .../test/script/basic/NASHORN-122.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-126.js | 34 + .../test/script/basic/NASHORN-126.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-127.js | 39 + .../test/script/basic/NASHORN-127.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-130.js | 38 + nashorn/test/script/basic/NASHORN-132.js | 70 + .../test/script/basic/NASHORN-132.js.EXPECTED | 10 + nashorn/test/script/basic/NASHORN-133.js | 46 + .../test/script/basic/NASHORN-133.js.EXPECTED | 7 + nashorn/test/script/basic/NASHORN-135.js | 49 + nashorn/test/script/basic/NASHORN-136.js | 77 + .../test/script/basic/NASHORN-136.js.EXPECTED | 24 + nashorn/test/script/basic/NASHORN-14.js | 39 + .../test/script/basic/NASHORN-14.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-148.js | 83 + .../test/script/basic/NASHORN-148.js.EXPECTED | 20 + nashorn/test/script/basic/NASHORN-15.js | 46 + .../test/script/basic/NASHORN-15.js.EXPECTED | 10 + nashorn/test/script/basic/NASHORN-153.js | 35 + nashorn/test/script/basic/NASHORN-156.js | 38 + nashorn/test/script/basic/NASHORN-157.js | 38 + nashorn/test/script/basic/NASHORN-163.js | 41 + .../test/script/basic/NASHORN-163.js.EXPECTED | 8 + nashorn/test/script/basic/NASHORN-164.js | 37 + nashorn/test/script/basic/NASHORN-165.js | 35 + nashorn/test/script/basic/NASHORN-166.js | 46 + nashorn/test/script/basic/NASHORN-168.js | 54 + .../test/script/basic/NASHORN-168.js.EXPECTED | 16 + nashorn/test/script/basic/NASHORN-169.js | 33 + nashorn/test/script/basic/NASHORN-172.js | 55 + nashorn/test/script/basic/NASHORN-173.js | 72 + .../test/script/basic/NASHORN-173.js.EXPECTED | 247 + nashorn/test/script/basic/NASHORN-174.js | 47 + nashorn/test/script/basic/NASHORN-175.js | 31 + nashorn/test/script/basic/NASHORN-176.js | 40 + nashorn/test/script/basic/NASHORN-177.js | 37 + .../test/script/basic/NASHORN-177.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-178.js | 46 + .../test/script/basic/NASHORN-178.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-179.js | 41 + nashorn/test/script/basic/NASHORN-18.js | 41 + .../test/script/basic/NASHORN-18.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-181.js | 40 + nashorn/test/script/basic/NASHORN-182.js | 54 + nashorn/test/script/basic/NASHORN-183.js | 55 + nashorn/test/script/basic/NASHORN-184.js | 38 + .../test/script/basic/NASHORN-184.js.EXPECTED | 3 + nashorn/test/script/basic/NASHORN-185.js | 37 + .../test/script/basic/NASHORN-185.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-187.js | 48 + nashorn/test/script/basic/NASHORN-188.js | 66 + .../test/script/basic/NASHORN-188.js.EXPECTED | 208 + nashorn/test/script/basic/NASHORN-19.js | 279 + .../test/script/basic/NASHORN-19.js.EXPECTED | 177 + nashorn/test/script/basic/NASHORN-190.js | 78 + nashorn/test/script/basic/NASHORN-192.js | 71 + nashorn/test/script/basic/NASHORN-194.js | 48 + nashorn/test/script/basic/NASHORN-196.js | 39 + nashorn/test/script/basic/NASHORN-198.js | 39 + nashorn/test/script/basic/NASHORN-20.js | 33 + .../test/script/basic/NASHORN-20.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-201.js | 36 + nashorn/test/script/basic/NASHORN-202.js | 33 + nashorn/test/script/basic/NASHORN-203.js | 40 + nashorn/test/script/basic/NASHORN-204.js | 46 + nashorn/test/script/basic/NASHORN-205.js | 65 + nashorn/test/script/basic/NASHORN-206.js | 38 + nashorn/test/script/basic/NASHORN-207.js | 132 + nashorn/test/script/basic/NASHORN-207_2.js | 237 + nashorn/test/script/basic/NASHORN-208.js | 70 + .../test/script/basic/NASHORN-208.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-209.js | 42 + .../test/script/basic/NASHORN-209.js.EXPECTED | 6 + nashorn/test/script/basic/NASHORN-21.js | 47 + .../test/script/basic/NASHORN-21.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-211.js | 50 + nashorn/test/script/basic/NASHORN-212.js | 72 + nashorn/test/script/basic/NASHORN-213.js | 40 + nashorn/test/script/basic/NASHORN-215.js | 100 + .../test/script/basic/NASHORN-215.js.EXPECTED | 15 + nashorn/test/script/basic/NASHORN-216.js | 41 + nashorn/test/script/basic/NASHORN-217.js | 54 + .../test/script/basic/NASHORN-217.js.EXPECTED | 10 + nashorn/test/script/basic/NASHORN-219.js | 31 + .../test/script/basic/NASHORN-219.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-22.js | 42 + .../test/script/basic/NASHORN-22.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-221.js | 51 + nashorn/test/script/basic/NASHORN-222.js | 44 + nashorn/test/script/basic/NASHORN-223.js | 40 + nashorn/test/script/basic/NASHORN-225.js | 40 + nashorn/test/script/basic/NASHORN-226.js | 51 + nashorn/test/script/basic/NASHORN-227.js | 46 + nashorn/test/script/basic/NASHORN-228.js | 54 + nashorn/test/script/basic/NASHORN-229.js | 42 + .../test/script/basic/NASHORN-229_subtest.js | 41 + nashorn/test/script/basic/NASHORN-23.js | 46 + .../test/script/basic/NASHORN-23.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-232.js | 44 + nashorn/test/script/basic/NASHORN-234.js | 58 + nashorn/test/script/basic/NASHORN-235.js | 45 + nashorn/test/script/basic/NASHORN-236.js | 30 + nashorn/test/script/basic/NASHORN-237.js | 37 + nashorn/test/script/basic/NASHORN-239.js | 35 + nashorn/test/script/basic/NASHORN-24.js | 47 + .../test/script/basic/NASHORN-24.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-241.js | 59 + nashorn/test/script/basic/NASHORN-242.js | 40 + nashorn/test/script/basic/NASHORN-245.js | 46 + nashorn/test/script/basic/NASHORN-247.js | 55 + nashorn/test/script/basic/NASHORN-25.js | 48 + .../test/script/basic/NASHORN-25.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-251.js | 103 + nashorn/test/script/basic/NASHORN-252.js | 42 + nashorn/test/script/basic/NASHORN-253.js | 74 + nashorn/test/script/basic/NASHORN-256.js | 74 + nashorn/test/script/basic/NASHORN-258.js | 67 + .../test/script/basic/NASHORN-258.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-26.js | 53 + .../test/script/basic/NASHORN-26.js.EXPECTED | 6 + nashorn/test/script/basic/NASHORN-260.js | 54 + nashorn/test/script/basic/NASHORN-261.js | 85 + nashorn/test/script/basic/NASHORN-262.js | 40 + nashorn/test/script/basic/NASHORN-263.js | 59 + nashorn/test/script/basic/NASHORN-264.js | 47 + nashorn/test/script/basic/NASHORN-265.js | 46 + .../test/script/basic/NASHORN-265.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-266.js | 66 + nashorn/test/script/basic/NASHORN-269.js | 67 + nashorn/test/script/basic/NASHORN-27.js | 41 + .../test/script/basic/NASHORN-27.js.EXPECTED | 9 + nashorn/test/script/basic/NASHORN-270.js | 46 + nashorn/test/script/basic/NASHORN-271.js | 46 + nashorn/test/script/basic/NASHORN-275.js | 81 + nashorn/test/script/basic/NASHORN-276.js | 38 + nashorn/test/script/basic/NASHORN-277.js | 34 + nashorn/test/script/basic/NASHORN-278.js | 42 + nashorn/test/script/basic/NASHORN-28.js | 54 + .../test/script/basic/NASHORN-28.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-281.js | 54 + nashorn/test/script/basic/NASHORN-284.js | 48 + .../test/script/basic/NASHORN-284.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-285.js | 60 + .../test/script/basic/NASHORN-285.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-288.js | 56 + nashorn/test/script/basic/NASHORN-29.js | 42 + .../test/script/basic/NASHORN-29.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-293.js | 54 + .../test/script/basic/NASHORN-293.js.EXPECTED | 9 + nashorn/test/script/basic/NASHORN-294.js | 46 + nashorn/test/script/basic/NASHORN-296.js | 53 + nashorn/test/script/basic/NASHORN-297.js | 46 + nashorn/test/script/basic/NASHORN-30.js | 48 + .../test/script/basic/NASHORN-30.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-300.js | 43 + nashorn/test/script/basic/NASHORN-301.js | 35 + .../test/script/basic/NASHORN-301.js.EXPECTED | 35 + nashorn/test/script/basic/NASHORN-304.js | 52 + nashorn/test/script/basic/NASHORN-310.js | 57 + .../test/script/basic/NASHORN-310.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-318.js | 36 + .../test/script/basic/NASHORN-318.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-32.js | 71 + .../test/script/basic/NASHORN-32.js.EXPECTED | 12 + nashorn/test/script/basic/NASHORN-321.js | 43 + .../test/script/basic/NASHORN-321.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-323.js | 38 + .../test/script/basic/NASHORN-323.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-324.js | 47 + nashorn/test/script/basic/NASHORN-33.js | 45 + .../test/script/basic/NASHORN-33.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-331.js | 60 + .../test/script/basic/NASHORN-331.js.EXPECTED | 24 + nashorn/test/script/basic/NASHORN-337.js | 43 + .../test/script/basic/NASHORN-337.js.EXPECTED | 8 + nashorn/test/script/basic/NASHORN-34.js | 49 + .../test/script/basic/NASHORN-34.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-340.js | 44 + .../test/script/basic/NASHORN-340.js.EXPECTED | 6 + nashorn/test/script/basic/NASHORN-349.js | 48 + nashorn/test/script/basic/NASHORN-354.js | 41 + .../test/script/basic/NASHORN-354.js.EXPECTED | 3 + nashorn/test/script/basic/NASHORN-355.js | 42 + .../test/script/basic/NASHORN-355.js.EXPECTED | 3 + nashorn/test/script/basic/NASHORN-36.js | 48 + .../test/script/basic/NASHORN-36.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-365.js | 45 + nashorn/test/script/basic/NASHORN-366.js | 35 + .../test/script/basic/NASHORN-366.js.EXPECTED | 5 + nashorn/test/script/basic/NASHORN-368.js | 40 + .../test/script/basic/NASHORN-368.js.EXPECTED | 20 + nashorn/test/script/basic/NASHORN-37.js | 75 + .../test/script/basic/NASHORN-37.js.EXPECTED | 20 + nashorn/test/script/basic/NASHORN-375.js | 53 + nashorn/test/script/basic/NASHORN-376.js | 46 + nashorn/test/script/basic/NASHORN-377.js | 226 + .../test/script/basic/NASHORN-377.js.EXPECTED | 34 + nashorn/test/script/basic/NASHORN-378.js | 59 + nashorn/test/script/basic/NASHORN-38.js | 43 + .../test/script/basic/NASHORN-38.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-380.js | 37 + .../test/script/basic/NASHORN-380.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-381.js | 47 + nashorn/test/script/basic/NASHORN-382.js | 40 + nashorn/test/script/basic/NASHORN-383.js | 54 + nashorn/test/script/basic/NASHORN-384.js | 34 + .../test/script/basic/NASHORN-384.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-385.js | 69 + .../test/script/basic/NASHORN-385.js.EXPECTED | 6 + nashorn/test/script/basic/NASHORN-389.js | 40 + .../test/script/basic/NASHORN-389.js.EXPECTED | 5 + nashorn/test/script/basic/NASHORN-393.js | 37 + .../test/script/basic/NASHORN-393.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-394.js | 34 + .../test/script/basic/NASHORN-394.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-396.js | 47 + nashorn/test/script/basic/NASHORN-397.js | 48 + nashorn/test/script/basic/NASHORN-398.js | 72 + nashorn/test/script/basic/NASHORN-40.js | 41 + .../test/script/basic/NASHORN-40.js.EXPECTED | 6 + nashorn/test/script/basic/NASHORN-400.js | 66 + .../test/script/basic/NASHORN-400.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-401.js | 43 + .../test/script/basic/NASHORN-401.js.EXPECTED | 9 + nashorn/test/script/basic/NASHORN-402.js | 44 + .../test/script/basic/NASHORN-402.js.EXPECTED | 5 + nashorn/test/script/basic/NASHORN-404.js | 43 + nashorn/test/script/basic/NASHORN-405.js | 35 + .../test/script/basic/NASHORN-405.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-406.js | 83 + nashorn/test/script/basic/NASHORN-408.js | 38 + .../test/script/basic/NASHORN-408.js.EXPECTED | 5 + nashorn/test/script/basic/NASHORN-415.js | 35 + .../test/script/basic/NASHORN-415.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-416.js | 51 + nashorn/test/script/basic/NASHORN-417.js | 47 + nashorn/test/script/basic/NASHORN-418.js | 81 + nashorn/test/script/basic/NASHORN-420.js | 45 + nashorn/test/script/basic/NASHORN-421.js | 63 + nashorn/test/script/basic/NASHORN-423.js | 4030 +++ .../test/script/basic/NASHORN-423.js.EXPECTED | 4000 ++ nashorn/test/script/basic/NASHORN-423a.js | 2030 ++ nashorn/test/script/basic/NASHORN-424.js | 83 + .../test/script/basic/NASHORN-424.js.EXPECTED | 33 + nashorn/test/script/basic/NASHORN-425.js | 44 + .../test/script/basic/NASHORN-425.js.EXPECTED | 3 + nashorn/test/script/basic/NASHORN-426.js | 54 + nashorn/test/script/basic/NASHORN-427.js | 75 + nashorn/test/script/basic/NASHORN-428.js | 53 + nashorn/test/script/basic/NASHORN-429.js | 40 + nashorn/test/script/basic/NASHORN-432.js | 39 + nashorn/test/script/basic/NASHORN-433.js | 47 + nashorn/test/script/basic/NASHORN-434.js | 61 + nashorn/test/script/basic/NASHORN-435.js | 40 + nashorn/test/script/basic/NASHORN-437.js | 51 + nashorn/test/script/basic/NASHORN-44.js | 52 + .../test/script/basic/NASHORN-44.js.EXPECTED | 12 + nashorn/test/script/basic/NASHORN-441.js | 89 + .../test/script/basic/NASHORN-441.js.EXPECTED | 17 + nashorn/test/script/basic/NASHORN-442.js | 50 + nashorn/test/script/basic/NASHORN-443.js | 48 + nashorn/test/script/basic/NASHORN-444.js | 71 + .../test/script/basic/NASHORN-444.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-445.js | 56 + nashorn/test/script/basic/NASHORN-446.js | 45 + nashorn/test/script/basic/NASHORN-447.js | 46 + nashorn/test/script/basic/NASHORN-448.js | 44 + nashorn/test/script/basic/NASHORN-449.js | 53 + .../test/script/basic/NASHORN-449.js.EXPECTED | 0 nashorn/test/script/basic/NASHORN-45.js | 62 + .../test/script/basic/NASHORN-45.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-450.js | 47 + nashorn/test/script/basic/NASHORN-452.js | 79 + nashorn/test/script/basic/NASHORN-459.js | 67 + nashorn/test/script/basic/NASHORN-46.js | 45 + .../test/script/basic/NASHORN-46.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-462.js | 43 + nashorn/test/script/basic/NASHORN-463.js | 36 + nashorn/test/script/basic/NASHORN-468.js | 3035 ++ nashorn/test/script/basic/NASHORN-47.js | 46 + nashorn/test/script/basic/NASHORN-473.js | 42 + .../test/script/basic/NASHORN-473.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-474.js | 54 + .../test/script/basic/NASHORN-474.js.EXPECTED | 6 + nashorn/test/script/basic/NASHORN-478.js | 115 + nashorn/test/script/basic/NASHORN-48.js | 73 + .../test/script/basic/NASHORN-48.js.EXPECTED | 6 + nashorn/test/script/basic/NASHORN-481.js | 10035 ++++++ .../test/script/basic/NASHORN-481.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-482.js | 41 + nashorn/test/script/basic/NASHORN-484.js | 34 + .../test/script/basic/NASHORN-484.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-486.js | 81 + nashorn/test/script/basic/NASHORN-487.js | 43 + nashorn/test/script/basic/NASHORN-488.js | 48 + nashorn/test/script/basic/NASHORN-49.js | 63 + .../test/script/basic/NASHORN-49.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-490.js | 48 + nashorn/test/script/basic/NASHORN-494.js | 57 + nashorn/test/script/basic/NASHORN-497.js | 44 + nashorn/test/script/basic/NASHORN-498.js | 42 + nashorn/test/script/basic/NASHORN-499.js | 38 + nashorn/test/script/basic/NASHORN-50.js | 55 + .../test/script/basic/NASHORN-50.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-500.js | 66 + nashorn/test/script/basic/NASHORN-503.js | 52 + .../test/script/basic/NASHORN-503.js.EXPECTED | 5 + nashorn/test/script/basic/NASHORN-51.js | 62 + .../test/script/basic/NASHORN-51.js.EXPECTED | 24 + nashorn/test/script/basic/NASHORN-511.js | 55 + nashorn/test/script/basic/NASHORN-515.js | 145 + .../test/script/basic/NASHORN-515.js.EXPECTED | 6 + nashorn/test/script/basic/NASHORN-516.js | 49 + nashorn/test/script/basic/NASHORN-52.js | 38 + nashorn/test/script/basic/NASHORN-534.js | 30066 ++++++++++++++++ .../test/script/basic/NASHORN-534.js.EXPECTED | 13 + nashorn/test/script/basic/NASHORN-535.js | 46 + .../test/script/basic/NASHORN-535.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-544.js | 46 + nashorn/test/script/basic/NASHORN-55.js | 37 + nashorn/test/script/basic/NASHORN-554.js | 40 + .../test/script/basic/NASHORN-554.js.EXPECTED | 10 + nashorn/test/script/basic/NASHORN-556.js | 216 + .../test/script/basic/NASHORN-556.js.EXPECTED | 16 + nashorn/test/script/basic/NASHORN-56.js | 41 + .../test/script/basic/NASHORN-56.js.EXPECTED | 3 + nashorn/test/script/basic/NASHORN-562.js | 38 + nashorn/test/script/basic/NASHORN-565.js | 38 + .../test/script/basic/NASHORN-565.js.EXPECTED | 6 + nashorn/test/script/basic/NASHORN-575.js | 61 + .../test/script/basic/NASHORN-575.js.EXPECTED | 18 + nashorn/test/script/basic/NASHORN-58.js | 149 + .../test/script/basic/NASHORN-58.js.EXPECTED | 23 + nashorn/test/script/basic/NASHORN-59.js | 41 + .../test/script/basic/NASHORN-59.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-592.js | 120 + .../test/script/basic/NASHORN-592.js.EXPECTED | 44 + nashorn/test/script/basic/NASHORN-597.js | 83 + .../test/script/basic/NASHORN-597.js.EXPECTED | 8 + nashorn/test/script/basic/NASHORN-60.js | 36 + .../test/script/basic/NASHORN-60.js.EXPECTED | 3 + nashorn/test/script/basic/NASHORN-609.js | 43 + .../test/script/basic/NASHORN-609.js.EXPECTED | 5 + nashorn/test/script/basic/NASHORN-61.js | 35 + .../test/script/basic/NASHORN-61.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-62.js | 52 + .../test/script/basic/NASHORN-62.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-620.js | 35 + .../test/script/basic/NASHORN-620.js.EXPECTED | 5 + nashorn/test/script/basic/NASHORN-623.js | 54 + .../test/script/basic/NASHORN-623.js.EXPECTED | 3 + nashorn/test/script/basic/NASHORN-627.js | 155 + .../test/script/basic/NASHORN-627.js.EXPECTED | 1241 + nashorn/test/script/basic/NASHORN-63.js | 108 + .../test/script/basic/NASHORN-631.js.EXPECTED | 3917 ++ nashorn/test/script/basic/NASHORN-637.js | 49 + .../test/script/basic/NASHORN-637.js.EXPECTED | 8 + nashorn/test/script/basic/NASHORN-638.js | 72 + .../test/script/basic/NASHORN-638.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-639.js | 41 + nashorn/test/script/basic/NASHORN-64.js | 61 + nashorn/test/script/basic/NASHORN-642.js | 41 + .../test/script/basic/NASHORN-642.js.EXPECTED | 3 + nashorn/test/script/basic/NASHORN-646.js | 31 + nashorn/test/script/basic/NASHORN-653.js | 104 + nashorn/test/script/basic/NASHORN-658.js | 45 + nashorn/test/script/basic/NASHORN-659.js | 39 + nashorn/test/script/basic/NASHORN-66.js | 33 + .../test/script/basic/NASHORN-66.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-664.js | 50 + nashorn/test/script/basic/NASHORN-665.js | 55 + nashorn/test/script/basic/NASHORN-67.js | 44 + .../test/script/basic/NASHORN-67.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-678.js | 50 + nashorn/test/script/basic/NASHORN-68.js | 34 + .../test/script/basic/NASHORN-68.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-689.js | 114 + .../test/script/basic/NASHORN-689.js.EXPECTED | 50 + nashorn/test/script/basic/NASHORN-69.js | 45 + .../test/script/basic/NASHORN-69.js.EXPECTED | 15 + nashorn/test/script/basic/NASHORN-691.js | 57 + .../test/script/basic/NASHORN-691.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-694.js | 39 + .../test/script/basic/NASHORN-694.js.EXPECTED | 6 + nashorn/test/script/basic/NASHORN-697.js | 59 + nashorn/test/script/basic/NASHORN-703.js | 113 + .../test/script/basic/NASHORN-703.js.EXPECTED | 7 + nashorn/test/script/basic/NASHORN-703a.js | 122 + .../script/basic/NASHORN-703a.js.EXPECTED | 7 + nashorn/test/script/basic/NASHORN-705.js | 35 + nashorn/test/script/basic/NASHORN-71.js | 33 + .../test/script/basic/NASHORN-71.js.EXPECTED | 3 + nashorn/test/script/basic/NASHORN-710.js | 42 + nashorn/test/script/basic/NASHORN-711.js | 54 + .../test/script/basic/NASHORN-711.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-72.js | 54 + .../test/script/basic/NASHORN-72.js.EXPECTED | 8 + nashorn/test/script/basic/NASHORN-722.js | 42 + nashorn/test/script/basic/NASHORN-73.js | 122 + .../test/script/basic/NASHORN-73.js.EXPECTED | 12 + nashorn/test/script/basic/NASHORN-737.js | 33 + .../test/script/basic/NASHORN-737.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-74.js | 35 + .../test/script/basic/NASHORN-74.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-740.js | 33 + .../test/script/basic/NASHORN-740.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-75.js | 47 + .../test/script/basic/NASHORN-75.js.EXPECTED | 3 + nashorn/test/script/basic/NASHORN-758.js | 40 + nashorn/test/script/basic/NASHORN-759.js | 78 + .../test/script/basic/NASHORN-759.js.EXPECTED | 47 + nashorn/test/script/basic/NASHORN-760.js | 54 + nashorn/test/script/basic/NASHORN-768.js | 93 + nashorn/test/script/basic/NASHORN-778.js | 33 + nashorn/test/script/basic/NASHORN-78.js | 54 + nashorn/test/script/basic/NASHORN-79.js | 40 + .../test/script/basic/NASHORN-79.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-792.js | 72 + .../test/script/basic/NASHORN-792.js.EXPECTED | 7 + nashorn/test/script/basic/NASHORN-80.js | 35 + .../test/script/basic/NASHORN-80.js.EXPECTED | 5 + nashorn/test/script/basic/NASHORN-81.js | 77 + nashorn/test/script/basic/NASHORN-833.js | 40 + .../test/script/basic/NASHORN-833.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-85.js | 31 + .../test/script/basic/NASHORN-85.js.EXPECTED | 1 + nashorn/test/script/basic/NASHORN-86.js | 67 + nashorn/test/script/basic/NASHORN-87.js | 40 + nashorn/test/script/basic/NASHORN-89.js | 81 + nashorn/test/script/basic/NASHORN-90.js | 34 + .../test/script/basic/NASHORN-90.js.EXPECTED | 5 + nashorn/test/script/basic/NASHORN-91.js | 42 + .../test/script/basic/NASHORN-91.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-92.js | 42 + .../test/script/basic/NASHORN-92.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-93.js | 39 + nashorn/test/script/basic/NASHORN-95.js | 50 + .../test/script/basic/NASHORN-95.js.EXPECTED | 4 + nashorn/test/script/basic/NASHORN-96.js | 35 + .../test/script/basic/NASHORN-96.js.EXPECTED | 2 + nashorn/test/script/basic/NASHORN-97.js | 37 + nashorn/test/script/basic/NASHORN-98.js | 47 + .../test/script/basic/NASHORN-98.js.EXPECTED | 6 + nashorn/test/script/basic/NASHORN-99.js | 54 + nashorn/test/script/basic/addition.js | 84 + .../test/script/basic/addition.js.EXPECTED | 20 + nashorn/test/script/basic/allgettersetters.js | 133 + nashorn/test/script/basic/andor.js | 35 + nashorn/test/script/basic/andor.js.EXPECTED | 4 + nashorn/test/script/basic/anonrecur.js | 34 + .../test/script/basic/anonrecur.js.EXPECTED | 1 + nashorn/test/script/basic/applycall.js | 56 + .../test/script/basic/applycall.js.EXPECTED | 14 + nashorn/test/script/basic/args.js | 47 + nashorn/test/script/basic/args.js.EXPECTED | 3 + nashorn/test/script/basic/arity.js | 91 + nashorn/test/script/basic/arity.js.EXPECTED | 30 + nashorn/test/script/basic/arrayprotoclass.js | 32 + .../script/basic/arrayprotoclass.js.EXPECTED | 1 + nashorn/test/script/basic/arrays.js | 160 + nashorn/test/script/basic/arrays.js.EXPECTED | 51 + nashorn/test/script/basic/arrays2.js | 53 + nashorn/test/script/basic/arrays2.js.EXPECTED | 7 + nashorn/test/script/basic/arraysIntKey.js | 35 + .../script/basic/arraysIntKey.js.EXPECTED | 2 + nashorn/test/script/basic/arrayset.js | 39 + .../test/script/basic/arrayset.js.EXPECTED | 6 + nashorn/test/script/basic/arrayundefined.js | 36 + .../script/basic/arrayundefined.js.EXPECTED | 4 + nashorn/test/script/basic/assign.js | 50 + nashorn/test/script/basic/assign.js.EXPECTED | 13 + nashorn/test/script/basic/bitwise_and.js | 51 + .../test/script/basic/bitwise_and.js.EXPECTED | 18 + nashorn/test/script/basic/booleangetter.js | 43 + .../script/basic/booleangetter.js.EXPECTED | 1 + nashorn/test/script/basic/builtin.js | 73 + nashorn/test/script/basic/builtin.js.EXPECTED | 1 + nashorn/test/script/basic/builtin_assign.js | 36 + .../script/basic/builtin_assign.js.EXPECTED | 3 + nashorn/test/script/basic/builtinchain.js | 55 + .../script/basic/builtinchain.js.EXPECTED | 16 + nashorn/test/script/basic/calllink.js | 81 + .../test/script/basic/calllink.js.EXPECTED | 12 + nashorn/test/script/basic/closure.js | 38 + nashorn/test/script/basic/closure.js.EXPECTED | 8 + nashorn/test/script/basic/commandargs.js | 36 + .../test/script/basic/commandargs.js.EXPECTED | 2 + nashorn/test/script/basic/compile-octane.js | 30 + .../script/basic/compile-octane.js.EXPECTED | 12 + nashorn/test/script/basic/condassign.js | 36 + .../test/script/basic/condassign.js.EXPECTED | 2 + nashorn/test/script/basic/construct.js | 59 + .../test/script/basic/construct.js.EXPECTED | 15 + nashorn/test/script/basic/constructorname.js | 52 + .../script/basic/constructorname.js.EXPECTED | 7 + nashorn/test/script/basic/date.js | 101 + nashorn/test/script/basic/date.js.EXPECTED | 132 + nashorn/test/script/basic/dateparse.js | 55 + .../test/script/basic/dateparse.js.EXPECTED | 10 + nashorn/test/script/basic/decinc.js | 70 + nashorn/test/script/basic/decinc.js.EXPECTED | 12 + nashorn/test/script/basic/delete.js | 63 + nashorn/test/script/basic/delete.js.EXPECTED | 18 + nashorn/test/script/basic/delete2.js | 80 + nashorn/test/script/basic/delete2.js.EXPECTED | 25 + nashorn/test/script/basic/dotpropname.js | 40 + .../test/script/basic/dotpropname.js.EXPECTED | 2 + nashorn/test/script/basic/doublecache.js | 54 + .../test/script/basic/doublecache.js.EXPECTED | 19 + nashorn/test/script/basic/enumeration.js | 55 + .../test/script/basic/enumeration.js.EXPECTED | 16 + nashorn/test/script/basic/errors.js | 95 + nashorn/test/script/basic/errors.js.EXPECTED | 31 + nashorn/test/script/basic/errorstack.js | 51 + .../test/script/basic/errorstack.js.EXPECTED | 4 + nashorn/test/script/basic/eval.js | 73 + nashorn/test/script/basic/eval.js.EXPECTED | 15 + nashorn/test/script/basic/evalreturn.js | 71 + .../test/script/basic/evalreturn.js.EXPECTED | 11 + nashorn/test/script/basic/exprclosure.js | 38 + .../test/script/basic/exprclosure.js.EXPECTED | 4 + nashorn/test/script/basic/extensibility.js | 47 + .../script/basic/extensibility.js.EXPECTED | 6 + nashorn/test/script/basic/fileline.js | 48 + .../test/script/basic/fileline.js.EXPECTED | 4 + .../test/script/basic/finally-catchalls.js | 121 + .../basic/finally-catchalls.js.EXPECTED | 62 + nashorn/test/script/basic/finallyreturn.js | 41 + .../script/basic/finallyreturn.js.EXPECTED | 1 + nashorn/test/script/basic/forin.js | 56 + nashorn/test/script/basic/forin.js.EXPECTED | 37 + nashorn/test/script/basic/forin2.js | 116 + nashorn/test/script/basic/forin2.js.EXPECTED | 4 + nashorn/test/script/basic/funcarray.js | 42 + .../test/script/basic/funcarray.js.EXPECTED | 4 + nashorn/test/script/basic/funcbind.js | 53 + .../test/script/basic/funcbind.js.EXPECTED | 11 + nashorn/test/script/basic/funcconstructor.js | 43 + .../script/basic/funcconstructor.js.EXPECTED | 10 + nashorn/test/script/basic/getclassname.js | 126 + nashorn/test/script/basic/getenv.js | 31 + nashorn/test/script/basic/getenv.js.EXPECTED | 1 + nashorn/test/script/basic/getter_callsite.js | 51 + .../script/basic/getter_callsite.js.EXPECTED | 4 + nashorn/test/script/basic/gettercalls.js | 48 + .../test/script/basic/gettercalls.js.EXPECTED | 21 + nashorn/test/script/basic/getterfunc.js | 69 + .../test/script/basic/getterfunc.js.EXPECTED | 30 + nashorn/test/script/basic/gettersetter.js | 78 + .../script/basic/gettersetter.js.EXPECTED | 13 + nashorn/test/script/basic/globalaccess.js | 40 + .../script/basic/globalaccess.js.EXPECTED | 1 + nashorn/test/script/basic/globals.js | 94 + nashorn/test/script/basic/globals.js.EXPECTED | 32 + nashorn/test/script/basic/globalscope.js | 43 + .../test/script/basic/globalscope.js.EXPECTED | 2 + nashorn/test/script/basic/hello.js | 31 + nashorn/test/script/basic/hello.js.EXPECTED | 1 + nashorn/test/script/basic/herestr_operator.js | 39 + .../script/basic/herestr_operator.js.EXPECTED | 1 + nashorn/test/script/basic/illegaljavaname.js | 37 + .../script/basic/illegaljavaname.js.EXPECTED | 2 + nashorn/test/script/basic/incheck.js | 54 + nashorn/test/script/basic/incheck.js.EXPECTED | 10 + nashorn/test/script/basic/indexedcall.js | 35 + .../test/script/basic/indexedcall.js.EXPECTED | 1 + nashorn/test/script/basic/info.js | 32 + nashorn/test/script/basic/info.js.EXPECTED | 1 + .../script/basic/inherited_nonwritable.js | 40 + nashorn/test/script/basic/instanceof.js | 66 + .../test/script/basic/instanceof.js.EXPECTED | 21 + nashorn/test/script/basic/instanceof2.js | 48 + .../test/script/basic/instanceof2.js.EXPECTED | 8 + nashorn/test/script/basic/interfaces.js | 50 + .../test/script/basic/interfaces.js.EXPECTED | 3 + nashorn/test/script/basic/iterator.js | 42 + .../test/script/basic/iterator.js.EXPECTED | 12 + nashorn/test/script/basic/java.js | 47 + nashorn/test/script/basic/java.js.EXPECTED | 12 + nashorn/test/script/basic/javaarray.js | 71 + .../test/script/basic/javaarray.js.EXPECTED | 16 + .../test/script/basic/javaarrayconversion.js | 221 + .../basic/javaarrayconversion.js.EXPECTED | 1 + nashorn/test/script/basic/javaexceptions.js | 58 + .../script/basic/javaexceptions.js.EXPECTED | 7 + nashorn/test/script/basic/javaimporter.js | 48 + .../script/basic/javaimporter.js.EXPECTED | 4 + nashorn/test/script/basic/javainnerclasses.js | 53 + .../script/basic/javainnerclasses.js.EXPECTED | 9 + nashorn/test/script/basic/javasigcall.js | 46 + .../test/script/basic/javasigcall.js.EXPECTED | 5 + nashorn/test/script/basic/jquery.js | 93 + nashorn/test/script/basic/jquery.js.EXPECTED | 2 + nashorn/test/script/basic/jsadapter.js | 99 + .../test/script/basic/jsadapter.js.EXPECTED | 22 + nashorn/test/script/basic/jsadapterlink.js | 67 + .../script/basic/jsadapterlink.js.EXPECTED | 8 + nashorn/test/script/basic/json.js | 62 + nashorn/test/script/basic/json.js.EXPECTED | 15 + nashorn/test/script/basic/list.js | 68 + nashorn/test/script/basic/list.js.EXPECTED | 17 + nashorn/test/script/basic/literal.js | 38 + nashorn/test/script/basic/literal.js.EXPECTED | 4 + nashorn/test/script/basic/load.js | 31 + nashorn/test/script/basic/load.js.EXPECTED | 1 + nashorn/test/script/basic/loadedfile.js | 36 + nashorn/test/script/basic/localundef.js | 46 + .../test/script/basic/localundef.js.EXPECTED | 3 + nashorn/test/script/basic/map.js | 60 + nashorn/test/script/basic/map.js.EXPECTED | 18 + nashorn/test/script/basic/math.js | 42 + nashorn/test/script/basic/math.js.EXPECTED | 9 + nashorn/test/script/basic/minuszero.js | 41 + .../test/script/basic/minuszero.js.EXPECTED | 6 + nashorn/test/script/basic/module.js | 34 + nashorn/test/script/basic/moduleload.js | 36 + .../test/script/basic/moduleload.js.EXPECTED | 6 + nashorn/test/script/basic/nashorn2.js | 35 + .../test/script/basic/nashorn2.js.EXPECTED | 2 + nashorn/test/script/basic/natives.js | 37 + nashorn/test/script/basic/natives.js.EXPECTED | 3 + nashorn/test/script/basic/new.js | 62 + nashorn/test/script/basic/new.js.EXPECTED | 14 + nashorn/test/script/basic/newexpr.js | 66 + nashorn/test/script/basic/newexpr.js.EXPECTED | 7 + nashorn/test/script/basic/newnew.js | 48 + nashorn/test/script/basic/newnew.js.EXPECTED | 6 + nashorn/test/script/basic/nonconstructors.js | 53 + .../script/basic/nonconstructors.js.EXPECTED | 4 + nashorn/test/script/basic/nosuchmethod.js | 40 + .../script/basic/nosuchmethod.js.EXPECTED | 4 + nashorn/test/script/basic/nosuchproperty.js | 63 + .../script/basic/nosuchproperty.js.EXPECTED | 4 + nashorn/test/script/basic/number.js | 42 + nashorn/test/script/basic/number.js.EXPECTED | 7 + nashorn/test/script/basic/numberstring.js | 43 + .../script/basic/numberstring.js.EXPECTED | 67 + nashorn/test/script/basic/objectprops.js | 64 + .../test/script/basic/objectprops.js.EXPECTED | 8 + nashorn/test/script/basic/objects.js | 72 + nashorn/test/script/basic/objects.js.EXPECTED | 46 + nashorn/test/script/basic/options.js | 34 + nashorn/test/script/basic/options.js.EXPECTED | 3 + nashorn/test/script/basic/propchange.js | 58 + .../test/script/basic/propchange.js.EXPECTED | 5 + nashorn/test/script/basic/propertycheck.js | 37 + .../script/basic/propertycheck.js.EXPECTED | 2 + nashorn/test/script/basic/proto.js.EXPECTED | 2 + nashorn/test/script/basic/prototype.js | 52 + .../test/script/basic/prototype.js.EXPECTED | 1 + nashorn/test/script/basic/pushpull.js | 41 + .../test/script/basic/pushpull.js.EXPECTED | 7 + nashorn/test/script/basic/regex.js | 114 + nashorn/test/script/basic/regex.js.EXPECTED | 49 + nashorn/test/script/basic/regexp_flags.js | 49 + nashorn/test/script/basic/run-octane.js | 222 + nashorn/test/script/basic/runsunspider.js | 191 + .../script/basic/runsunspider.js.EXPECTED | 1 + nashorn/test/script/basic/samfunc.js | 48 + nashorn/test/script/basic/samfunc.js.EXPECTED | 2 + nashorn/test/script/basic/scripting.js | 81 + .../test/script/basic/scripting.js.EXPECTED | 103 + nashorn/test/script/basic/sealfreeze.js | 55 + .../test/script/basic/sealfreeze.js.EXPECTED | 10 + nashorn/test/script/basic/setlength.js | 45 + .../test/script/basic/setlength.js.EXPECTED | 10 + nashorn/test/script/basic/stdin.js | 35 + nashorn/test/script/basic/stdin.js.EXPECTED | 3 + nashorn/test/script/basic/strings.js | 87 + nashorn/test/script/basic/strings.js.EXPECTED | 37 + nashorn/test/script/basic/throws.js | 33 + nashorn/test/script/basic/throws.js.EXPECTED | 1 + nashorn/test/script/basic/tosource.js | 38 + .../test/script/basic/tosource.js.EXPECTED | 4 + nashorn/test/script/basic/tostring.js | 53 + .../test/script/basic/tostring.js.EXPECTED | 8 + nashorn/test/script/basic/try.js | 50 + nashorn/test/script/basic/try.js.EXPECTED | 7 + nashorn/test/script/basic/trybreakcont.js | 39 + .../script/basic/trybreakcont.js.EXPECTED | 2 + nashorn/test/script/basic/trycatch.js | 47 + .../test/script/basic/trycatch.js.EXPECTED | 1 + nashorn/test/script/basic/trycatchfor.js | 37 + .../test/script/basic/trycatchfor.js.EXPECTED | 1 + nashorn/test/script/basic/tryfinallyreturn.js | 44 + .../script/basic/tryfinallyreturn.js.EXPECTED | 2 + nashorn/test/script/basic/tryforbreak.js | 38 + .../test/script/basic/tryforbreak.js.EXPECTED | 1 + nashorn/test/script/basic/typechange.js | 33 + .../test/script/basic/typechange.js.EXPECTED | 1 + nashorn/test/script/basic/typeof.js | 47 + nashorn/test/script/basic/typeof.js.EXPECTED | 7 + nashorn/test/script/basic/typeof2.js | 45 + nashorn/test/script/basic/typeof2.js.EXPECTED | 12 + nashorn/test/script/basic/undefined.js | 94 + .../test/script/basic/undefined.js.EXPECTED | 10 + nashorn/test/script/basic/underscore.js | 37 + .../test/script/basic/underscore.js.EXPECTED | 1 + nashorn/test/script/basic/varargs.js | 56 + nashorn/test/script/basic/varargs.js.EXPECTED | 57 + nashorn/test/script/basic/void.js | 41 + nashorn/test/script/basic/void.js.EXPECTED | 8 + nashorn/test/script/basic/with.js | 64 + nashorn/test/script/basic/with.js.EXPECTED | 13 + nashorn/test/script/basic/withprimitive.js | 38 + .../script/basic/withprimitive.js.EXPECTED | 1 + nashorn/test/script/basic/writable_relink.js | 41 + .../script/basic/writable_relink.js.EXPECTED | 4 + .../test/script/basic/xmlStrings.js.EXPECTED | 23 + nashorn/test/script/basic/xorassign.js | 37 + .../test/script/basic/xorassign.js.EXPECTED | 1 + nashorn/test/script/basic/yui.js | 45 + nashorn/test/script/basic/yui.js.EXPECTED | 2 + nashorn/test/script/error/NASHORN-154/README | 6 + .../function_mult_params_in_strict.js | 38 + ...function_mult_params_in_strict.js.EXPECTED | 3 + .../improper_return_break_continue.js | 40 + ...improper_return_break_continue.js.EXPECTED | 15 + .../error/NASHORN-154/invalid_lvalue.js | 42 + .../NASHORN-154/invalid_lvalue.js.EXPECTED | 15 + .../NASHORN-154/literal_data_and_accessor.js | 38 + .../literal_data_and_accessor.js.EXPECTED | 6 + .../error/NASHORN-154/literal_mult_getters.js | 36 + .../literal_mult_getters.js.EXPECTED | 3 + .../literal_mult_prop_in_strict.js | 37 + .../literal_mult_prop_in_strict.js.EXPECTED | 3 + .../error/NASHORN-154/with_in_strict.js | 38 + .../NASHORN-154/with_in_strict.js.EXPECTED | 9 + nashorn/test/script/error/NASHORN-214.js | 44 + .../test/script/error/NASHORN-214.js.EXPECTED | 3 + nashorn/test/script/error/NASHORN-35.js | 32 + .../test/script/error/NASHORN-35.js.EXPECTED | 3 + nashorn/test/script/error/NASHORN-39.js | 33 + .../test/script/error/NASHORN-39.js.EXPECTED | 3 + nashorn/test/script/error/NASHORN-568.js | 30 + .../test/script/error/NASHORN-568.js.EXPECTED | 3 + nashorn/test/script/error/NASHORN-57.js | 35 + .../test/script/error/NASHORN-57.js.EXPECTED | 3 + nashorn/test/script/error/NASHORN-668.js | 38 + .../test/script/error/NASHORN-668.js.EXPECTED | 11 + nashorn/test/script/error/quotemissing.js | 28 + .../script/error/quotemissing.js.EXPECTED | 3 + nashorn/test/script/error/strictmode.js | 35 + .../test/script/error/strictmode.js.EXPECTED | 1 + .../script/representations/NASHORN-592a.js | 122 + nashorn/test/script/sandbox/NASHORN-525.js | 54 + nashorn/test/script/sandbox/README | 1 + nashorn/test/script/sandbox/classloader.js | 41 + .../script/sandbox/classloader.js.EXPECTED | 1 + nashorn/test/script/sandbox/doprivileged.js | 58 + .../script/sandbox/doprivileged.js.EXPECTED | 2 + nashorn/test/script/sandbox/exit.js | 46 + nashorn/test/script/sandbox/exit.js.EXPECTED | 2 + nashorn/test/script/sandbox/file.js | 55 + nashorn/test/script/sandbox/file.js.EXPECTED | 3 + nashorn/test/script/sandbox/javaextend.js | 102 + .../script/sandbox/javaextend.js.EXPECTED | 19 + nashorn/test/script/sandbox/loadLibrary.js | 43 + nashorn/test/script/sandbox/net.js | 43 + nashorn/test/script/sandbox/net.js.EXPECTED | 1 + nashorn/test/script/sandbox/property.js | 44 + .../test/script/sandbox/property.js.EXPECTED | 1 + nashorn/test/script/sandbox/reflection.js | 45 + .../script/sandbox/reflection.js.EXPECTED | 1 + nashorn/test/script/sandbox/runnable.js | 41 + .../test/script/sandbox/runnable.js.EXPECTED | 2 + nashorn/test/script/sandbox/unsafe.js | 66 + .../test/script/sandbox/unsafe.js.EXPECTED | 4 + nashorn/test/script/test262.js | 39 + nashorn/test/script/test262_single.js | 38 + .../test/src/UnnamedPackageTestCallback.java | 28 + .../api/scripting/MultipleEngineTest.java | 54 + .../api/scripting/ScriptEngineTest.java | 862 + .../src/jdk/nashorn/api/scripting/Window.java | 75 + .../api/scripting/WindowEventHandler.java | 32 + .../internal/access/BooleanAccessTest.java | 206 + .../internal/access/MethodAccessTest.java | 453 + .../internal/access/NumberAccessTest.java | 776 + .../internal/access/NumberBoxingTest.java | 348 + .../internal/access/ObjectAccessTest.java | 152 + .../jdk/nashorn/internal/access/Person.java | 58 + .../nashorn/internal/access/SharedObject.java | 466 + .../internal/access/StringAccessTest.java | 155 + .../internal/codegen/CompilerTest.java | 188 + .../nashorn/internal/parser/ParserTest.java | 187 + .../internal/performance/AuroraWrapper.java | 214 + .../internal/performance/OctaneTest.java | 307 + .../performance/PerformanceWrapper.java | 155 + .../internal/performance/SplayTest.java | 48 + .../nashorn/internal/runtime/ContextTest.java | 111 + .../nashorn/internal/runtime/JSTypeTest.java | 104 + .../runtime/Nashorn401TestSubject.java | 57 + .../framework/AbstractScriptRunnable.java | 297 + .../test/framework/JSJUnitReportReporter.java | 41 + .../test/framework/OrphanTestFinder.java | 67 + .../test/framework/ParallelTestRunner.java | 492 + .../test/framework/ScriptEvaluator.java | 45 + .../test/framework/ScriptRunnable.java | 236 + .../internal/test/framework/ScriptTest.java | 79 + .../framework/SeparateContextEvaluator.java | 40 + .../framework/SharedContextEvaluator.java | 151 + .../internal/test/framework/TestConfig.java | 75 + .../internal/test/framework/TestFinder.java | 362 + .../internal/test/framework/TestHelper.java | 134 + .../framework/TestReorderInterceptor.java | 59 + .../test/models/ConstructorWithArgument.java | 40 + .../internal/test/models/FinalClass.java | 30 + .../models/NoAccessibleConstructorClass.java | 30 + .../internal/test/models/NonPublicClass.java | 30 + .../internal/test/models/OuterClass.java | 65 + .../internal/test/models/OverloadedSam.java | 31 + .../internal/test/models/OverrideObject.java | 44 + 1176 files changed, 188153 insertions(+), 1 deletion(-) create mode 100644 nashorn/ASSEMBLY_EXCEPTION create mode 100644 nashorn/LICENSE create mode 100644 nashorn/README create mode 100644 nashorn/RELEASE_README create mode 100644 nashorn/THIRD_PARTY_README create mode 100644 nashorn/bin/checkintest.sh create mode 100644 nashorn/bin/fixorphantests.sh create mode 100644 nashorn/bin/fixwhitespace.sh create mode 100644 nashorn/bin/jjs create mode 100644 nashorn/bin/jjs.bat create mode 100644 nashorn/bin/jjssecure create mode 100644 nashorn/bin/jjssecure.bat create mode 100644 nashorn/bin/nashorn create mode 100644 nashorn/bin/nashorn.bat create mode 100644 nashorn/bin/rm-non-tracked.sh create mode 100644 nashorn/bin/verbose_octane.bat create mode 100644 nashorn/bin/verbose_octane.sh create mode 100644 nashorn/buildtools/nasgen/README create mode 100644 nashorn/buildtools/nasgen/build.xml create mode 100644 nashorn/buildtools/nasgen/nasgen.iml create mode 100644 nashorn/buildtools/nasgen/project.properties create mode 100644 nashorn/buildtools/nasgen/src/META-INF/MANIFEST.MF create mode 100644 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java create mode 100644 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java create mode 100644 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/Main.java create mode 100644 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java create mode 100644 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java create mode 100644 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/NullVisitor.java create mode 100644 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java create mode 100644 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java create mode 100644 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java create mode 100644 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java create mode 100644 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java create mode 100644 nashorn/docs/DEVELOPER_README create mode 100644 nashorn/docs/genshelldoc.js create mode 100644 nashorn/make/Makefile create mode 100644 nashorn/make/build-benchmark.xml create mode 100644 nashorn/make/build-nasgen.xml create mode 100644 nashorn/make/build.xml create mode 100644 nashorn/make/nbproject/ide-file-targets.xml create mode 100644 nashorn/make/nbproject/ide-targets.xml create mode 100644 nashorn/make/nbproject/jdk.xml create mode 100644 nashorn/make/nbproject/nbjdk.properties create mode 100644 nashorn/make/nbproject/nbjdk.xml create mode 100644 nashorn/make/nbproject/project.xml create mode 100644 nashorn/make/project.properties create mode 100644 nashorn/samples/counters.js create mode 100644 nashorn/samples/letter.js create mode 100644 nashorn/samples/parser.js create mode 100644 nashorn/samples/shell.js create mode 100644 nashorn/samples/test.js create mode 100644 nashorn/samples/uniq.js create mode 100644 nashorn/src/META-INF/MANIFEST.MF create mode 100644 nashorn/src/META-INF/services/javax.script.ScriptEngineFactory create mode 100644 nashorn/src/jdk/nashorn/api/scripting/NashornException.java create mode 100644 nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java create mode 100644 nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java create mode 100644 nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java create mode 100644 nashorn/src/jdk/nashorn/api/scripting/package-info.java create mode 100644 nashorn/src/jdk/nashorn/api/scripting/resources/engine.js create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/AccessSpecializer.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/CompileUnit.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/Compiler.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/ConstantData.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/Emitter.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/Frame.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/Lower.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/Namespace.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/Splitter.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/Transform.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/objects/FieldObjectCreator.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/objects/FunctionObjectCreator.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/objects/MapCreator.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectClassGenerator.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectCreator.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectMapCreator.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/types/ArrayType.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/types/BitwiseType.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/types/BooleanType.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/types/BytecodeArrayOps.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/types/BytecodeBitwiseOps.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/types/BytecodeNumericOps.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/types/BytecodeOps.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/types/IntType.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/types/LongType.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/types/NumberType.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/types/NumericType.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/types/ObjectType.java create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/types/Type.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/AccessNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/Assignment.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/BaseNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/Block.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/BreakNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/BreakableNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/CallNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/CaseNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/CatchNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/ContinueNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/DoWhileNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/EmptyNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/ExecuteNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/ForNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/FunctionCall.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/IdentNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/IfNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/IndexNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/LabelNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/LabeledNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/LineNumberNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/Location.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/Node.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/ObjectNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/PropertyKey.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/PropertyNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/ReferenceNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/ReturnNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/SplitNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/Symbol.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/TernaryNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/ThrowNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/TryNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/TypeOverride.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/VarNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/WhileNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/WithNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/annotations/ChildNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/annotations/Ignore.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/annotations/ParentNode.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/annotations/Reference.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/debug/ASTWriter.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java create mode 100644 nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/DateParser.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/Global.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeArguments.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeArray.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeDate.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeError.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeJava.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeMath.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeObject.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeStrictArguments.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeString.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/PrototypeObject.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/annotations/Attribute.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/annotations/Constructor.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/annotations/Function.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/annotations/Getter.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/annotations/Property.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/annotations/ScriptClass.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/annotations/Setter.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/annotations/SpecializedConstructor.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/annotations/Where.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/package-info.java create mode 100644 nashorn/src/jdk/nashorn/internal/parser/AbstractParser.java create mode 100644 nashorn/src/jdk/nashorn/internal/parser/JSONParser.java create mode 100644 nashorn/src/jdk/nashorn/internal/parser/Lexer.java create mode 100644 nashorn/src/jdk/nashorn/internal/parser/Parser.java create mode 100644 nashorn/src/jdk/nashorn/internal/parser/RegExp.java create mode 100644 nashorn/src/jdk/nashorn/internal/parser/RegExpScanner.java create mode 100644 nashorn/src/jdk/nashorn/internal/parser/Scanner.java create mode 100644 nashorn/src/jdk/nashorn/internal/parser/Token.java create mode 100644 nashorn/src/jdk/nashorn/internal/parser/TokenKind.java create mode 100644 nashorn/src/jdk/nashorn/internal/parser/TokenLookup.java create mode 100644 nashorn/src/jdk/nashorn/internal/parser/TokenStream.java create mode 100644 nashorn/src/jdk/nashorn/internal/parser/TokenType.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/BitVector.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/ConsString.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/Context.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/Debug.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/DefaultPropertyAccess.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/ECMAErrors.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/ECMAException.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/ErrorManager.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/FunctionScope.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/JSErrorType.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/JSType.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/Logging.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/NashornLoader.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/NumberToString.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/ParserException.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/Property.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/PropertyAccess.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/PropertyDescriptor.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/PropertyHashMap.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/PropertyListener.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/PropertyListenerManager.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/QuotedStringTokenizer.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/RegExpMatch.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/Scope.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/Source.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/SpillProperty.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/URIUtils.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/Undefined.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/Version.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/WithObject.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/EmptyArrayLikeIterator.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/FrozenArrayFilter.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/InvalidArrayIndexException.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/MapIterator.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseArrayIterator.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseMapIterator.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/InvokeByName.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/Lookup.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/Mangler.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/MethodHandleFactory.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/MethodHandleFunctionality.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuardedInvocation.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/options/KeyValueOption.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/options/Option.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/options/Options.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/options/ValueOption.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/resources/parser.js create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/resources/version.properties-template create mode 100644 nashorn/src/jdk/nashorn/internal/scripts/JO$.java create mode 100644 nashorn/src/jdk/nashorn/internal/scripts/JS$.java create mode 100644 nashorn/src/jdk/nashorn/tools/Shell.java create mode 100644 nashorn/src/jdk/nashorn/tools/resources/Shell.properties create mode 100644 nashorn/src/jdk/nashorn/tools/resources/shell.js create mode 100644 nashorn/src/netscape/javascript/JSObject.java create mode 100644 nashorn/src/overview.html create mode 100644 nashorn/test/README create mode 100644 nashorn/test/examples/dual-fields-micro.js create mode 100644 nashorn/test/examples/innerbench.js create mode 100644 nashorn/test/examples/typechain.js create mode 100644 nashorn/test/lib/benchmark.js create mode 100644 nashorn/test/opt/add.js create mode 100644 nashorn/test/opt/add_constant.js create mode 100644 nashorn/test/opt/add_reuse_callsite.js create mode 100644 nashorn/test/opt/add_revert2.js create mode 100644 nashorn/test/opt/cascade_specialize.js create mode 100644 nashorn/test/script/assert.js create mode 100644 nashorn/test/script/basic/NASHORN-100.js create mode 100644 nashorn/test/script/basic/NASHORN-100.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-101.js create mode 100644 nashorn/test/script/basic/NASHORN-101.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-102.js create mode 100644 nashorn/test/script/basic/NASHORN-102.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-103.js create mode 100644 nashorn/test/script/basic/NASHORN-104.js create mode 100644 nashorn/test/script/basic/NASHORN-104.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-105.js create mode 100644 nashorn/test/script/basic/NASHORN-105.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-106.js create mode 100644 nashorn/test/script/basic/NASHORN-106.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-107.js create mode 100644 nashorn/test/script/basic/NASHORN-108.js create mode 100644 nashorn/test/script/basic/NASHORN-108.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-109.js create mode 100644 nashorn/test/script/basic/NASHORN-109.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-11.js create mode 100644 nashorn/test/script/basic/NASHORN-11.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-111.js create mode 100644 nashorn/test/script/basic/NASHORN-111.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-113.js create mode 100644 nashorn/test/script/basic/NASHORN-113.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-114.js create mode 100644 nashorn/test/script/basic/NASHORN-115.js create mode 100644 nashorn/test/script/basic/NASHORN-115.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-117.js create mode 100644 nashorn/test/script/basic/NASHORN-118.js create mode 100644 nashorn/test/script/basic/NASHORN-118.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-119.js create mode 100644 nashorn/test/script/basic/NASHORN-119.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-12.js create mode 100644 nashorn/test/script/basic/NASHORN-120.js create mode 100644 nashorn/test/script/basic/NASHORN-122.js create mode 100644 nashorn/test/script/basic/NASHORN-122.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-126.js create mode 100644 nashorn/test/script/basic/NASHORN-126.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-127.js create mode 100644 nashorn/test/script/basic/NASHORN-127.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-130.js create mode 100644 nashorn/test/script/basic/NASHORN-132.js create mode 100644 nashorn/test/script/basic/NASHORN-132.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-133.js create mode 100644 nashorn/test/script/basic/NASHORN-133.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-135.js create mode 100644 nashorn/test/script/basic/NASHORN-136.js create mode 100644 nashorn/test/script/basic/NASHORN-136.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-14.js create mode 100644 nashorn/test/script/basic/NASHORN-14.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-148.js create mode 100644 nashorn/test/script/basic/NASHORN-148.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-15.js create mode 100644 nashorn/test/script/basic/NASHORN-15.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-153.js create mode 100644 nashorn/test/script/basic/NASHORN-156.js create mode 100644 nashorn/test/script/basic/NASHORN-157.js create mode 100644 nashorn/test/script/basic/NASHORN-163.js create mode 100644 nashorn/test/script/basic/NASHORN-163.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-164.js create mode 100644 nashorn/test/script/basic/NASHORN-165.js create mode 100644 nashorn/test/script/basic/NASHORN-166.js create mode 100644 nashorn/test/script/basic/NASHORN-168.js create mode 100644 nashorn/test/script/basic/NASHORN-168.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-169.js create mode 100644 nashorn/test/script/basic/NASHORN-172.js create mode 100644 nashorn/test/script/basic/NASHORN-173.js create mode 100644 nashorn/test/script/basic/NASHORN-173.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-174.js create mode 100644 nashorn/test/script/basic/NASHORN-175.js create mode 100644 nashorn/test/script/basic/NASHORN-176.js create mode 100644 nashorn/test/script/basic/NASHORN-177.js create mode 100644 nashorn/test/script/basic/NASHORN-177.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-178.js create mode 100644 nashorn/test/script/basic/NASHORN-178.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-179.js create mode 100644 nashorn/test/script/basic/NASHORN-18.js create mode 100644 nashorn/test/script/basic/NASHORN-18.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-181.js create mode 100644 nashorn/test/script/basic/NASHORN-182.js create mode 100644 nashorn/test/script/basic/NASHORN-183.js create mode 100644 nashorn/test/script/basic/NASHORN-184.js create mode 100644 nashorn/test/script/basic/NASHORN-184.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-185.js create mode 100644 nashorn/test/script/basic/NASHORN-185.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-187.js create mode 100644 nashorn/test/script/basic/NASHORN-188.js create mode 100644 nashorn/test/script/basic/NASHORN-188.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-19.js create mode 100644 nashorn/test/script/basic/NASHORN-19.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-190.js create mode 100644 nashorn/test/script/basic/NASHORN-192.js create mode 100644 nashorn/test/script/basic/NASHORN-194.js create mode 100644 nashorn/test/script/basic/NASHORN-196.js create mode 100644 nashorn/test/script/basic/NASHORN-198.js create mode 100644 nashorn/test/script/basic/NASHORN-20.js create mode 100644 nashorn/test/script/basic/NASHORN-20.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-201.js create mode 100644 nashorn/test/script/basic/NASHORN-202.js create mode 100644 nashorn/test/script/basic/NASHORN-203.js create mode 100644 nashorn/test/script/basic/NASHORN-204.js create mode 100644 nashorn/test/script/basic/NASHORN-205.js create mode 100644 nashorn/test/script/basic/NASHORN-206.js create mode 100644 nashorn/test/script/basic/NASHORN-207.js create mode 100644 nashorn/test/script/basic/NASHORN-207_2.js create mode 100644 nashorn/test/script/basic/NASHORN-208.js create mode 100644 nashorn/test/script/basic/NASHORN-208.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-209.js create mode 100644 nashorn/test/script/basic/NASHORN-209.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-21.js create mode 100644 nashorn/test/script/basic/NASHORN-21.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-211.js create mode 100644 nashorn/test/script/basic/NASHORN-212.js create mode 100644 nashorn/test/script/basic/NASHORN-213.js create mode 100644 nashorn/test/script/basic/NASHORN-215.js create mode 100644 nashorn/test/script/basic/NASHORN-215.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-216.js create mode 100644 nashorn/test/script/basic/NASHORN-217.js create mode 100644 nashorn/test/script/basic/NASHORN-217.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-219.js create mode 100644 nashorn/test/script/basic/NASHORN-219.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-22.js create mode 100644 nashorn/test/script/basic/NASHORN-22.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-221.js create mode 100644 nashorn/test/script/basic/NASHORN-222.js create mode 100644 nashorn/test/script/basic/NASHORN-223.js create mode 100644 nashorn/test/script/basic/NASHORN-225.js create mode 100644 nashorn/test/script/basic/NASHORN-226.js create mode 100644 nashorn/test/script/basic/NASHORN-227.js create mode 100644 nashorn/test/script/basic/NASHORN-228.js create mode 100644 nashorn/test/script/basic/NASHORN-229.js create mode 100644 nashorn/test/script/basic/NASHORN-229_subtest.js create mode 100644 nashorn/test/script/basic/NASHORN-23.js create mode 100644 nashorn/test/script/basic/NASHORN-23.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-232.js create mode 100644 nashorn/test/script/basic/NASHORN-234.js create mode 100644 nashorn/test/script/basic/NASHORN-235.js create mode 100644 nashorn/test/script/basic/NASHORN-236.js create mode 100644 nashorn/test/script/basic/NASHORN-237.js create mode 100644 nashorn/test/script/basic/NASHORN-239.js create mode 100644 nashorn/test/script/basic/NASHORN-24.js create mode 100644 nashorn/test/script/basic/NASHORN-24.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-241.js create mode 100644 nashorn/test/script/basic/NASHORN-242.js create mode 100644 nashorn/test/script/basic/NASHORN-245.js create mode 100644 nashorn/test/script/basic/NASHORN-247.js create mode 100644 nashorn/test/script/basic/NASHORN-25.js create mode 100644 nashorn/test/script/basic/NASHORN-25.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-251.js create mode 100644 nashorn/test/script/basic/NASHORN-252.js create mode 100644 nashorn/test/script/basic/NASHORN-253.js create mode 100644 nashorn/test/script/basic/NASHORN-256.js create mode 100644 nashorn/test/script/basic/NASHORN-258.js create mode 100644 nashorn/test/script/basic/NASHORN-258.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-26.js create mode 100644 nashorn/test/script/basic/NASHORN-26.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-260.js create mode 100644 nashorn/test/script/basic/NASHORN-261.js create mode 100644 nashorn/test/script/basic/NASHORN-262.js create mode 100644 nashorn/test/script/basic/NASHORN-263.js create mode 100644 nashorn/test/script/basic/NASHORN-264.js create mode 100644 nashorn/test/script/basic/NASHORN-265.js create mode 100644 nashorn/test/script/basic/NASHORN-265.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-266.js create mode 100644 nashorn/test/script/basic/NASHORN-269.js create mode 100644 nashorn/test/script/basic/NASHORN-27.js create mode 100644 nashorn/test/script/basic/NASHORN-27.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-270.js create mode 100644 nashorn/test/script/basic/NASHORN-271.js create mode 100644 nashorn/test/script/basic/NASHORN-275.js create mode 100644 nashorn/test/script/basic/NASHORN-276.js create mode 100644 nashorn/test/script/basic/NASHORN-277.js create mode 100644 nashorn/test/script/basic/NASHORN-278.js create mode 100644 nashorn/test/script/basic/NASHORN-28.js create mode 100644 nashorn/test/script/basic/NASHORN-28.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-281.js create mode 100644 nashorn/test/script/basic/NASHORN-284.js create mode 100644 nashorn/test/script/basic/NASHORN-284.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-285.js create mode 100644 nashorn/test/script/basic/NASHORN-285.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-288.js create mode 100644 nashorn/test/script/basic/NASHORN-29.js create mode 100644 nashorn/test/script/basic/NASHORN-29.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-293.js create mode 100644 nashorn/test/script/basic/NASHORN-293.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-294.js create mode 100644 nashorn/test/script/basic/NASHORN-296.js create mode 100644 nashorn/test/script/basic/NASHORN-297.js create mode 100644 nashorn/test/script/basic/NASHORN-30.js create mode 100644 nashorn/test/script/basic/NASHORN-30.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-300.js create mode 100644 nashorn/test/script/basic/NASHORN-301.js create mode 100644 nashorn/test/script/basic/NASHORN-301.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-304.js create mode 100644 nashorn/test/script/basic/NASHORN-310.js create mode 100644 nashorn/test/script/basic/NASHORN-310.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-318.js create mode 100644 nashorn/test/script/basic/NASHORN-318.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-32.js create mode 100644 nashorn/test/script/basic/NASHORN-32.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-321.js create mode 100644 nashorn/test/script/basic/NASHORN-321.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-323.js create mode 100644 nashorn/test/script/basic/NASHORN-323.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-324.js create mode 100644 nashorn/test/script/basic/NASHORN-33.js create mode 100644 nashorn/test/script/basic/NASHORN-33.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-331.js create mode 100644 nashorn/test/script/basic/NASHORN-331.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-337.js create mode 100644 nashorn/test/script/basic/NASHORN-337.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-34.js create mode 100644 nashorn/test/script/basic/NASHORN-34.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-340.js create mode 100644 nashorn/test/script/basic/NASHORN-340.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-349.js create mode 100644 nashorn/test/script/basic/NASHORN-354.js create mode 100644 nashorn/test/script/basic/NASHORN-354.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-355.js create mode 100644 nashorn/test/script/basic/NASHORN-355.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-36.js create mode 100644 nashorn/test/script/basic/NASHORN-36.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-365.js create mode 100644 nashorn/test/script/basic/NASHORN-366.js create mode 100644 nashorn/test/script/basic/NASHORN-366.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-368.js create mode 100644 nashorn/test/script/basic/NASHORN-368.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-37.js create mode 100644 nashorn/test/script/basic/NASHORN-37.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-375.js create mode 100644 nashorn/test/script/basic/NASHORN-376.js create mode 100644 nashorn/test/script/basic/NASHORN-377.js create mode 100644 nashorn/test/script/basic/NASHORN-377.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-378.js create mode 100644 nashorn/test/script/basic/NASHORN-38.js create mode 100644 nashorn/test/script/basic/NASHORN-38.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-380.js create mode 100644 nashorn/test/script/basic/NASHORN-380.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-381.js create mode 100644 nashorn/test/script/basic/NASHORN-382.js create mode 100644 nashorn/test/script/basic/NASHORN-383.js create mode 100644 nashorn/test/script/basic/NASHORN-384.js create mode 100644 nashorn/test/script/basic/NASHORN-384.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-385.js create mode 100644 nashorn/test/script/basic/NASHORN-385.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-389.js create mode 100644 nashorn/test/script/basic/NASHORN-389.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-393.js create mode 100644 nashorn/test/script/basic/NASHORN-393.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-394.js create mode 100644 nashorn/test/script/basic/NASHORN-394.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-396.js create mode 100644 nashorn/test/script/basic/NASHORN-397.js create mode 100644 nashorn/test/script/basic/NASHORN-398.js create mode 100644 nashorn/test/script/basic/NASHORN-40.js create mode 100644 nashorn/test/script/basic/NASHORN-40.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-400.js create mode 100644 nashorn/test/script/basic/NASHORN-400.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-401.js create mode 100644 nashorn/test/script/basic/NASHORN-401.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-402.js create mode 100644 nashorn/test/script/basic/NASHORN-402.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-404.js create mode 100644 nashorn/test/script/basic/NASHORN-405.js create mode 100644 nashorn/test/script/basic/NASHORN-405.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-406.js create mode 100644 nashorn/test/script/basic/NASHORN-408.js create mode 100644 nashorn/test/script/basic/NASHORN-408.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-415.js create mode 100644 nashorn/test/script/basic/NASHORN-415.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-416.js create mode 100644 nashorn/test/script/basic/NASHORN-417.js create mode 100644 nashorn/test/script/basic/NASHORN-418.js create mode 100644 nashorn/test/script/basic/NASHORN-420.js create mode 100644 nashorn/test/script/basic/NASHORN-421.js create mode 100644 nashorn/test/script/basic/NASHORN-423.js create mode 100644 nashorn/test/script/basic/NASHORN-423.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-423a.js create mode 100644 nashorn/test/script/basic/NASHORN-424.js create mode 100644 nashorn/test/script/basic/NASHORN-424.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-425.js create mode 100644 nashorn/test/script/basic/NASHORN-425.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-426.js create mode 100644 nashorn/test/script/basic/NASHORN-427.js create mode 100644 nashorn/test/script/basic/NASHORN-428.js create mode 100644 nashorn/test/script/basic/NASHORN-429.js create mode 100644 nashorn/test/script/basic/NASHORN-432.js create mode 100644 nashorn/test/script/basic/NASHORN-433.js create mode 100644 nashorn/test/script/basic/NASHORN-434.js create mode 100644 nashorn/test/script/basic/NASHORN-435.js create mode 100644 nashorn/test/script/basic/NASHORN-437.js create mode 100644 nashorn/test/script/basic/NASHORN-44.js create mode 100644 nashorn/test/script/basic/NASHORN-44.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-441.js create mode 100644 nashorn/test/script/basic/NASHORN-441.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-442.js create mode 100644 nashorn/test/script/basic/NASHORN-443.js create mode 100644 nashorn/test/script/basic/NASHORN-444.js create mode 100644 nashorn/test/script/basic/NASHORN-444.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-445.js create mode 100644 nashorn/test/script/basic/NASHORN-446.js create mode 100644 nashorn/test/script/basic/NASHORN-447.js create mode 100644 nashorn/test/script/basic/NASHORN-448.js create mode 100644 nashorn/test/script/basic/NASHORN-449.js create mode 100644 nashorn/test/script/basic/NASHORN-449.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-45.js create mode 100644 nashorn/test/script/basic/NASHORN-45.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-450.js create mode 100644 nashorn/test/script/basic/NASHORN-452.js create mode 100644 nashorn/test/script/basic/NASHORN-459.js create mode 100644 nashorn/test/script/basic/NASHORN-46.js create mode 100644 nashorn/test/script/basic/NASHORN-46.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-462.js create mode 100644 nashorn/test/script/basic/NASHORN-463.js create mode 100644 nashorn/test/script/basic/NASHORN-468.js create mode 100644 nashorn/test/script/basic/NASHORN-47.js create mode 100644 nashorn/test/script/basic/NASHORN-473.js create mode 100644 nashorn/test/script/basic/NASHORN-473.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-474.js create mode 100644 nashorn/test/script/basic/NASHORN-474.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-478.js create mode 100644 nashorn/test/script/basic/NASHORN-48.js create mode 100644 nashorn/test/script/basic/NASHORN-48.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-481.js create mode 100644 nashorn/test/script/basic/NASHORN-481.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-482.js create mode 100644 nashorn/test/script/basic/NASHORN-484.js create mode 100644 nashorn/test/script/basic/NASHORN-484.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-486.js create mode 100644 nashorn/test/script/basic/NASHORN-487.js create mode 100644 nashorn/test/script/basic/NASHORN-488.js create mode 100644 nashorn/test/script/basic/NASHORN-49.js create mode 100644 nashorn/test/script/basic/NASHORN-49.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-490.js create mode 100644 nashorn/test/script/basic/NASHORN-494.js create mode 100644 nashorn/test/script/basic/NASHORN-497.js create mode 100644 nashorn/test/script/basic/NASHORN-498.js create mode 100644 nashorn/test/script/basic/NASHORN-499.js create mode 100644 nashorn/test/script/basic/NASHORN-50.js create mode 100644 nashorn/test/script/basic/NASHORN-50.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-500.js create mode 100644 nashorn/test/script/basic/NASHORN-503.js create mode 100644 nashorn/test/script/basic/NASHORN-503.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-51.js create mode 100644 nashorn/test/script/basic/NASHORN-51.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-511.js create mode 100644 nashorn/test/script/basic/NASHORN-515.js create mode 100644 nashorn/test/script/basic/NASHORN-515.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-516.js create mode 100644 nashorn/test/script/basic/NASHORN-52.js create mode 100644 nashorn/test/script/basic/NASHORN-534.js create mode 100644 nashorn/test/script/basic/NASHORN-534.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-535.js create mode 100644 nashorn/test/script/basic/NASHORN-535.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-544.js create mode 100644 nashorn/test/script/basic/NASHORN-55.js create mode 100644 nashorn/test/script/basic/NASHORN-554.js create mode 100644 nashorn/test/script/basic/NASHORN-554.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-556.js create mode 100644 nashorn/test/script/basic/NASHORN-556.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-56.js create mode 100644 nashorn/test/script/basic/NASHORN-56.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-562.js create mode 100644 nashorn/test/script/basic/NASHORN-565.js create mode 100644 nashorn/test/script/basic/NASHORN-565.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-575.js create mode 100644 nashorn/test/script/basic/NASHORN-575.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-58.js create mode 100644 nashorn/test/script/basic/NASHORN-58.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-59.js create mode 100644 nashorn/test/script/basic/NASHORN-59.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-592.js create mode 100644 nashorn/test/script/basic/NASHORN-592.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-597.js create mode 100644 nashorn/test/script/basic/NASHORN-597.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-60.js create mode 100644 nashorn/test/script/basic/NASHORN-60.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-609.js create mode 100644 nashorn/test/script/basic/NASHORN-609.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-61.js create mode 100644 nashorn/test/script/basic/NASHORN-61.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-62.js create mode 100644 nashorn/test/script/basic/NASHORN-62.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-620.js create mode 100644 nashorn/test/script/basic/NASHORN-620.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-623.js create mode 100644 nashorn/test/script/basic/NASHORN-623.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-627.js create mode 100644 nashorn/test/script/basic/NASHORN-627.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-63.js create mode 100644 nashorn/test/script/basic/NASHORN-631.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-637.js create mode 100644 nashorn/test/script/basic/NASHORN-637.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-638.js create mode 100644 nashorn/test/script/basic/NASHORN-638.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-639.js create mode 100644 nashorn/test/script/basic/NASHORN-64.js create mode 100644 nashorn/test/script/basic/NASHORN-642.js create mode 100644 nashorn/test/script/basic/NASHORN-642.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-646.js create mode 100644 nashorn/test/script/basic/NASHORN-653.js create mode 100644 nashorn/test/script/basic/NASHORN-658.js create mode 100644 nashorn/test/script/basic/NASHORN-659.js create mode 100644 nashorn/test/script/basic/NASHORN-66.js create mode 100644 nashorn/test/script/basic/NASHORN-66.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-664.js create mode 100644 nashorn/test/script/basic/NASHORN-665.js create mode 100644 nashorn/test/script/basic/NASHORN-67.js create mode 100644 nashorn/test/script/basic/NASHORN-67.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-678.js create mode 100644 nashorn/test/script/basic/NASHORN-68.js create mode 100644 nashorn/test/script/basic/NASHORN-68.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-689.js create mode 100644 nashorn/test/script/basic/NASHORN-689.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-69.js create mode 100644 nashorn/test/script/basic/NASHORN-69.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-691.js create mode 100644 nashorn/test/script/basic/NASHORN-691.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-694.js create mode 100644 nashorn/test/script/basic/NASHORN-694.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-697.js create mode 100644 nashorn/test/script/basic/NASHORN-703.js create mode 100644 nashorn/test/script/basic/NASHORN-703.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-703a.js create mode 100644 nashorn/test/script/basic/NASHORN-703a.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-705.js create mode 100644 nashorn/test/script/basic/NASHORN-71.js create mode 100644 nashorn/test/script/basic/NASHORN-71.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-710.js create mode 100644 nashorn/test/script/basic/NASHORN-711.js create mode 100644 nashorn/test/script/basic/NASHORN-711.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-72.js create mode 100644 nashorn/test/script/basic/NASHORN-72.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-722.js create mode 100644 nashorn/test/script/basic/NASHORN-73.js create mode 100644 nashorn/test/script/basic/NASHORN-73.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-737.js create mode 100644 nashorn/test/script/basic/NASHORN-737.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-74.js create mode 100644 nashorn/test/script/basic/NASHORN-74.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-740.js create mode 100644 nashorn/test/script/basic/NASHORN-740.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-75.js create mode 100644 nashorn/test/script/basic/NASHORN-75.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-758.js create mode 100644 nashorn/test/script/basic/NASHORN-759.js create mode 100644 nashorn/test/script/basic/NASHORN-759.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-760.js create mode 100644 nashorn/test/script/basic/NASHORN-768.js create mode 100644 nashorn/test/script/basic/NASHORN-778.js create mode 100644 nashorn/test/script/basic/NASHORN-78.js create mode 100644 nashorn/test/script/basic/NASHORN-79.js create mode 100644 nashorn/test/script/basic/NASHORN-79.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-792.js create mode 100644 nashorn/test/script/basic/NASHORN-792.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-80.js create mode 100644 nashorn/test/script/basic/NASHORN-80.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-81.js create mode 100644 nashorn/test/script/basic/NASHORN-833.js create mode 100644 nashorn/test/script/basic/NASHORN-833.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-85.js create mode 100644 nashorn/test/script/basic/NASHORN-85.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-86.js create mode 100644 nashorn/test/script/basic/NASHORN-87.js create mode 100644 nashorn/test/script/basic/NASHORN-89.js create mode 100644 nashorn/test/script/basic/NASHORN-90.js create mode 100644 nashorn/test/script/basic/NASHORN-90.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-91.js create mode 100644 nashorn/test/script/basic/NASHORN-91.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-92.js create mode 100644 nashorn/test/script/basic/NASHORN-92.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-93.js create mode 100644 nashorn/test/script/basic/NASHORN-95.js create mode 100644 nashorn/test/script/basic/NASHORN-95.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-96.js create mode 100644 nashorn/test/script/basic/NASHORN-96.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-97.js create mode 100644 nashorn/test/script/basic/NASHORN-98.js create mode 100644 nashorn/test/script/basic/NASHORN-98.js.EXPECTED create mode 100644 nashorn/test/script/basic/NASHORN-99.js create mode 100644 nashorn/test/script/basic/addition.js create mode 100644 nashorn/test/script/basic/addition.js.EXPECTED create mode 100644 nashorn/test/script/basic/allgettersetters.js create mode 100644 nashorn/test/script/basic/andor.js create mode 100644 nashorn/test/script/basic/andor.js.EXPECTED create mode 100644 nashorn/test/script/basic/anonrecur.js create mode 100644 nashorn/test/script/basic/anonrecur.js.EXPECTED create mode 100644 nashorn/test/script/basic/applycall.js create mode 100644 nashorn/test/script/basic/applycall.js.EXPECTED create mode 100644 nashorn/test/script/basic/args.js create mode 100644 nashorn/test/script/basic/args.js.EXPECTED create mode 100644 nashorn/test/script/basic/arity.js create mode 100644 nashorn/test/script/basic/arity.js.EXPECTED create mode 100644 nashorn/test/script/basic/arrayprotoclass.js create mode 100644 nashorn/test/script/basic/arrayprotoclass.js.EXPECTED create mode 100644 nashorn/test/script/basic/arrays.js create mode 100644 nashorn/test/script/basic/arrays.js.EXPECTED create mode 100644 nashorn/test/script/basic/arrays2.js create mode 100644 nashorn/test/script/basic/arrays2.js.EXPECTED create mode 100644 nashorn/test/script/basic/arraysIntKey.js create mode 100644 nashorn/test/script/basic/arraysIntKey.js.EXPECTED create mode 100644 nashorn/test/script/basic/arrayset.js create mode 100644 nashorn/test/script/basic/arrayset.js.EXPECTED create mode 100644 nashorn/test/script/basic/arrayundefined.js create mode 100644 nashorn/test/script/basic/arrayundefined.js.EXPECTED create mode 100644 nashorn/test/script/basic/assign.js create mode 100644 nashorn/test/script/basic/assign.js.EXPECTED create mode 100644 nashorn/test/script/basic/bitwise_and.js create mode 100644 nashorn/test/script/basic/bitwise_and.js.EXPECTED create mode 100644 nashorn/test/script/basic/booleangetter.js create mode 100644 nashorn/test/script/basic/booleangetter.js.EXPECTED create mode 100644 nashorn/test/script/basic/builtin.js create mode 100644 nashorn/test/script/basic/builtin.js.EXPECTED create mode 100644 nashorn/test/script/basic/builtin_assign.js create mode 100644 nashorn/test/script/basic/builtin_assign.js.EXPECTED create mode 100644 nashorn/test/script/basic/builtinchain.js create mode 100644 nashorn/test/script/basic/builtinchain.js.EXPECTED create mode 100644 nashorn/test/script/basic/calllink.js create mode 100644 nashorn/test/script/basic/calllink.js.EXPECTED create mode 100644 nashorn/test/script/basic/closure.js create mode 100644 nashorn/test/script/basic/closure.js.EXPECTED create mode 100644 nashorn/test/script/basic/commandargs.js create mode 100644 nashorn/test/script/basic/commandargs.js.EXPECTED create mode 100644 nashorn/test/script/basic/compile-octane.js create mode 100644 nashorn/test/script/basic/compile-octane.js.EXPECTED create mode 100644 nashorn/test/script/basic/condassign.js create mode 100644 nashorn/test/script/basic/condassign.js.EXPECTED create mode 100644 nashorn/test/script/basic/construct.js create mode 100644 nashorn/test/script/basic/construct.js.EXPECTED create mode 100644 nashorn/test/script/basic/constructorname.js create mode 100644 nashorn/test/script/basic/constructorname.js.EXPECTED create mode 100644 nashorn/test/script/basic/date.js create mode 100644 nashorn/test/script/basic/date.js.EXPECTED create mode 100644 nashorn/test/script/basic/dateparse.js create mode 100644 nashorn/test/script/basic/dateparse.js.EXPECTED create mode 100644 nashorn/test/script/basic/decinc.js create mode 100644 nashorn/test/script/basic/decinc.js.EXPECTED create mode 100644 nashorn/test/script/basic/delete.js create mode 100644 nashorn/test/script/basic/delete.js.EXPECTED create mode 100644 nashorn/test/script/basic/delete2.js create mode 100644 nashorn/test/script/basic/delete2.js.EXPECTED create mode 100644 nashorn/test/script/basic/dotpropname.js create mode 100644 nashorn/test/script/basic/dotpropname.js.EXPECTED create mode 100644 nashorn/test/script/basic/doublecache.js create mode 100644 nashorn/test/script/basic/doublecache.js.EXPECTED create mode 100644 nashorn/test/script/basic/enumeration.js create mode 100644 nashorn/test/script/basic/enumeration.js.EXPECTED create mode 100644 nashorn/test/script/basic/errors.js create mode 100644 nashorn/test/script/basic/errors.js.EXPECTED create mode 100644 nashorn/test/script/basic/errorstack.js create mode 100644 nashorn/test/script/basic/errorstack.js.EXPECTED create mode 100644 nashorn/test/script/basic/eval.js create mode 100644 nashorn/test/script/basic/eval.js.EXPECTED create mode 100644 nashorn/test/script/basic/evalreturn.js create mode 100644 nashorn/test/script/basic/evalreturn.js.EXPECTED create mode 100644 nashorn/test/script/basic/exprclosure.js create mode 100644 nashorn/test/script/basic/exprclosure.js.EXPECTED create mode 100644 nashorn/test/script/basic/extensibility.js create mode 100644 nashorn/test/script/basic/extensibility.js.EXPECTED create mode 100644 nashorn/test/script/basic/fileline.js create mode 100644 nashorn/test/script/basic/fileline.js.EXPECTED create mode 100644 nashorn/test/script/basic/finally-catchalls.js create mode 100644 nashorn/test/script/basic/finally-catchalls.js.EXPECTED create mode 100644 nashorn/test/script/basic/finallyreturn.js create mode 100644 nashorn/test/script/basic/finallyreturn.js.EXPECTED create mode 100644 nashorn/test/script/basic/forin.js create mode 100644 nashorn/test/script/basic/forin.js.EXPECTED create mode 100644 nashorn/test/script/basic/forin2.js create mode 100644 nashorn/test/script/basic/forin2.js.EXPECTED create mode 100644 nashorn/test/script/basic/funcarray.js create mode 100644 nashorn/test/script/basic/funcarray.js.EXPECTED create mode 100644 nashorn/test/script/basic/funcbind.js create mode 100644 nashorn/test/script/basic/funcbind.js.EXPECTED create mode 100644 nashorn/test/script/basic/funcconstructor.js create mode 100644 nashorn/test/script/basic/funcconstructor.js.EXPECTED create mode 100644 nashorn/test/script/basic/getclassname.js create mode 100644 nashorn/test/script/basic/getenv.js create mode 100644 nashorn/test/script/basic/getenv.js.EXPECTED create mode 100644 nashorn/test/script/basic/getter_callsite.js create mode 100644 nashorn/test/script/basic/getter_callsite.js.EXPECTED create mode 100644 nashorn/test/script/basic/gettercalls.js create mode 100644 nashorn/test/script/basic/gettercalls.js.EXPECTED create mode 100644 nashorn/test/script/basic/getterfunc.js create mode 100644 nashorn/test/script/basic/getterfunc.js.EXPECTED create mode 100644 nashorn/test/script/basic/gettersetter.js create mode 100644 nashorn/test/script/basic/gettersetter.js.EXPECTED create mode 100644 nashorn/test/script/basic/globalaccess.js create mode 100644 nashorn/test/script/basic/globalaccess.js.EXPECTED create mode 100644 nashorn/test/script/basic/globals.js create mode 100644 nashorn/test/script/basic/globals.js.EXPECTED create mode 100644 nashorn/test/script/basic/globalscope.js create mode 100644 nashorn/test/script/basic/globalscope.js.EXPECTED create mode 100644 nashorn/test/script/basic/hello.js create mode 100644 nashorn/test/script/basic/hello.js.EXPECTED create mode 100644 nashorn/test/script/basic/herestr_operator.js create mode 100644 nashorn/test/script/basic/herestr_operator.js.EXPECTED create mode 100644 nashorn/test/script/basic/illegaljavaname.js create mode 100644 nashorn/test/script/basic/illegaljavaname.js.EXPECTED create mode 100644 nashorn/test/script/basic/incheck.js create mode 100644 nashorn/test/script/basic/incheck.js.EXPECTED create mode 100644 nashorn/test/script/basic/indexedcall.js create mode 100644 nashorn/test/script/basic/indexedcall.js.EXPECTED create mode 100644 nashorn/test/script/basic/info.js create mode 100644 nashorn/test/script/basic/info.js.EXPECTED create mode 100644 nashorn/test/script/basic/inherited_nonwritable.js create mode 100644 nashorn/test/script/basic/instanceof.js create mode 100644 nashorn/test/script/basic/instanceof.js.EXPECTED create mode 100644 nashorn/test/script/basic/instanceof2.js create mode 100644 nashorn/test/script/basic/instanceof2.js.EXPECTED create mode 100644 nashorn/test/script/basic/interfaces.js create mode 100644 nashorn/test/script/basic/interfaces.js.EXPECTED create mode 100644 nashorn/test/script/basic/iterator.js create mode 100644 nashorn/test/script/basic/iterator.js.EXPECTED create mode 100644 nashorn/test/script/basic/java.js create mode 100644 nashorn/test/script/basic/java.js.EXPECTED create mode 100644 nashorn/test/script/basic/javaarray.js create mode 100644 nashorn/test/script/basic/javaarray.js.EXPECTED create mode 100644 nashorn/test/script/basic/javaarrayconversion.js create mode 100644 nashorn/test/script/basic/javaarrayconversion.js.EXPECTED create mode 100644 nashorn/test/script/basic/javaexceptions.js create mode 100644 nashorn/test/script/basic/javaexceptions.js.EXPECTED create mode 100644 nashorn/test/script/basic/javaimporter.js create mode 100644 nashorn/test/script/basic/javaimporter.js.EXPECTED create mode 100644 nashorn/test/script/basic/javainnerclasses.js create mode 100644 nashorn/test/script/basic/javainnerclasses.js.EXPECTED create mode 100644 nashorn/test/script/basic/javasigcall.js create mode 100644 nashorn/test/script/basic/javasigcall.js.EXPECTED create mode 100644 nashorn/test/script/basic/jquery.js create mode 100644 nashorn/test/script/basic/jquery.js.EXPECTED create mode 100644 nashorn/test/script/basic/jsadapter.js create mode 100644 nashorn/test/script/basic/jsadapter.js.EXPECTED create mode 100644 nashorn/test/script/basic/jsadapterlink.js create mode 100644 nashorn/test/script/basic/jsadapterlink.js.EXPECTED create mode 100644 nashorn/test/script/basic/json.js create mode 100644 nashorn/test/script/basic/json.js.EXPECTED create mode 100644 nashorn/test/script/basic/list.js create mode 100644 nashorn/test/script/basic/list.js.EXPECTED create mode 100644 nashorn/test/script/basic/literal.js create mode 100644 nashorn/test/script/basic/literal.js.EXPECTED create mode 100644 nashorn/test/script/basic/load.js create mode 100644 nashorn/test/script/basic/load.js.EXPECTED create mode 100644 nashorn/test/script/basic/loadedfile.js create mode 100644 nashorn/test/script/basic/localundef.js create mode 100644 nashorn/test/script/basic/localundef.js.EXPECTED create mode 100644 nashorn/test/script/basic/map.js create mode 100644 nashorn/test/script/basic/map.js.EXPECTED create mode 100644 nashorn/test/script/basic/math.js create mode 100644 nashorn/test/script/basic/math.js.EXPECTED create mode 100644 nashorn/test/script/basic/minuszero.js create mode 100644 nashorn/test/script/basic/minuszero.js.EXPECTED create mode 100644 nashorn/test/script/basic/module.js create mode 100644 nashorn/test/script/basic/moduleload.js create mode 100644 nashorn/test/script/basic/moduleload.js.EXPECTED create mode 100644 nashorn/test/script/basic/nashorn2.js create mode 100644 nashorn/test/script/basic/nashorn2.js.EXPECTED create mode 100644 nashorn/test/script/basic/natives.js create mode 100644 nashorn/test/script/basic/natives.js.EXPECTED create mode 100644 nashorn/test/script/basic/new.js create mode 100644 nashorn/test/script/basic/new.js.EXPECTED create mode 100644 nashorn/test/script/basic/newexpr.js create mode 100644 nashorn/test/script/basic/newexpr.js.EXPECTED create mode 100644 nashorn/test/script/basic/newnew.js create mode 100644 nashorn/test/script/basic/newnew.js.EXPECTED create mode 100644 nashorn/test/script/basic/nonconstructors.js create mode 100644 nashorn/test/script/basic/nonconstructors.js.EXPECTED create mode 100644 nashorn/test/script/basic/nosuchmethod.js create mode 100644 nashorn/test/script/basic/nosuchmethod.js.EXPECTED create mode 100644 nashorn/test/script/basic/nosuchproperty.js create mode 100644 nashorn/test/script/basic/nosuchproperty.js.EXPECTED create mode 100644 nashorn/test/script/basic/number.js create mode 100644 nashorn/test/script/basic/number.js.EXPECTED create mode 100644 nashorn/test/script/basic/numberstring.js create mode 100644 nashorn/test/script/basic/numberstring.js.EXPECTED create mode 100644 nashorn/test/script/basic/objectprops.js create mode 100644 nashorn/test/script/basic/objectprops.js.EXPECTED create mode 100644 nashorn/test/script/basic/objects.js create mode 100644 nashorn/test/script/basic/objects.js.EXPECTED create mode 100644 nashorn/test/script/basic/options.js create mode 100644 nashorn/test/script/basic/options.js.EXPECTED create mode 100644 nashorn/test/script/basic/propchange.js create mode 100644 nashorn/test/script/basic/propchange.js.EXPECTED create mode 100644 nashorn/test/script/basic/propertycheck.js create mode 100644 nashorn/test/script/basic/propertycheck.js.EXPECTED create mode 100644 nashorn/test/script/basic/proto.js.EXPECTED create mode 100644 nashorn/test/script/basic/prototype.js create mode 100644 nashorn/test/script/basic/prototype.js.EXPECTED create mode 100644 nashorn/test/script/basic/pushpull.js create mode 100644 nashorn/test/script/basic/pushpull.js.EXPECTED create mode 100644 nashorn/test/script/basic/regex.js create mode 100644 nashorn/test/script/basic/regex.js.EXPECTED create mode 100644 nashorn/test/script/basic/regexp_flags.js create mode 100644 nashorn/test/script/basic/run-octane.js create mode 100644 nashorn/test/script/basic/runsunspider.js create mode 100644 nashorn/test/script/basic/runsunspider.js.EXPECTED create mode 100644 nashorn/test/script/basic/samfunc.js create mode 100644 nashorn/test/script/basic/samfunc.js.EXPECTED create mode 100644 nashorn/test/script/basic/scripting.js create mode 100644 nashorn/test/script/basic/scripting.js.EXPECTED create mode 100644 nashorn/test/script/basic/sealfreeze.js create mode 100644 nashorn/test/script/basic/sealfreeze.js.EXPECTED create mode 100644 nashorn/test/script/basic/setlength.js create mode 100644 nashorn/test/script/basic/setlength.js.EXPECTED create mode 100644 nashorn/test/script/basic/stdin.js create mode 100644 nashorn/test/script/basic/stdin.js.EXPECTED create mode 100644 nashorn/test/script/basic/strings.js create mode 100644 nashorn/test/script/basic/strings.js.EXPECTED create mode 100644 nashorn/test/script/basic/throws.js create mode 100644 nashorn/test/script/basic/throws.js.EXPECTED create mode 100644 nashorn/test/script/basic/tosource.js create mode 100644 nashorn/test/script/basic/tosource.js.EXPECTED create mode 100644 nashorn/test/script/basic/tostring.js create mode 100644 nashorn/test/script/basic/tostring.js.EXPECTED create mode 100644 nashorn/test/script/basic/try.js create mode 100644 nashorn/test/script/basic/try.js.EXPECTED create mode 100644 nashorn/test/script/basic/trybreakcont.js create mode 100644 nashorn/test/script/basic/trybreakcont.js.EXPECTED create mode 100644 nashorn/test/script/basic/trycatch.js create mode 100644 nashorn/test/script/basic/trycatch.js.EXPECTED create mode 100644 nashorn/test/script/basic/trycatchfor.js create mode 100644 nashorn/test/script/basic/trycatchfor.js.EXPECTED create mode 100644 nashorn/test/script/basic/tryfinallyreturn.js create mode 100644 nashorn/test/script/basic/tryfinallyreturn.js.EXPECTED create mode 100644 nashorn/test/script/basic/tryforbreak.js create mode 100644 nashorn/test/script/basic/tryforbreak.js.EXPECTED create mode 100644 nashorn/test/script/basic/typechange.js create mode 100644 nashorn/test/script/basic/typechange.js.EXPECTED create mode 100644 nashorn/test/script/basic/typeof.js create mode 100644 nashorn/test/script/basic/typeof.js.EXPECTED create mode 100644 nashorn/test/script/basic/typeof2.js create mode 100644 nashorn/test/script/basic/typeof2.js.EXPECTED create mode 100644 nashorn/test/script/basic/undefined.js create mode 100644 nashorn/test/script/basic/undefined.js.EXPECTED create mode 100644 nashorn/test/script/basic/underscore.js create mode 100644 nashorn/test/script/basic/underscore.js.EXPECTED create mode 100644 nashorn/test/script/basic/varargs.js create mode 100644 nashorn/test/script/basic/varargs.js.EXPECTED create mode 100644 nashorn/test/script/basic/void.js create mode 100644 nashorn/test/script/basic/void.js.EXPECTED create mode 100644 nashorn/test/script/basic/with.js create mode 100644 nashorn/test/script/basic/with.js.EXPECTED create mode 100644 nashorn/test/script/basic/withprimitive.js create mode 100644 nashorn/test/script/basic/withprimitive.js.EXPECTED create mode 100644 nashorn/test/script/basic/writable_relink.js create mode 100644 nashorn/test/script/basic/writable_relink.js.EXPECTED create mode 100644 nashorn/test/script/basic/xmlStrings.js.EXPECTED create mode 100644 nashorn/test/script/basic/xorassign.js create mode 100644 nashorn/test/script/basic/xorassign.js.EXPECTED create mode 100644 nashorn/test/script/basic/yui.js create mode 100644 nashorn/test/script/basic/yui.js.EXPECTED create mode 100644 nashorn/test/script/error/NASHORN-154/README create mode 100644 nashorn/test/script/error/NASHORN-154/function_mult_params_in_strict.js create mode 100644 nashorn/test/script/error/NASHORN-154/function_mult_params_in_strict.js.EXPECTED create mode 100644 nashorn/test/script/error/NASHORN-154/improper_return_break_continue.js create mode 100644 nashorn/test/script/error/NASHORN-154/improper_return_break_continue.js.EXPECTED create mode 100644 nashorn/test/script/error/NASHORN-154/invalid_lvalue.js create mode 100644 nashorn/test/script/error/NASHORN-154/invalid_lvalue.js.EXPECTED create mode 100644 nashorn/test/script/error/NASHORN-154/literal_data_and_accessor.js create mode 100644 nashorn/test/script/error/NASHORN-154/literal_data_and_accessor.js.EXPECTED create mode 100644 nashorn/test/script/error/NASHORN-154/literal_mult_getters.js create mode 100644 nashorn/test/script/error/NASHORN-154/literal_mult_getters.js.EXPECTED create mode 100644 nashorn/test/script/error/NASHORN-154/literal_mult_prop_in_strict.js create mode 100644 nashorn/test/script/error/NASHORN-154/literal_mult_prop_in_strict.js.EXPECTED create mode 100644 nashorn/test/script/error/NASHORN-154/with_in_strict.js create mode 100644 nashorn/test/script/error/NASHORN-154/with_in_strict.js.EXPECTED create mode 100644 nashorn/test/script/error/NASHORN-214.js create mode 100644 nashorn/test/script/error/NASHORN-214.js.EXPECTED create mode 100644 nashorn/test/script/error/NASHORN-35.js create mode 100644 nashorn/test/script/error/NASHORN-35.js.EXPECTED create mode 100644 nashorn/test/script/error/NASHORN-39.js create mode 100644 nashorn/test/script/error/NASHORN-39.js.EXPECTED create mode 100644 nashorn/test/script/error/NASHORN-568.js create mode 100644 nashorn/test/script/error/NASHORN-568.js.EXPECTED create mode 100644 nashorn/test/script/error/NASHORN-57.js create mode 100644 nashorn/test/script/error/NASHORN-57.js.EXPECTED create mode 100644 nashorn/test/script/error/NASHORN-668.js create mode 100644 nashorn/test/script/error/NASHORN-668.js.EXPECTED create mode 100644 nashorn/test/script/error/quotemissing.js create mode 100644 nashorn/test/script/error/quotemissing.js.EXPECTED create mode 100644 nashorn/test/script/error/strictmode.js create mode 100644 nashorn/test/script/error/strictmode.js.EXPECTED create mode 100644 nashorn/test/script/representations/NASHORN-592a.js create mode 100644 nashorn/test/script/sandbox/NASHORN-525.js create mode 100644 nashorn/test/script/sandbox/README create mode 100644 nashorn/test/script/sandbox/classloader.js create mode 100644 nashorn/test/script/sandbox/classloader.js.EXPECTED create mode 100644 nashorn/test/script/sandbox/doprivileged.js create mode 100644 nashorn/test/script/sandbox/doprivileged.js.EXPECTED create mode 100644 nashorn/test/script/sandbox/exit.js create mode 100644 nashorn/test/script/sandbox/exit.js.EXPECTED create mode 100644 nashorn/test/script/sandbox/file.js create mode 100644 nashorn/test/script/sandbox/file.js.EXPECTED create mode 100644 nashorn/test/script/sandbox/javaextend.js create mode 100644 nashorn/test/script/sandbox/javaextend.js.EXPECTED create mode 100644 nashorn/test/script/sandbox/loadLibrary.js create mode 100644 nashorn/test/script/sandbox/net.js create mode 100644 nashorn/test/script/sandbox/net.js.EXPECTED create mode 100644 nashorn/test/script/sandbox/property.js create mode 100644 nashorn/test/script/sandbox/property.js.EXPECTED create mode 100644 nashorn/test/script/sandbox/reflection.js create mode 100644 nashorn/test/script/sandbox/reflection.js.EXPECTED create mode 100644 nashorn/test/script/sandbox/runnable.js create mode 100644 nashorn/test/script/sandbox/runnable.js.EXPECTED create mode 100644 nashorn/test/script/sandbox/unsafe.js create mode 100644 nashorn/test/script/sandbox/unsafe.js.EXPECTED create mode 100644 nashorn/test/script/test262.js create mode 100644 nashorn/test/script/test262_single.js create mode 100644 nashorn/test/src/UnnamedPackageTestCallback.java create mode 100644 nashorn/test/src/jdk/nashorn/api/scripting/MultipleEngineTest.java create mode 100644 nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java create mode 100644 nashorn/test/src/jdk/nashorn/api/scripting/Window.java create mode 100644 nashorn/test/src/jdk/nashorn/api/scripting/WindowEventHandler.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/access/BooleanAccessTest.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/access/MethodAccessTest.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/access/NumberAccessTest.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/access/NumberBoxingTest.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/access/ObjectAccessTest.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/access/Person.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/access/SharedObject.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/access/StringAccessTest.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/performance/AuroraWrapper.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/performance/OctaneTest.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/performance/PerformanceWrapper.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/performance/SplayTest.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/runtime/JSTypeTest.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/runtime/Nashorn401TestSubject.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/framework/AbstractScriptRunnable.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/framework/JSJUnitReportReporter.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/framework/OrphanTestFinder.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/framework/ScriptEvaluator.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/framework/ScriptTest.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/framework/SeparateContextEvaluator.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/framework/TestConfig.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/framework/TestFinder.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/framework/TestHelper.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/framework/TestReorderInterceptor.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/models/ConstructorWithArgument.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/models/FinalClass.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/models/NoAccessibleConstructorClass.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/models/NonPublicClass.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/models/OuterClass.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/models/OverloadedSam.java create mode 100644 nashorn/test/src/jdk/nashorn/internal/test/models/OverrideObject.java diff --git a/nashorn/.hgignore b/nashorn/.hgignore index 83cef213d48..fe2082c8702 100644 --- a/nashorn/.hgignore +++ b/nashorn/.hgignore @@ -1,4 +1,25 @@ +syntax: glob + ^build/ ^dist/ -/nbproject/private/ ^.hgtip +/nbproject/private/ +^webrev/ +webrev.zip +*.class +*.log +*.orig +hotspot.log +private.properties +genfiles.properties +private.xml +.DS_Store* +TEST-*.xml +TESTS-*.xml +report.xml +CC/ +jcov2/ +buildtools/nasgen/nbproject/private/ +buildtools/nasgen/dist/ +buildtools/nasgen/build/ +.idea/* diff --git a/nashorn/ASSEMBLY_EXCEPTION b/nashorn/ASSEMBLY_EXCEPTION new file mode 100644 index 00000000000..8b7ac1d0813 --- /dev/null +++ b/nashorn/ASSEMBLY_EXCEPTION @@ -0,0 +1,27 @@ + +OPENJDK ASSEMBLY EXCEPTION + +The OpenJDK source code made available by Sun at openjdk.java.net and +openjdk.dev.java.net ("OpenJDK Code") is distributed under the terms of the +GNU General Public License version 2 +only ("GPL2"), with the following clarification and special exception. + + Linking this OpenJDK Code statically or dynamically with other code + is making a combined work based on this library. Thus, the terms + and conditions of GPL2 cover the whole combination. + + As a special exception, Sun gives you permission to link this + OpenJDK Code with certain code licensed by Sun as indicated at + http://openjdk.java.net/legal/exception-modules-2007-05-08.html + ("Designated Exception Modules") to produce an executable, + regardless of the license terms of the Designated Exception Modules, + and to copy and distribute the resulting executable under GPL2, + provided that the Designated Exception Modules continue to be + governed by the licenses under which they were offered by Sun. + +As such, it allows licensees and sublicensees of Sun's GPL2 OpenJDK Code to +build an executable that includes those portions of necessary code that Sun +could not provide under GPL2 (or that Sun has provided under GPL2 with the +Classpath exception). If you modify or add to the OpenJDK code, that new +GPL2 code may still be combined with Designated Exception Modules if the +new code is made subject to this exception by its copyright holder. diff --git a/nashorn/LICENSE b/nashorn/LICENSE new file mode 100644 index 00000000000..b40a0f457d7 --- /dev/null +++ b/nashorn/LICENSE @@ -0,0 +1,347 @@ +The GNU General Public License (GPL) + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public License is intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. This General Public License applies to +most of the Free Software Foundation's software and to any other program whose +authors commit to using it. (Some other Free Software Foundation software is +covered by the GNU Library General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom to +distribute copies of free software (and charge for this service if you wish), +that you receive source code or can get it if you want it, that you can change +the software or use pieces of it in new free programs; and that you know you +can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny +you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of the +software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for +a fee, you must give the recipients all the rights that you have. You must +make sure that they, too, receive or can get the source code. And you must +show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) +offer you this license which gives you legal permission to copy, distribute +and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. If the +software is modified by someone else and passed on, we want its recipients to +know that what they have is not the original, so that any problems introduced +by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We +wish to avoid the danger that redistributors of a free program will +individually obtain patent licenses, in effect making the program proprietary. +To prevent this, we have made it clear that any patent must be licensed for +everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification +follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice +placed by the copyright holder saying it may be distributed under the terms of +this General Public License. The "Program", below, refers to any such program +or work, and a "work based on the Program" means either the Program or any +derivative work under copyright law: that is to say, a work containing the +Program or a portion of it, either verbatim or with modifications and/or +translated into another language. (Hereinafter, translation is included +without limitation in the term "modification".) Each licensee is addressed as +"you". + +Activities other than copying, distribution and modification are not covered by +this License; they are outside its scope. The act of running the Program is +not restricted, and the output from the Program is covered only if its contents +constitute a work based on the Program (independent of having been made by +running the Program). Whether that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code as +you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this License +and to the absence of any warranty; and give any other recipients of the +Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may +at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, thus +forming a work based on the Program, and copy and distribute such modifications +or work under the terms of Section 1 above, provided that you also meet all of +these conditions: + + a) You must cause the modified files to carry prominent notices stating + that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in whole or + in part contains or is derived from the Program or any part thereof, to be + licensed as a whole at no charge to all third parties under the terms of + this License. + + c) If the modified program normally reads commands interactively when run, + you must cause it, when started running for such interactive use in the + most ordinary way, to print or display an announcement including an + appropriate copyright notice and a notice that there is no warranty (or + else, saying that you provide a warranty) and that users may redistribute + the program under these conditions, and telling the user how to view a copy + of this License. (Exception: if the Program itself is interactive but does + not normally print such an announcement, your work based on the Program is + not required to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Program, and can be reasonably +considered independent and separate works in themselves, then this License, and +its terms, do not apply to those sections when you distribute them as separate +works. But when you distribute the same sections as part of a whole which is a +work based on the Program, the distribution of the whole must be on the terms +of this License, whose permissions for other licensees extend to the entire +whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise the +right to control the distribution of derivative or collective works based on +the Program. + +In addition, mere aggregation of another work not based on the Program with the +Program (or with a work based on the Program) on a volume of a storage or +distribution medium does not bring the other work under the scope of this +License. + +3. You may copy and distribute the Program (or a work based on it, under +Section 2) in object code or executable form under the terms of Sections 1 and +2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable source + code, which must be distributed under the terms of Sections 1 and 2 above + on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three years, to + give any third party, for a charge no more than your cost of physically + performing source distribution, a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of Sections 1 + and 2 above on a medium customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer to + distribute corresponding source code. (This alternative is allowed only + for noncommercial distribution and only if you received the program in + object code or executable form with such an offer, in accord with + Subsection b above.) + +The source code for a work means the preferred form of the work for making +modifications to it. For an executable work, complete source code means all +the source code for all modules it contains, plus any associated interface +definition files, plus the scripts used to control compilation and installation +of the executable. However, as a special exception, the source code +distributed need not include anything that is normally distributed (in either +source or binary form) with the major components (compiler, kernel, and so on) +of the operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the source +code from the same place counts as distribution of the source code, even though +third parties are not compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as +expressly provided under this License. Any attempt otherwise to copy, modify, +sublicense or distribute the Program is void, and will automatically terminate +your rights under this License. However, parties who have received copies, or +rights, from you under this License will not have their licenses terminated so +long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed it. +However, nothing else grants you permission to modify or distribute the Program +or its derivative works. These actions are prohibited by law if you do not +accept this License. Therefore, by modifying or distributing the Program (or +any work based on the Program), you indicate your acceptance of this License to +do so, and all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), +the recipient automatically receives a license from the original licensor to +copy, distribute or modify the Program subject to these terms and conditions. +You may not impose any further restrictions on the recipients' exercise of the +rights granted herein. You are not responsible for enforcing compliance by +third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), conditions +are imposed on you (whether by court order, agreement or otherwise) that +contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot distribute so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not distribute the Program at all. +For example, if a patent license would not permit royalty-free redistribution +of the Program by all those who receive copies directly or indirectly through +you, then the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply and +the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or +other property right claims or to contest validity of any such claims; this +section has the sole purpose of protecting the integrity of the free software +distribution system, which is implemented by public license practices. Many +people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose that +choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original +copyright holder who places the Program under this License may add an explicit +geographical distribution limitation excluding those countries, so that +distribution is permitted only in or among countries not thus excluded. In +such case, this License incorporates the limitation as if written in the body +of this License. + +9. The Free Software Foundation may publish revised and/or new versions of the +General Public License from time to time. Such new versions will be similar in +spirit to the present version, but may differ in detail to address new problems +or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any later +version", you have the option of following the terms and conditions either of +that version or of any later version published by the Free Software Foundation. +If the Program does not specify a version number of this License, you may +choose any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs +whose distribution conditions are different, write to the author to ask for +permission. For software which is copyrighted by the Free Software Foundation, +write to the Free Software Foundation; we sometimes make exceptions for this. +Our decision will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing and reuse of +software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE +PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, +YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL +ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE +PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR +INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA +BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER +OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible +use to the public, the best way to achieve this is to make it free software +which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach +them to the start of each source file to most effectively convey the exclusion +of warranty; and each file should have at least the "copyright" line and a +pointer to where the full notice is found. + + One line to give the program's name and a brief idea of what it does. + + Copyright (C) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program 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 for + more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this when it +starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes + with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free + software, and you are welcome to redistribute it under certain conditions; + type 'show c' for details. + +The hypothetical commands 'show w' and 'show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may be +called something other than 'show w' and 'show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the program, if necessary. Here +is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + 'Gnomovision' (which makes passes at compilers) written by James Hacker. + + signature of Ty Coon, 1 April 1989 + + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General Public +License instead of this License. + + +"CLASSPATH" EXCEPTION TO THE GPL + +Certain source files distributed by Oracle America and/or its affiliates are +subject to the following clarification and special exception to the GPL, but +only where Oracle has expressly included in the particular source file's header +the words "Oracle designates this particular file as subject to the "Classpath" +exception as provided by Oracle in the LICENSE file that accompanied this code." + + Linking this library statically or dynamically with other modules is making + a combined work based on this library. Thus, the terms and conditions of + the GNU General Public License cover the whole combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent modules, + and to copy and distribute the resulting executable under terms of your + choice, provided that you also meet, for each linked independent module, + the terms and conditions of the license of that module. An independent + module is a module which is not derived from or based on this library. If + you modify this library, you may extend this exception to your version of + the library, but you are not obligated to do so. If you do not wish to do + so, delete this exception statement from your version. diff --git a/nashorn/README b/nashorn/README new file mode 100644 index 00000000000..52b30919065 --- /dev/null +++ b/nashorn/README @@ -0,0 +1,147 @@ +- What is Nashorn? + +Nashorn is a runtime environment for programs written in ECMAScript 5.1 +that runs on top of JVM. + +- How to find out more about ECMAScript 5.1? + +The specification can be found at + + http://www.ecma-international.org/publications/standards/Ecma-262.htm + +- How to checkout sources of Nashorn project? + +Nashorn project uses Mercurial source code control system. You can +download Mercurial from http://mercurial.selenic.com/wiki/Download + +Information about the forest extension can be found at + + http://mercurial.selenic.com/wiki/ForestExtension + +and downlaoded using + + hg clone https://bitbucket.org/gxti/hgforest + +You can clone Nashorn Mercurial forest using this command: + + hg fclone http://hg.openjdk.java.net/nashorn/jdk8 nashorn~jdk8 + +To update your copy of the forest (fwith the latest code: + + (cd nashorn~jdk8 ; hg fpull) + +Or just the nashorn subdirectory with + + (cd nashorn~jdk8/nashorn ; hg pull -u) + +To learn about Mercurial in detail, please visit http://hgbook.red-bean.com. + +- How to build? + +To build Nashorn, you need to install JDK 8. You may use the Nashorn +forest build (recommended) or down load from java.net. You will need to +set JAVA_HOME environmental variable to point to your JDK installation +directory. + + cd nashorn~jdk8/nashorn/make + ant clean; ant + +- How to run? + +Use the jjs script (see RELESE_README): + + cd nashorn~jdk8/nashorn + sh bin/jjs + +Nashorn supports javax.script API. It is possible to drop nashorn.jar in +class path and request for "nashorn" script engine from +javax.script.ScriptEngineManager. + +Look for samples under the directory test/src/jdk/nashorn/api/scripting/. + +- Documentation + +Comprehensive development documentation is found in the Nashorn JavaDoc. You can +build it using: + + cd nashorn~jdk8/nashorn/make + ant javadoc + +after which you can view the generated documentation at dist/javadoc/index.html. + +- Running tests + +Nashorn tests are TestNG based. Running tests requires downloading the +TestNG library and placing its jar file into the lib subdirectory: + + # download and install TestNG + wget http://testng.org/testng-x.y.z.zip + unzip testng-x.y.z.zip + cp testng-x.y.z/testng-x.y.z.jar test/lib/testng.jar + +After that, you can run the tests using: + cd make + ant test + +You can also run the ECMA-262 test suite with Nashorn. In order to do +that, you will need to get a copy of it and put it in +test/script/external/test262 directory. A convenient way to do it is: + + hg clone http://hg.ecmascript.org/tests/test262/ test/script/external/test262 + +Alternatively, you can check it out elsewhere and make +test/script/external/test262 a symbolic link to that directory. After +you've done this, you can run the ECMA-262 tests using: + + cd nashorn~jdk8/nashorn/make + ant test262 + +These tests take time, so we have a parallelized runner for them that +takes advantage of all processor cores on the computer: + + cd nashorn~jdk8/nashorn/make + ant test262parallel + +- How to write your own test? + +Nashorn uses it's own simple test framework. Any .js file dropped under +nashorn/test directory is considered as a test. A test file can +optionally have .js.EXPECTED (foo.js.EXPECTED for foo.js) associated +with it. The .EXPECTED file, if exists, should contain the output +expected from compiling and/or running the test file. + +The test runner crawls these directories for .js files and looks for +JTReg-style @foo comments to identify tests. + + * @test - A test is tagged with @test. + + * @test/fail - Tests that are supposed to fail (compiling, see @run/fail + for runtime) are tagged with @test/fail. + + * @test/compile-error - Test expects compilation to fail, compares + output. + + * @test/warning - Test expects compiler warnings, compares output. + + * @test/nocompare - Test expects to compile [and/or run?] + successfully(may be warnings), does not compare output. + + * @subtest - denotes necessary file for a main test file; itself is not + a test. + + * @run - A test that should be run is also tagged with @run (otherwise + the test runner only compiles the test). + + * @run/fail - A test that should compile but fail with a runtime error. + + * @run/ignore-std-error - script may produce output on stderr, ignore + this output. + + * @argument - pass an argument to script. + + * @option \ - pass option to engine, sample. + +/** + * @option --dump-ir-graph + * @test + */ diff --git a/nashorn/RELEASE_README b/nashorn/RELEASE_README new file mode 100644 index 00000000000..9984be4ce32 --- /dev/null +++ b/nashorn/RELEASE_README @@ -0,0 +1,20 @@ +The Nashorn repo is in the process of being migrated to OpenJDK and as such is +incomplete in several areas. + +- The build system is not fully integrated. When complete, Nashorn will be +installed in its proper location in the JRE. + +- Once integrated, the correct version of the JDK will be wrapped around +Nashorn. In the meantime, ensure you use JDK8 b68 or later. + +- The jjs tool has not been implemented in binary form yet. Use "sh bin/jjs" +(or bin/jjs.bat on windows) in the interm. + +- The Dynalink component is not fully integrated into Nashorn as yet, but will +be when details are finalized. + +- And, finally Nashorn is still in development. To stay up to date, subscribe +to nashorn-dev@openjdk.java.net at + + http://mail.openjdk.java.net/mailman/listinfo/nashorn-dev. + diff --git a/nashorn/THIRD_PARTY_README b/nashorn/THIRD_PARTY_README new file mode 100644 index 00000000000..44318349aed --- /dev/null +++ b/nashorn/THIRD_PARTY_README @@ -0,0 +1,69 @@ +DO NOT TRANSLATE OR LOCALIZE. +----------------------------- + +%% This notice is provided with respect to ECMAScript Language +Specification ECMA-262 Edition 5.1 which is included with the Nashorn +technology. + +--- begin of LICENSE --- +Copyright notice +Copyright © 2011 Ecma International +Ecma International +Rue du Rhone 114 +CH-1204 Geneva +Tel: +41 22 849 6000 +Fax: +41 22 849 6001 +Web: http://www.ecma-international.org + +This document and possible translations of it may be copied and furnished to +others, and derivative works that comment on or otherwise explain it or assist +in its implementation may be prepared, copied, published, and distributed, in +whole or in part, without restriction of any kind, provided that the above +copyright notice and this section are included on all such copies and derivative +works. However, this document itself may not be modified in any way, including +by removing the copyright notice or references to Ecma International, except as +needed for the purpose of developing any document or deliverable produced by +Ecma International (in which case the rules applied to copyrights must be +followed) or as required to translate it into languages other than English. The +limited permissions granted above are perpetual and will not be revoked by Ecma +International or its successors or assigns. This document and the information +contained herein is provided on an "AS IS" basis and ECMA INTERNATIONAL +DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY +WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY OWNERSHIP +RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR +PURPOSE." Software License + +All Software contained in this document ("Software)" is protected by copyright +and is being made available under the "BSD License", included below. This +Software may be subject to third party rights (rights from parties other than +Ecma International), including patent rights, and no licenses under such third +party rights are granted under this license even if the third party concerned is +a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS +AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR +INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO +IMPLEMENT ECMA INTERNATIONAL STANDARDS*. Redistribution and use in source and +binary forms, with or without modification, are permitted provided that the +following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the authors nor Ecma International may be used to endorse +or promote products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "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 ECMA INTERNATIONAL 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. +--- end of LICENSE --- diff --git a/nashorn/bin/checkintest.sh b/nashorn/bin/checkintest.sh new file mode 100644 index 00000000000..a4750d5888e --- /dev/null +++ b/nashorn/bin/checkintest.sh @@ -0,0 +1,266 @@ +#!/bin/bash +# +# Copyright (c) 2010, 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. +# + +#best pass rate at test 262 known +TEST262_PASS_AT_LEAST=435 + +RUN_TEST="true" +RUN_TEST262="true" +RUN_NODE="true" +KEEP_OUTPUT="true" +CLEAN_AND_BUILD_NASHORN="true" + +#the stable node version to sync against +NODE_LAST_STABLE=v0.6.18 + +#parse args +for arg in $* +do + if [ $arg = "--no-test" ]; then + RUN_TEST="false" + echo "**** WARNING - you have disabled 'ant test', which is a minimum checkin requirement..." + elif [ $arg = "--no-262" ]; then + RUN_TEST262="false" + elif [ $arg = "--no-node" ]; then + RUN_NODE="false" + elif [ $arg = "--no-build" ]; then + CLEAN_AND_BUILD_NASHORN="false" + elif [ $arg = "--no-logs" ]; then + KEEP_OUTPUT="false" + fi +done + +function lastpart() { + arr=$(echo $1 | tr "/" "\n") + for x in $arr + do + _last=$x + done + echo $_last +} + +function check_installed() { + which $1 >/dev/null + if [ $? -ne 0 ]; then + echo "Error $1 not installed: $?" + exit 2 + fi +} + +check_installed hg +check_installed git +check_installed mv +check_installed git + +PWD=$(pwd); + +while [ -z $NASHORN_ROOT ] +do + if [ -e $PWD/.hg ]; then + NASHORN_ROOT=${PWD} + break + fi + PWD=$(dirname ${PWD}) +done + +echo "Nashorn root detected at ${NASHORN_ROOT}" + +COMMON_ROOT=$(dirname $NASHORN_ROOT) +echo "Common root is ${COMMON_ROOT}" + +echo "Running checkintest..." + +ABSOLUTE_NASHORN_HOME=$COMMON_ROOT/$(lastpart $NASHORN_ROOT) + +if [ $CLEAN_AND_BUILD_NASHORN != "false" ]; then + echo "Cleaning and building nashorn at $ABSOLUTE_NASHORN_HOME/nashorn..." + $(cd $ABSOLUTE_NASHORN_HOME/nashorn; ant clean >/dev/null 2>/dev/null) + $(cd $ABSOLUTE_NASHORN_HOME/nashorn; ant jar >/dev/null 2>/dev/null) + echo "Done." +fi + +function failure_check() { + while read line + do + LINE=$(echo $line | grep "Tests run") + if [ "${LINE}" != "" ]; then + RESULT=$(echo $line | grep "Failures: 0" | grep "Errors: 0") + if [ "${RESULT}" == "" ]; then + TESTNAME=$2 + echo "There were errors in ${TESTNAME} : ${LINE}" + exit 1 + fi + fi + done < $1 +} + +function test() { + TEST_OUTPUT=$ABSOLUTE_NASHORN_HOME/$(mktemp tmp.XXXXX) + echo "Running 'ant test' on nashorn from ${ABSOLUTE_NASHORN_HOME}/nashorn..." + $(cd $ABSOLUTE_NASHORN_HOME/nashorn; ant test >$TEST_OUTPUT) + echo "Done." + + failure_check $TEST_OUTPUT + + echo "**** SUCCESS: 'ant test' successful" + + if [ $KEEP_OUTPUT == "true" ]; then + cp $TEST_OUTPUT ./checkintest.test.log + rm -fr $TEST_OUTPUT + fi +} + +if [ $RUN_TEST != "false" ]; then + test; +fi + +function test262() { + + echo "Running 'ant test262parallel' on nashorn from ${ABSOLUTE_NASHORN_HOME}/nashorn..." + TEST262_OUTPUT=$ABSOLUTE_NASHORN_HOME/$(mktemp tmp.XXXXX) + + echo "Looking for ${ABSOLUTE_NASHORN_HOME}/test/test262..." + + if [ ! -e $ABSOLUTE_NASHORN_HOME/nashorn/test/test262 ]; then + echo "test262 is missing... looking in $COMMON_ROOT..." + if [ ! -e $COMMON_ROOT/test262 ]; then + echo "... not there either... cloning from repo..." + hg clone http://hg.ecmascript.org/tests/test262 $COMMON_ROOT/test262 >/dev/null 2>/dev/null + echo "Done." + fi + echo "Adding soft link ${COMMON_ROOT}/test262 -> ${ABSOLUTE_NASHORN_HOME}/test/test262..." + ln -s $COMMON_ROOT/test262 $ABSOLUTE_NASHORN_HOME/nashorn/test/test262 + echo "Done." + fi + + echo "Ensuring test262 is up to date..." + $(cd $ABSOLUTE_NASHORN_HOME/nashorn/test/test262; hg pull -u >/dev/null 2>/dev/null) + echo "Done." + + echo "Running test262..." + $(cd $ABSOLUTE_NASHORN_HOME/nashorn; ant test262parallel > $TEST262_OUTPUT) + + FAILED=$(cat $TEST262_OUTPUT|grep "Tests run:"| cut -d ' ' -f 15 |tr -cd '"[[:digit:]]') + if [ $FAILED -gt $TEST262_PASS_AT_LEAST ]; then + echo "FAILURE: There are ${FAILED} failures in test262 and can be no more than ${TEST262_PASS_AT_LEAST}" + cp $TEST262_OUTPUT ./checkintest.test262.log + echo "See ./checkintest.test262.log" + echo "Terminating due to error" + exit 1 + elif [ $FAILED -lt $TEST262_PASS_AT_LEAST ]; then + echo "There seem to have been fixes to 262. ${FAILED} < ${TEST262_PASS_AT_LEAST}. Please update limit in bin/checkintest.sh" + fi + + echo "**** SUCCESS: Test262 passed with no more than ${TEST262_PASS_AT_LEAST} failures." + + if [ $KEEP_OUTPUT == "true" ]; then + cp $TEST262_OUTPUT ./checkintest.test262.log + rm -fr $TEST262_OUTPUT + fi +} + +if [ $RUN_TEST262 != "false" ]; then + test262; +fi; + +function testnode() { + TESTNODEJAR_OUTPUT=$ABSOLUTE_NASHORN_HOME/$(mktemp tmp.XXXXX) + + echo "Running node tests..." +#replace node jar properties nashorn with this nashorn + + NODEJAR_PROPERTIES=~/nodejar.properties + + NODE_HOME=$(cat $NODEJAR_PROPERTIES | grep ^node.home | cut -f2 -d=) + NASHORN_HOME=$(cat $NODEJAR_PROPERTIES | grep ^nashorn.home | cut -f2 -d=) + + ABSOLUTE_NODE_HOME=$COMMON_ROOT/$(lastpart $NODE_HOME) + + echo "Writing nodejar.properties..." + + cat > $NODEJAR_PROPERTIES << EOF +node.home=../node +nashorn.home=../$(lastpart $NASHORN_ROOT) +EOF + echo "Done." + echo "Checking node home ${ABSOLUTE_NODE_HOME}..." + + if [ ! -e $ABSOLUTE_NODE_HOME ]; then + echo "Node base dir not found. Cloning node..." + $(cd $COMMON_ROOT; git clone https://github.com/joyent/node.git $(lastpart $NODE_HOME) >/dev/null 2>/dev/null) + echo "Done." + echo "Updating to last stable version ${NODE_LAST_STABLE}..." + $(cd $ABSOLUTE_NODE_HOME; git checkout $NODE_LAST_STABLE >/dev/null 2>/dev/null) + echo "Done." + echo "Running configure..." + $(cd $ABSOLUTE_NODE_HOME; ./configure >/dev/null 2>/dev/null) + echo "Done." + fi + + echo "Ensuring node is built..." +#make sure node is built + $(cd $ABSOLUTE_NODE_HOME; make >/dev/null 2>/dev/null) + echo "Done." + + NODEJAR_HOME=$COMMON_ROOT/nodejar + + if [ ! -e $NODEJAR_HOME ]; then + echo "No node jar home found. cloning from depot..." + $(cd $COMMON_ROOT; hg clone https://hg.kenai.com/hg/nodejs~source nodejar >/dev/null 2>/dev/null) + $(cd $COMMON_ROOT/nodejar; ant >/dev/null) + echo "Done." + echo "Copying node files..." + $(cd $COMMON_ROOT/nodejar; ant copy-node-files >/dev/null 2>/dev/null) + echo "Patching node files..." + $(cd $COMMON_ROOT/nodejar; ant patch-node-files >/dev/null 2>/dev/null) + echo "Done." + fi + + echo "Ensuring node.jar is up to date from source depot..." + $(cd $COMMON_ROOT/nodejar; hg pull -u >/dev/null 2>/dev/null) + echo "Done." + + echo "Installing nashorn..." + $(cd $COMMON_ROOT/nodejar; ant >/dev/null) + echo "Done." + + echo "Running node.jar test..." + $(cd $COMMON_ROOT/nodejar; mvn clean verify >$TESTNODEJAR_OUTPUT) + echo "Done." + + failure_check $TESTNODEJAR_OUTPUT + + echo "**** SUCCESS: Node test successful." + + if [ $KEEP_OUTPUT == "true" ]; then + rm -fr $TESTNODEJAR_OUTPUT + cp $TESTNODEJAR_OUTPUT ./checkintest.nodejar.log + fi +} + +if [ $RUN_NODE != "false" ]; then + testnode; +fi; + +echo "Finished" diff --git a/nashorn/bin/fixorphantests.sh b/nashorn/bin/fixorphantests.sh new file mode 100644 index 00000000000..d7e5f74b6af --- /dev/null +++ b/nashorn/bin/fixorphantests.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# +# Copyright (c) 2010, 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. +# + +#ensure that all tests tagged with @test are also tagged with @run + +for f in $(find test/script/basic/*.js); do + grep @test $f >/dev/null + TEST=$? + grep @run $f >/dev/null + RUN=$? + + if [ $TEST -eq 0 ] && [ ! $RUN -eq 0 ]; then + echo "repairing ${f}..." + TEMP=$(mktemp /tmp/scratch.XXXXXX) + + #IFS='', -raw flag to preserve white space + while IFS='' read -r line; do + echo $line | grep @test >/dev/null + TEST=$? + printf "%s\n" "$line" + if [ $TEST -eq 0 ]; then + printf "%s\n" "$line" | sed s/@test/@run/g + fi + done < $f >$TEMP + + cp $TEMP $f + + rm -fr $TEMP + fi + +done diff --git a/nashorn/bin/fixwhitespace.sh b/nashorn/bin/fixwhitespace.sh new file mode 100644 index 00000000000..921a233df21 --- /dev/null +++ b/nashorn/bin/fixwhitespace.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# +# Copyright (c) 2010, 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. +# + +#convert tabs to spaces +find . -name "*.java" -exec sed -i "" 's/ / /g' {} \; + +#remove trailing whitespace +find . -name "*.java" -exec sed -i "" 's/[ ]*$//' \{} \; + diff --git a/nashorn/bin/jjs b/nashorn/bin/jjs new file mode 100644 index 00000000000..ae436b27ab5 --- /dev/null +++ b/nashorn/bin/jjs @@ -0,0 +1,29 @@ +#!/bin/bash +# +# Copyright (c) 2010, 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. +# + +[ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1; + +$JAVA_HOME/bin/java -server -XX:-TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $* diff --git a/nashorn/bin/jjs.bat b/nashorn/bin/jjs.bat new file mode 100644 index 00000000000..a7169577bcb --- /dev/null +++ b/nashorn/bin/jjs.bat @@ -0,0 +1,27 @@ +rem +rem Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +rem DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +rem +rem This code is free software; you can redistribute it and/or modify it +rem under the terms of the GNU General Public License version 2 only, as +rem published by the Free Software Foundation. Oracle designates this +rem particular file as subject to the "Classpath" exception as provided +rem by Oracle in the LICENSE file that accompanied this code. +rem +rem This code is distributed in the hope that it will be useful, but WITHOUT +rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +rem version 2 for more details (a copy is included in the LICENSE file that +rem accompanied this code). +rem +rem You should have received a copy of the GNU General Public License version +rem 2 along with this work; if not, write to the Free Software Foundation, +rem Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +rem +rem Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +rem or visit www.oracle.com if you need additional information or have any +rem questions. +rem +@echo off + +java -Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -Djava.ext.dirs=%~dp0\..\dist -XX:+HeapDumpOnOutOfMemoryError -Dnashorn.debug=true -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false jdk.nashorn.tools.Shell diff --git a/nashorn/bin/jjssecure b/nashorn/bin/jjssecure new file mode 100644 index 00000000000..887c421d95c --- /dev/null +++ b/nashorn/bin/jjssecure @@ -0,0 +1,29 @@ +#!/bin/bash +# +# Copyright (c) 2010, 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. +# + +[ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1; + +$JAVA_HOME/bin/java -Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -XX:+HeapDumpOnOutOfMemoryError -Dnashorn.debug=true -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=true -Dnashorn.home=`dirname $0`/.. -Djava.security.manager jdk.nashorn.tools.Shell $* diff --git a/nashorn/bin/jjssecure.bat b/nashorn/bin/jjssecure.bat new file mode 100644 index 00000000000..662b167ae19 --- /dev/null +++ b/nashorn/bin/jjssecure.bat @@ -0,0 +1,27 @@ +rem +rem Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +rem DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +rem +rem This code is free software; you can redistribute it and/or modify it +rem under the terms of the GNU General Public License version 2 only, as +rem published by the Free Software Foundation. Oracle designates this +rem particular file as subject to the "Classpath" exception as provided +rem by Oracle in the LICENSE file that accompanied this code. +rem +rem This code is distributed in the hope that it will be useful, but WITHOUT +rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +rem version 2 for more details (a copy is included in the LICENSE file that +rem accompanied this code). +rem +rem You should have received a copy of the GNU General Public License version +rem 2 along with this work; if not, write to the Free Software Foundation, +rem Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +rem +rem Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +rem or visit www.oracle.com if you need additional information or have any +rem questions. +rem +@echo off + +java -Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -Djava.ext.dirs=%~dp0\..\dist -XX:+HeapDumpOnOutOfMemoryError -Dnashorn.debug=true -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.home=%~dp0\.. -Djava.security.manager jdk.nashorn.tools.Shell diff --git a/nashorn/bin/nashorn b/nashorn/bin/nashorn new file mode 100644 index 00000000000..7720f423cdb --- /dev/null +++ b/nashorn/bin/nashorn @@ -0,0 +1,29 @@ +#!/bin/bash +# +# Copyright (c) 2010, 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. +# + +[ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1; + +$JAVA_HOME/bin/jrunscript -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -J-XX:+HeapDumpOnOutOfMemoryError -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -J-Dnashorn.debug=true -l nashorn $* diff --git a/nashorn/bin/nashorn.bat b/nashorn/bin/nashorn.bat new file mode 100644 index 00000000000..86aafc44a8a --- /dev/null +++ b/nashorn/bin/nashorn.bat @@ -0,0 +1,27 @@ +rem +rem Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +rem DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +rem +rem This code is free software; you can redistribute it and/or modify it +rem under the terms of the GNU General Public License version 2 only, as +rem published by the Free Software Foundation. Oracle designates this +rem particular file as subject to the "Classpath" exception as provided +rem by Oracle in the LICENSE file that accompanied this code. +rem +rem This code is distributed in the hope that it will be useful, but WITHOUT +rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +rem version 2 for more details (a copy is included in the LICENSE file that +rem accompanied this code). +rem +rem You should have received a copy of the GNU General Public License version +rem 2 along with this work; if not, write to the Free Software Foundation, +rem Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +rem +rem Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +rem or visit www.oracle.com if you need additional information or have any +rem questions. +rem +@echo off + +jrunscript -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=%~dp0\..\dist -J-XX:+HeapDumpOnOutOfMemoryError -J-Dnashorn.debug=true -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -l nashorn diff --git a/nashorn/bin/rm-non-tracked.sh b/nashorn/bin/rm-non-tracked.sh new file mode 100644 index 00000000000..aaadcf3809c --- /dev/null +++ b/nashorn/bin/rm-non-tracked.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# +# Copyright (c) 2010, 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. +# +hg status|grep ^\?|awk '{print $2}'|xargs rm diff --git a/nashorn/bin/verbose_octane.bat b/nashorn/bin/verbose_octane.bat new file mode 100644 index 00000000000..69abbf8b47d --- /dev/null +++ b/nashorn/bin/verbose_octane.bat @@ -0,0 +1,59 @@ +rem +rem Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +rem DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +rem +rem This code is free software; you can redistribute it and/or modify it +rem under the terms of the GNU General Public License version 2 only, as +rem published by the Free Software Foundation. +rem +rem This code is distributed in the hope that it will be useful, but WITHOUT +rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +rem version 2 for more details (a copy is included in the LICENSE file that +rem accompanied this code). +rem +rem You should have received a copy of the GNU General Public License version +rem 2 along with this work; if not, write to the Free Software Foundation, +rem Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +rem +rem Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +rem or visit www.oracle.com if you need additional information or have any +rem questions. +rem +@echo off + +if "%JAVA_HOME%" neq "" ( + call :run "%JAVA_HOME%/bin/java" +) else ( + call :run java +) +goto :EOF + +:run +setlocal +set NASHORN_JAR=dist/nashorn.jar +set JVM_FLAGS=-Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -jar %NASHORN_JAR% +set JVM_FLAGS7=-Xbootclasspath/p:%NASHORN_JAR% %JVM_FLAGS% +set OCTANE_ARGS=--verbose --iterations 7 + +%1 -fullversion 2>&1 | findstr /L /C:"version ""1.7" +if %errorlevel% equ 0 ( + set CMD=%1 %JVM_FLAGS7% +) else ( + %1 -fullversion + set CMD=%1 %JVM_FLAGS% +) + +%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/box2d.js %OCTANE_ARGS% +%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/code-load.js %OCTANE_ARGS% +%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/crypto.js %OCTANE_ARGS% +%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/deltablue.js %OCTANE_ARGS% +%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/gbemu.js %OCTANE_ARGS% +%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/navier-stokes.js %OCTANE_ARGS% +%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/pdfjs.js %OCTANE_ARGS% +%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/raytrace.js %OCTANE_ARGS% +%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/regexp.js %OCTANE_ARGS% +%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/richards.js %OCTANE_ARGS% +%CMD% test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/splay.js %OCTANE_ARGS% +endlocal +goto :EOF diff --git a/nashorn/bin/verbose_octane.sh b/nashorn/bin/verbose_octane.sh new file mode 100644 index 00000000000..6a9b7eb32e1 --- /dev/null +++ b/nashorn/bin/verbose_octane.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# Copyright (c) 2010, 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. +# + +ITERS=$1 +if [ -z $ITERS ]; then + ITERS=7 +fi +NASHORN_JAR=dist/nashorn.jar +JVM_FLAGS="-XX:+UnlockDiagnosticVMOptions -Dnashorn.unstable.relink.threshold=8 -Xms2G -Xmx2G -XX:-TieredCompilation -server -jar ${NASHORN_JAR}" +JVM_FLAGS7="-Xbootclasspath/p:${NASHORN_JAR} ${JVM_FLAGS}" +OCTANE_ARGS="--verbose --iterations ${ITERS}" + +BENCHMARKS=( "box2d.js" "code-load.js" "crypto.js" "deltablue.js" "earley-boyer.js" "gbemu.js" "navier-stokes.js" "raytrace.js" "regexp.js" "richards.js" "splay.js" ) +# TODO mandreel.js has metaspace issues + +if [ ! -z $JAVA7_HOME ]; then + echo "running ${ITERS} iterations with java7 using JAVA_HOME=${JAVA7_HOME}..." + for BENCHMARK in "${BENCHMARKS[@]}" + do + CMD="${JAVA8_HOME}/bin/java ${JVM_FLAGS} test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/${BENCHMARK} ${OCTANE_ARGS}" + $CMD + done +else + echo "no JAVA7_HOME set. skipping java7" +fi + +if [ ! -z $JAVA8_HOME ]; then + echo "running ${ITERS} iterations with java8 using JAVA_HOME=${JAVA8_HOME}..." + for BENCHMARK in "${BENCHMARKS[@]}" + do + CMD="${JAVA8_HOME}/bin/java ${JVM_FLAGS} test/script/basic/run-octane.js -- test/script/external/octane/benchmarks/${BENCHMARK} ${OCTANE_ARGS}" + $CMD + done +else + echo "no JAVA8_HOME set" +fi + +echo "Done" diff --git a/nashorn/buildtools/nasgen/README b/nashorn/buildtools/nasgen/README new file mode 100644 index 00000000000..d4509459691 --- /dev/null +++ b/nashorn/buildtools/nasgen/README @@ -0,0 +1,34 @@ +Nasgen is a tool for processing Java classes that implement native +JavaScript objects. It does so by looking for the +com.oracle.nashorn.objects.annotations.ScriptClass annotation and other +annotations in that package. + +For each class "C", nasgen instruments the original class and generates +two additional classes: a "C$Prototype" class for the JavaScript +prototype object, and a "C$Constructor" class for the JavaScript +constructor function. + +Each class instrumented or generated by nasgen contains a private static +"$nasgenmap$" field of type com.oracle.nashorn.runtime.PropertyMap and +static initializer block to initialize the field to the object's +JavaScript properties. + +Members annotated with @Function, @Property, @Getter, and @Setter are +mapped to the $Constructor, $Prototype, or main class, depending on the +value of the annotation's 'where' field. By default, @Property, @Getter, +and @Setter belong to the main class while @Function methods without +explicit 'where' field belong to the $Prototype class. The @Constructor +annotation marks a method to be invoked as JavaScript constructor. + +Nasgen enforces all @Function/@Getter/@Setter/@Constructor annotated +methods to be declared as static. Static final @Property fields remain +in the main class while other @Property fields are moved to respective +classes depending on the annotation's 'where' value. For functions +mapped to the $Prototype or $Constructor class, nasgen also generates +getters and setters prefixed by G$ and S$, respectively. + +Nasgen-generated classes are hidden from normal ClassLoaders by giving +them a ".clazz" file name extension instead of the standard ".class" +extension. This allows script classes to be loaded independently by each +Nashorn context through the com.oracle.nashorn.runtime.StructureLoader +class loader. diff --git a/nashorn/buildtools/nasgen/build.xml b/nashorn/buildtools/nasgen/build.xml new file mode 100644 index 00000000000..e20793b7d43 --- /dev/null +++ b/nashorn/buildtools/nasgen/build.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nashorn/buildtools/nasgen/nasgen.iml b/nashorn/buildtools/nasgen/nasgen.iml new file mode 100644 index 00000000000..b67d39e96ff --- /dev/null +++ b/nashorn/buildtools/nasgen/nasgen.iml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + diff --git a/nashorn/buildtools/nasgen/project.properties b/nashorn/buildtools/nasgen/project.properties new file mode 100644 index 00000000000..65047d95312 --- /dev/null +++ b/nashorn/buildtools/nasgen/project.properties @@ -0,0 +1,52 @@ +# +# Copyright (c) 2010, 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. +# +application.title=nasgen + +# source and target levels +build.compiler=modern +javac.source=1.7 +javac.target=1.7 + +build.classes.dir=${build.dir}/classes + +# This directory is removed when the project is cleaned: +build.dir=build + +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/nasgen.jar +dist.javadoc.dir=${dist.dir}/javadoc + +nashorn.dir=../../ + +javac.debug=true + +javac.classpath=\ + ${nashorn.dir}/build/classes + +meta.inf.dir=${src.dir}/META-INF +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +run.jvmargs= +src.dir=src diff --git a/nashorn/buildtools/nasgen/src/META-INF/MANIFEST.MF b/nashorn/buildtools/nasgen/src/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..b70986369a1 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/META-INF/MANIFEST.MF @@ -0,0 +1,4 @@ +Manifest-Version: 1.0 +Class-Path: lib/ant-1.7.1.jar +Main-Class: jdk.nashorn.internal.tools.nasgen.Main + diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java new file mode 100644 index 00000000000..3a78da413d2 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.tools.nasgen; + +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKEVIRTUAL; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.CLINIT; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.GETTER_PREFIX; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.GET_CLASS_NAME; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.GET_CLASS_NAME_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_NEWPROPERTY; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_NEWPROPERTY_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_NEWMAP; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_NEWMAP_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SETTER_PREFIX; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_OBJECT; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.List; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Type; +import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind; + +/** + * Base class for class generator classes. + * + */ +public class ClassGenerator { + /** ASM class writer used to output bytecode for this class */ + protected final ClassWriter cw; + + /** + * Constructor + */ + protected ClassGenerator() { + this.cw = makeClassWriter(); + } + + MethodGenerator makeStaticInitializer() { + return makeStaticInitializer(cw); + } + + MethodGenerator makeConstructor() { + return makeConstructor(cw); + } + + MethodGenerator makeMethod(final int access, final String name, final String desc) { + return makeMethod(cw, access, name, desc); + } + + void addMapField() { + addMapField(cw); + } + + void addField(final String name, final String desc) { + addField(cw, name, desc); + } + + void addFunctionField(final String name) { + addFunctionField(cw, name); + } + + void addGetter(final String owner, final MemberInfo memInfo) { + addGetter(cw, owner, memInfo); + } + + void addSetter(final String owner, final MemberInfo memInfo) { + addSetter(cw, owner, memInfo); + } + + void emitGetClassName(final String name) { + final MethodGenerator mi = makeMethod(ACC_PUBLIC, GET_CLASS_NAME, GET_CLASS_NAME_DESC); + mi.loadLiteral(name); + mi.returnValue(); + mi.computeMaxs(); + mi.visitEnd(); + } + + static ClassWriter makeClassWriter() { + return new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) { + @Override + protected String getCommonSuperClass(final String type1, final String type2) { + try { + return super.getCommonSuperClass(type1, type2); + } catch (final RuntimeException | LinkageError e) { + return StringConstants.OBJECT_TYPE; + } + } + }; + } + + static MethodGenerator makeStaticInitializer(final ClassVisitor cv) { + return makeStaticInitializer(cv, CLINIT); + } + + static MethodGenerator makeStaticInitializer(final ClassVisitor cv, final String name) { + final int access = ACC_PUBLIC | ACC_STATIC; + final String desc = DEFAULT_INIT_DESC; + final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null); + return new MethodGenerator(mv, access, name, desc); + } + + static MethodGenerator makeConstructor(final ClassVisitor cv) { + final int access = ACC_PUBLIC; + final String name = INIT; + final String desc = DEFAULT_INIT_DESC; + final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null); + return new MethodGenerator(mv, access, name, desc); + } + + static MethodGenerator makeMethod(final ClassVisitor cv, final int access, final String name, final String desc) { + final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null); + return new MethodGenerator(mv, access, name, desc); + } + + static void emitStaticInitPrefix(final MethodGenerator mi, final String className) { + mi.visitCode(); + mi.pushNull(); + mi.putStatic(className, MAP_FIELD_NAME, MAP_DESC); + mi.loadClass(className); + mi.invokeStatic(MAP_TYPE, MAP_NEWMAP, MAP_NEWMAP_DESC); + mi.storeLocal(0); + } + + static void emitStaticInitSuffix(final MethodGenerator mi, final String className) { + mi.loadLocal(0); + mi.putStatic(className, MAP_FIELD_NAME, MAP_DESC); + mi.returnVoid(); + mi.computeMaxs(); + mi.visitEnd(); + } + + @SuppressWarnings("fallthrough") + private static Type memInfoType(final MemberInfo memInfo) { + switch (memInfo.getJavaDesc().charAt(0)) { + case 'I': return Type.INT_TYPE; + case 'J': return Type.LONG_TYPE; + case 'D': return Type.DOUBLE_TYPE; + default: assert false : memInfo.getJavaDesc(); + case 'L': return TYPE_OBJECT; + } + } + + private static String getterDesc(final MemberInfo memInfo) { + return Type.getMethodDescriptor(memInfoType(memInfo)); + } + + private static String setterDesc(final MemberInfo memInfo) { + return Type.getMethodDescriptor(Type.VOID_TYPE, memInfoType(memInfo)); + } + + static void addGetter(final ClassVisitor cv, final String owner, final MemberInfo memInfo) { + final int access = ACC_PUBLIC; + final String name = GETTER_PREFIX + memInfo.getJavaName(); + final String desc = getterDesc(memInfo); + final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null); + final MethodGenerator mi = new MethodGenerator(mv, access, name, desc); + mi.visitCode(); + if (memInfo.isStatic() && memInfo.getKind() == Kind.PROPERTY) { + mi.getStatic(owner, memInfo.getJavaName(), memInfo.getJavaDesc()); + } else { + mi.loadLocal(0); + mi.getField(owner, memInfo.getJavaName(), memInfo.getJavaDesc()); + } + mi.returnValue(); + mi.computeMaxs(); + mi.visitEnd(); + } + + static void addSetter(final ClassVisitor cv, final String owner, final MemberInfo memInfo) { + final int access = ACC_PUBLIC; + final String name = SETTER_PREFIX + memInfo.getJavaName(); + final String desc = setterDesc(memInfo); + final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null); + final MethodGenerator mi = new MethodGenerator(mv, access, name, desc); + mi.visitCode(); + if (memInfo.isStatic() && memInfo.getKind() == Kind.PROPERTY) { + mi.loadLocal(1); + mi.putStatic(owner, memInfo.getJavaName(), memInfo.getJavaDesc()); + } else { + mi.loadLocal(0); + mi.loadLocal(1); + mi.putField(owner, memInfo.getJavaName(), memInfo.getJavaDesc()); + } + mi.returnVoid(); + mi.computeMaxs(); + mi.visitEnd(); + } + + static void addMapField(final ClassVisitor cv) { + // add a MAP static field + final FieldVisitor fv = cv.visitField(ACC_PRIVATE | ACC_STATIC, + MAP_FIELD_NAME, MAP_DESC, null, null); + if (fv != null) { + fv.visitEnd(); + } + } + + static void addField(final ClassVisitor cv, final String name, final String desc) { + final FieldVisitor fv = cv.visitField(ACC_PRIVATE, name, desc, null, null); + if (fv != null) { + fv.visitEnd(); + } + } + + static void addFunctionField(final ClassVisitor cv, final String name) { + addField(cv, name, OBJECT_DESC); + } + + static void newFunction(final MethodGenerator mi, final String className, final MemberInfo memInfo, final List specs) { + final boolean arityFound = (memInfo.getArity() != MemberInfo.DEFAULT_ARITY); + + mi.loadLiteral(memInfo.getName()); + mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className, memInfo.getJavaName(), memInfo.getJavaDesc())); + + assert specs != null; + if (!specs.isEmpty()) { + mi.memberInfoArray(className, specs); + mi.invokeStatic(SCRIPTFUNCTIONIMPL_TYPE, SCRIPTFUNCTIONIMPL_MAKEFUNCTION, SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC); + } else { + mi.invokeStatic(SCRIPTFUNCTIONIMPL_TYPE, SCRIPTFUNCTIONIMPL_MAKEFUNCTION, SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC); + } + + if (arityFound) { + mi.dup(); + mi.push(memInfo.getArity()); + mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY, SCRIPTFUNCTION_SETARITY_DESC); + } + + } + + static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo memInfo) { + final String propertyName = memInfo.getName(); + mi.loadLocal(0); + mi.loadLiteral(propertyName); + // setup flags + mi.push(memInfo.getAttributes()); + // setup getter method handle + String javaName = GETTER_PREFIX + memInfo.getJavaName(); + mi.visitLdcInsn(new Handle(H_INVOKEVIRTUAL, className, javaName, getterDesc(memInfo))); + // setup setter method handle + if (memInfo.isFinal()) { + mi.pushNull(); + } else { + javaName = SETTER_PREFIX + memInfo.getJavaName(); + mi.visitLdcInsn(new Handle(H_INVOKEVIRTUAL, className, javaName, setterDesc(memInfo))); + } + mi.invokeStatic(LOOKUP_TYPE, LOOKUP_NEWPROPERTY, LOOKUP_NEWPROPERTY_DESC); + mi.storeLocal(0); + } + + static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo getter, final MemberInfo setter) { + final String propertyName = getter.getName(); + mi.loadLocal(0); + mi.loadLiteral(propertyName); + // setup flags + mi.push(getter.getAttributes()); + // setup getter method handle + mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className, + getter.getJavaName(), getter.getJavaDesc())); + // setup setter method handle + if (setter == null) { + mi.pushNull(); + } else { + mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className, + setter.getJavaName(), setter.getJavaDesc())); + } + mi.invokeStatic(LOOKUP_TYPE, LOOKUP_NEWPROPERTY, LOOKUP_NEWPROPERTY_DESC); + mi.storeLocal(0); + } + + static ScriptClassInfo getScriptClassInfo(final String fileName) throws IOException { + try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName))) { + return getScriptClassInfo(new ClassReader(bis)); + } + } + + static ScriptClassInfo getScriptClassInfo(final byte[] classBuf) { + return getScriptClassInfo(new ClassReader(classBuf)); + } + + private static ScriptClassInfo getScriptClassInfo(final ClassReader reader) { + final ScriptClassInfoCollector scic = new ScriptClassInfoCollector(); + reader.accept(scic, 0); + return scic.getScriptClassInfo(); + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java new file mode 100644 index 00000000000..2491e630ee7 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.tools.nasgen; + +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.V1_7; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.CONSTRUCTOR_SUFFIX; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_INIT_DESC3; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_INIT_DESC4; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; +import jdk.internal.org.objectweb.asm.Handle; + +/** + * This class generates constructor class for a @ClassInfo annotated class. + * + */ +public class ConstructorGenerator extends ClassGenerator { + private final ScriptClassInfo scriptClassInfo; + private final String className; + private final MemberInfo constructor; + private final int memberCount; + private final List specs; + + ConstructorGenerator(final ScriptClassInfo sci) { + this.scriptClassInfo = sci; + + this.className = scriptClassInfo.getConstructorClassName(); + this.constructor = scriptClassInfo.getConstructor(); + this.memberCount = scriptClassInfo.getConstructorMemberCount(); + this.specs = scriptClassInfo.getSpecializedConstructors(); + } + + byte[] getClassBytes() { + // new class extensing from ScriptObject + final String superClass = (constructor != null)? SCRIPTFUNCTIONIMPL_TYPE : SCRIPTOBJECT_TYPE; + cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, className, null, superClass, null); + if (memberCount > 0) { + // add fields + emitFields(); + // add + emitStaticInitializer(); + } + // add + emitConstructor(); + + if (constructor == null) { + emitGetClassName(scriptClassInfo.getName()); + } + + cw.visitEnd(); + return cw.toByteArray(); + } + + // --Internals only below this point + private void emitFields() { + // Introduce "Function" type instance fields for each + // constructor @Function in script class and introduce instance + // fields for each constructor @Property in the script class. + for (MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (memInfo.isConstructorFunction()) { + addFunctionField(memInfo.getJavaName()); + memInfo = (MemberInfo)memInfo.clone(); + memInfo.setJavaDesc(OBJECT_DESC); + memInfo.setJavaAccess(ACC_PUBLIC); + addGetter(className, memInfo); + addSetter(className, memInfo); + } else if (memInfo.isConstructorProperty()) { + if (memInfo.isStaticFinal()) { + addGetter(scriptClassInfo.getJavaName(), memInfo); + } else { + addField(memInfo.getJavaName(), memInfo.getJavaDesc()); + memInfo = (MemberInfo)memInfo.clone(); + memInfo.setJavaAccess(ACC_PUBLIC); + addGetter(className, memInfo); + addSetter(className, memInfo); + } + } + } + + addMapField(); + } + + private void emitStaticInitializer() { + final MethodGenerator mi = makeStaticInitializer(); + emitStaticInitPrefix(mi, className); + + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (memInfo.isConstructorFunction() || memInfo.isConstructorProperty()) { + linkerAddGetterSetter(mi, className, memInfo); + } else if (memInfo.isConstructorGetter()) { + final MemberInfo setter = scriptClassInfo.findSetter(memInfo); + linkerAddGetterSetter(mi, className, memInfo, setter); + } + } + emitStaticInitSuffix(mi, className); + } + + private void emitConstructor() { + final MethodGenerator mi = makeConstructor(); + mi.visitCode(); + callSuper(mi); + + if (memberCount > 0) { + // initialize Function type fields + initFunctionFields(mi); + // initialize data fields + initDataFields(mi); + } + + if (constructor != null) { + final int arity = constructor.getArity(); + if (arity != MemberInfo.DEFAULT_ARITY) { + mi.loadThis(); + mi.push(arity); + mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY, + SCRIPTFUNCTION_SETARITY_DESC); + } + } + mi.returnVoid(); + mi.computeMaxs(); + mi.visitEnd(); + } + + private void loadMap(final MethodGenerator mi) { + if (memberCount > 0) { + mi.getStatic(className, MAP_FIELD_NAME, MAP_DESC); + // make sure we use duplicated PropertyMap so that original map + // stays intact and so can be used for many globals in same context + mi.invokeVirtual(MAP_TYPE, MAP_DUPLICATE, MAP_DUPLICATE_DESC); + } + } + + private void callSuper(final MethodGenerator mi) { + String superClass, superDesc; + mi.loadThis(); + if (constructor == null) { + // call ScriptObject. + superClass = SCRIPTOBJECT_TYPE; + superDesc = (memberCount > 0) ? SCRIPTOBJECT_INIT_DESC : DEFAULT_INIT_DESC; + loadMap(mi); + } else { + // call Function. + superClass = SCRIPTFUNCTIONIMPL_TYPE; + superDesc = (memberCount > 0) ? SCRIPTFUNCTIONIMPL_INIT_DESC4 : SCRIPTFUNCTIONIMPL_INIT_DESC3; + mi.loadLiteral(constructor.getName()); + mi.visitLdcInsn(new Handle(H_INVOKESTATIC, scriptClassInfo.getJavaName(), constructor.getJavaName(), constructor.getJavaDesc())); + loadMap(mi); + mi.memberInfoArray(scriptClassInfo.getJavaName(), specs); //pushes null if specs empty + } + + mi.invokeSpecial(superClass, INIT, superDesc); + } + + private void initFunctionFields(final MethodGenerator mi) { + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (!memInfo.isConstructorFunction()) { + continue; + } + mi.loadThis(); + newFunction(mi, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName())); + mi.putField(className, memInfo.getJavaName(), OBJECT_DESC); + } + } + + private void initDataFields(final MethodGenerator mi) { + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (!memInfo.isConstructorProperty() || memInfo.isFinal()) { + continue; + } + final Object value = memInfo.getValue(); + if (value != null) { + mi.loadThis(); + mi.loadLiteral(value); + mi.putField(className, memInfo.getJavaName(), memInfo.getJavaDesc()); + } else if (!memInfo.getInitClass().isEmpty()) { + final String clazz = memInfo.getInitClass(); + mi.loadThis(); + mi.newObject(clazz); + mi.dup(); + mi.invokeSpecial(clazz, INIT, DEFAULT_INIT_DESC); + mi.putField(className, memInfo.getJavaName(), memInfo.getJavaDesc()); + } + } + + if (constructor != null) { + mi.loadThis(); + final String protoName = scriptClassInfo.getPrototypeClassName(); + mi.newObject(protoName); + mi.dup(); + mi.invokeSpecial(protoName, INIT, DEFAULT_INIT_DESC); + mi.dup(); + mi.loadThis(); + mi.invokeStatic(PROTOTYPEOBJECT_TYPE, PROTOTYPEOBJECT_SETCONSTRUCTOR, + PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC); + mi.putField(SCRIPTFUNCTION_TYPE, PROTOTYPE, OBJECT_DESC); + } + } + + /** + * Entry point for ConstructorGenerator run separately as an application. Will display + * usage. Takes one argument, a class name. + * @param args args vector + * @throws IOException if class can't be read + */ + public static void main(final String[] args) throws IOException { + if (args.length != 1) { + System.err.println("Usage: " + ConstructorGenerator.class.getName() + " "); + System.exit(1); + } + + final String className = args[0].replace('.', '/'); + final ScriptClassInfo sci = getScriptClassInfo(className + ".class"); + if (sci == null) { + System.err.println("No @ScriptClass in " + className); + System.exit(2); + throw new IOException(); // get rid of warning for sci.verify() below - may be null + } + + try { + sci.verify(); + } catch (final Exception e) { + System.err.println(e.getMessage()); + System.exit(3); + } + final ConstructorGenerator gen = new ConstructorGenerator(sci); + try (FileOutputStream fos = new FileOutputStream(className + CONSTRUCTOR_SUFFIX + ".class")) { + fos.write(gen.getClassBytes()); + } + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/Main.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/Main.java new file mode 100644 index 00000000000..96e49c1df49 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/Main.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.tools.nasgen; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.util.CheckClassAdapter; + +/** + * Main class for the "nasgen" tool. + * + */ +public class Main { + private static final boolean DEBUG = Boolean.getBoolean("nasgen.debug"); + + private interface ErrorReporter { + public void error(String msg); + } + + /** + * Public entry point for Nasgen if invoked from command line. Nasgen takes three arguments + * in order: input directory, package list, output directory + * + * @param args argument vector + */ + public static void main(final String[] args) { + final ErrorReporter reporter = new ErrorReporter() { + @Override + public void error(final String msg) { + Main.error(msg, 1); + } + }; + if (args.length == 3) { + processAll(args[0], args[1], args[2], reporter); + } else { + error("Usage: nasgen ", 1); + } + } + + private static void processAll(final String in, final String pkgList, final String out, final ErrorReporter reporter) { + final File inDir = new File(in); + if (!inDir.exists() || !inDir.isDirectory()) { + reporter.error(in + " does not exist or not a directory"); + return; + } + + final File outDir = new File(out); + if (!outDir.exists() || !outDir.isDirectory()) { + reporter.error(out + " does not exist or not a directory"); + return; + } + + final String[] packages = pkgList.split(":"); + for (String pkg : packages) { + pkg = pkg.replace('.', File.separatorChar); + final File dir = new File(inDir, pkg); + final File[] classes = dir.listFiles(); + for (final File clazz : classes) { + if (clazz.isFile() && clazz.getName().endsWith(".class")) { + if (! process(clazz, new File(outDir, pkg), reporter)) { + return; + } + } + } + } + } + + private static boolean process(final File inFile, final File outDir, final ErrorReporter reporter) { + try { + byte[] buf = new byte[(int)inFile.length()]; + + try (FileInputStream fin = new FileInputStream(inFile)) { + fin.read(buf); + } + + final ScriptClassInfo sci = ClassGenerator.getScriptClassInfo(buf); + + if (sci != null) { + try { + sci.verify(); + } catch (final Exception e) { + reporter.error(e.getMessage()); + return false; + } + + // create necessary output package dir + outDir.mkdirs(); + + // instrument @ScriptClass + final ClassWriter writer = ClassGenerator.makeClassWriter(); + final ClassReader reader = new ClassReader(buf); + final ScriptClassInstrumentor inst = new ScriptClassInstrumentor(writer, sci); + reader.accept(inst, 0); + //noinspection UnusedAssignment + + // write instrumented class + try (FileOutputStream fos = new FileOutputStream(new File(outDir, inFile.getName()))) { + buf = writer.toByteArray(); + if (DEBUG) { + verify(buf); + } + fos.write(buf); + } + + // simple class name without package prefix + String simpleName = inFile.getName(); + simpleName = simpleName.substring(0, simpleName.indexOf(".class")); + + if (sci.getPrototypeMemberCount() > 0) { + // generate prototype class + final PrototypeGenerator protGen = new PrototypeGenerator(sci); + buf = protGen.getClassBytes(); + if (DEBUG) { + verify(buf); + } + try (FileOutputStream fos = new FileOutputStream(new File(outDir, simpleName + StringConstants.PROTOTYPE_SUFFIX + ".class"))) { + fos.write(buf); + } + } + + if (sci.getConstructorMemberCount() > 0 || sci.getConstructor() != null) { + // generate constructor class + final ConstructorGenerator consGen = new ConstructorGenerator(sci); + buf = consGen.getClassBytes(); + if (DEBUG) { + verify(buf); + } + try (FileOutputStream fos = new FileOutputStream(new File(outDir, simpleName + StringConstants.CONSTRUCTOR_SUFFIX + ".class"))) { + fos.write(buf); + } + } + } + return true; + } catch (final IOException | RuntimeException e) { + if (DEBUG) { + e.printStackTrace(System.err); + } + reporter.error(e.getMessage()); + + return false; + } + } + + private static void verify(final byte[] buf) { + final ClassReader cr = new ClassReader(buf); + CheckClassAdapter.verify(cr, false, new PrintWriter(System.err)); + } + + private static void error(final String msg, final int exitCode) { + System.err.println(msg); + System.exit(exitCode); + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java new file mode 100644 index 00000000000..62e8de2a6bc --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.tools.nasgen; + +import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_ARRAY_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; + +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.Type; +import jdk.nashorn.internal.objects.annotations.Where; + +/** + * Details about a Java method or field annotated with any of the field/method + * annotations from the jdk.nashorn.internal.objects.annotations package. + */ +public final class MemberInfo implements Cloneable { + /** + * The different kinds of available class annotations + */ + public static enum Kind { + /** This is a script class */ + SCRIPT_CLASS, + /** This is a constructor */ + CONSTRUCTOR, + /** This is a function */ + FUNCTION, + /** This is a getter */ + GETTER, + /** This is a setter */ + SETTER, + /** This is a property */ + PROPERTY, + /** This is a specialized version of a function */ + SPECIALIZED_FUNCTION, + /** This is a specialized version of a constructor */ + SPECIALIZED_CONSTRUCTOR + } + + // keep in sync with jdk.nashorn.internal.objects.annotations.Attribute + static final int DEFAULT_ATTRIBUTES = 0x0; + + static final int DEFAULT_ARITY = -2; + + // the kind of the script annotation - one of the above constants + private MemberInfo.Kind kind; + // script property name + private String name; + // script property attributes + private int attributes; + // name of the java member + private String javaName; + // type descriptor of the java member + private String javaDesc; + // access bits of the Java field or method + private int javaAccess; + // initial value for static @Property fields + private Object value; + // class whose object is created to fill property value + private String initClass; + // arity of the Function or Constructor + private int arity; + + private Where where; + + /** + * @return the kind + */ + public Kind getKind() { + return kind; + } + + /** + * @param kind the kind to set + */ + public void setKind(final Kind kind) { + this.kind = kind; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(final String name) { + this.name = name; + } + + /** + * @return the attributes + */ + public int getAttributes() { + return attributes; + } + + /** + * @param attributes the attributes to set + */ + public void setAttributes(final int attributes) { + this.attributes = attributes; + } + + /** + * @return the javaName + */ + public String getJavaName() { + return javaName; + } + + /** + * @param javaName the javaName to set + */ + public void setJavaName(final String javaName) { + this.javaName = javaName; + } + + /** + * @return the javaDesc + */ + public String getJavaDesc() { + return javaDesc; + } + + void setJavaDesc(final String javaDesc) { + this.javaDesc = javaDesc; + } + + int getJavaAccess() { + return javaAccess; + } + + void setJavaAccess(final int access) { + this.javaAccess = access; + } + + Object getValue() { + return value; + } + + void setValue(final Object value) { + this.value = value; + } + + Where getWhere() { + return where; + } + + void setWhere(final Where where) { + this.where = where; + } + + boolean isFinal() { + return (javaAccess & Opcodes.ACC_FINAL) != 0; + } + + boolean isStatic() { + return (javaAccess & Opcodes.ACC_STATIC) != 0; + } + + boolean isStaticFinal() { + return isStatic() && isFinal(); + } + + boolean isInstanceGetter() { + return kind == Kind.GETTER && where == Where.INSTANCE; + } + + /** + * Check whether this MemberInfo is a getter that resides in the instance + * @return true if instance setter + */ + boolean isInstanceSetter() { + return kind == Kind.SETTER && where == Where.INSTANCE; + } + + boolean isInstanceProperty() { + return kind == Kind.PROPERTY && where == Where.INSTANCE; + } + + boolean isInstanceFunction() { + return kind == Kind.FUNCTION && where == Where.INSTANCE; + } + + boolean isPrototypeGetter() { + return kind == Kind.GETTER && where == Where.PROTOTYPE; + } + + boolean isPrototypeSetter() { + return kind == Kind.SETTER && where == Where.PROTOTYPE; + } + + boolean isPrototypeProperty() { + return kind == Kind.PROPERTY && where == Where.PROTOTYPE; + } + + boolean isPrototypeFunction() { + return kind == Kind.FUNCTION && where == Where.PROTOTYPE; + } + + boolean isConstructorGetter() { + return kind == Kind.GETTER && where == Where.CONSTRUCTOR; + } + + boolean isConstructorSetter() { + return kind == Kind.SETTER && where == Where.CONSTRUCTOR; + } + + boolean isConstructorProperty() { + return kind == Kind.PROPERTY && where == Where.CONSTRUCTOR; + } + + boolean isConstructorFunction() { + return kind == Kind.FUNCTION && where == Where.CONSTRUCTOR; + } + + boolean isConstructor() { + return kind == Kind.CONSTRUCTOR; + } + + void verify() { + if (kind == Kind.CONSTRUCTOR) { + final Type returnType = Type.getReturnType(javaDesc); + if (! returnType.toString().equals(OBJECT_DESC)) { + error("return value should be of Object type, found" + returnType); + } + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length < 2) { + error("constructor methods should have at least 2 args"); + } + if (! argTypes[0].equals(Type.BOOLEAN_TYPE)) { + error("first argument should be of boolean type, found" + argTypes[0]); + } + if (! argTypes[1].toString().equals(OBJECT_DESC)) { + error("second argument should be of Object type, found" + argTypes[0]); + } + + if (argTypes.length > 2) { + for (int i = 2; i < argTypes.length - 1; i++) { + if (! argTypes[i].toString().equals(OBJECT_DESC)) { + error(i + "'th argument should be of Object type, found " + argTypes[i]); + } + } + + final String lastArgType = argTypes[argTypes.length - 1].toString(); + final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC); + if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) { + error("last argument is neither Object nor Object[] type: " + lastArgType); + } + + if (isVarArg && argTypes.length > 3) { + error("vararg constructor has more than 3 arguments"); + } + } + } else if (kind == Kind.FUNCTION) { + final Type returnType = Type.getReturnType(javaDesc); + if (! returnType.toString().equals(OBJECT_DESC)) { + error("return value should be of Object type, found" + returnType); + } + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length < 1) { + error("function methods should have at least 1 arg"); + } + if (! argTypes[0].toString().equals(OBJECT_DESC)) { + error("first argument should be of Object type, found" + argTypes[0]); + } + + if (argTypes.length > 1) { + for (int i = 1; i < argTypes.length - 1; i++) { + if (! argTypes[i].toString().equals(OBJECT_DESC)) { + error(i + "'th argument should be of Object type, found " + argTypes[i]); + } + } + + final String lastArgType = argTypes[argTypes.length - 1].toString(); + final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC); + if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) { + error("last argument is neither Object nor Object[] type: " + lastArgType); + } + + if (isVarArg && argTypes.length > 2) { + error("vararg function has more than 2 arguments"); + } + } + } else if (kind == Kind.GETTER) { + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length != 1) { + error("getter methods should have one argument"); + } + if (! argTypes[0].toString().equals(OBJECT_DESC)) { + error("first argument of getter should be of Object type, found: " + argTypes[0]); + } + if (Type.getReturnType(javaDesc).equals(Type.VOID_TYPE)) { + error("return type of getter should not be void"); + } + } else if (kind == Kind.SETTER) { + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length != 2) { + error("setter methods should have two arguments"); + } + if (! argTypes[0].toString().equals(OBJECT_DESC)) { + error("first argument of setter should be of Object type, found: " + argTypes[0]); + } + if (!Type.getReturnType(javaDesc).toString().equals("V")) { + error("return type of setter should be void, found: " + Type.getReturnType(javaDesc)); + } + } + } + + private void error(final String msg) { + throw new RuntimeException(javaName + javaDesc + " : " + msg); + } + + /** + * @return the initClass + */ + String getInitClass() { + return initClass; + } + + /** + * @param initClass the initClass to set + */ + void setInitClass(final String initClass) { + this.initClass = initClass; + } + + @Override + protected Object clone() { + try { + return super.clone(); + } catch (final CloneNotSupportedException e) { + assert false : "clone not supported " + e; + return null; + } + } + + /** + * @return the arity + */ + int getArity() { + return arity; + } + + /** + * @param arity the arity to set + */ + void setArity(final int arity) { + this.arity = arity; + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java new file mode 100644 index 00000000000..500b8224946 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.tools.nasgen; + +import static jdk.internal.org.objectweb.asm.Opcodes.AALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.AASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL; +import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.ANEWARRAY; +import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN; +import static jdk.internal.org.objectweb.asm.Opcodes.ASM4; +import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.BALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.BASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.BIPUSH; +import static jdk.internal.org.objectweb.asm.Opcodes.CALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.CASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST; +import static jdk.internal.org.objectweb.asm.Opcodes.DALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.DASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.DCONST_0; +import static jdk.internal.org.objectweb.asm.Opcodes.DRETURN; +import static jdk.internal.org.objectweb.asm.Opcodes.DUP; +import static jdk.internal.org.objectweb.asm.Opcodes.DUP2; +import static jdk.internal.org.objectweb.asm.Opcodes.FALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.FASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.FCONST_0; +import static jdk.internal.org.objectweb.asm.Opcodes.FRETURN; +import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD; +import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.IALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.IASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0; +import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL; +import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN; +import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.LCONST_0; +import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN; +import static jdk.internal.org.objectweb.asm.Opcodes.NEW; +import static jdk.internal.org.objectweb.asm.Opcodes.POP; +import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD; +import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; +import static jdk.internal.org.objectweb.asm.Opcodes.SALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.SASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH; +import static jdk.internal.org.objectweb.asm.Opcodes.SWAP; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.METHODHANDLE_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_METHODHANDLE; + +import java.util.List; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Type; + +/** + * Base class for all method generating classes. + * + */ +public class MethodGenerator extends MethodVisitor { + private final int access; + private final String name; + private final String descriptor; + private final Type returnType; + private final Type[] argumentTypes; + + MethodGenerator(final MethodVisitor mv, final int access, final String name, final String descriptor) { + super(ASM4, mv); + this.access = access; + this.name = name; + this.descriptor = descriptor; + this.returnType = Type.getReturnType(descriptor); + this.argumentTypes = Type.getArgumentTypes(descriptor); + } + + int getAccess() { + return access; + } + + final String getName() { + return name; + } + + final String getDescriptor() { + return descriptor; + } + + final Type getReturnType() { + return returnType; + } + + final Type[] getArgumentTypes() { + return argumentTypes; + } + + /** + * Check whether access for this method is static + * @return true if static + */ + protected final boolean isStatic() { + return (getAccess() & ACC_STATIC) != 0; + } + + /** + * Check whether this method is a constructor + * @return true if constructor + */ + protected final boolean isConstructor() { + return "".equals(name); + } + + void newObject(final String type) { + super.visitTypeInsn(NEW, type); + } + + void newObjectArray(final String type) { + super.visitTypeInsn(ANEWARRAY, type); + } + + void loadThis() { + if ((access & ACC_STATIC) != 0) { + throw new IllegalStateException("no 'this' inside static method"); + } + super.visitVarInsn(ALOAD, 0); + } + + void returnValue() { + super.visitInsn(returnType.getOpcode(IRETURN)); + } + + void returnVoid() { + super.visitInsn(RETURN); + } + + // load, store + void arrayLoad(final Type type) { + super.visitInsn(type.getOpcode(IALOAD)); + } + + void arrayLoad() { + super.visitInsn(AALOAD); + } + + void arrayStore(final Type type) { + super.visitInsn(type.getOpcode(IASTORE)); + } + + void arrayStore() { + super.visitInsn(AASTORE); + } + + void loadLiteral(final Object value) { + super.visitLdcInsn(value); + } + + void classLiteral(final String className) { + super.visitLdcInsn(className); + } + + void loadLocal(final Type type, final int index) { + super.visitVarInsn(type.getOpcode(ILOAD), index); + } + + void loadLocal(final int index) { + super.visitVarInsn(ALOAD, index); + } + + void storeLocal(final Type type, final int index) { + super.visitVarInsn(type.getOpcode(ISTORE), index); + } + + void storeLocal(final int index) { + super.visitVarInsn(ASTORE, index); + } + + void checkcast(final String type) { + super.visitTypeInsn(CHECKCAST, type); + } + + // push constants/literals + void pushNull() { + super.visitInsn(ACONST_NULL); + } + + void push(final int value) { + if (value >= -1 && value <= 5) { + super.visitInsn(ICONST_0 + value); + } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { + super.visitIntInsn(BIPUSH, value); + } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { + super.visitIntInsn(SIPUSH, value); + } else { + super.visitLdcInsn(value); + } + } + + void loadClass(final String className) { + super.visitLdcInsn(Type.getObjectType(className)); + } + + void pop() { + super.visitInsn(POP); + } + + // various "dups" + void dup() { + super.visitInsn(DUP); + } + + void dup2() { + super.visitInsn(DUP2); + } + + void swap() { + super.visitInsn(SWAP); + } + + void dupArrayValue(final int arrayOpcode) { + switch (arrayOpcode) { + case IALOAD: case FALOAD: + case AALOAD: case BALOAD: + case CALOAD: case SALOAD: + case IASTORE: case FASTORE: + case AASTORE: case BASTORE: + case CASTORE: case SASTORE: + dup(); + break; + + case LALOAD: case DALOAD: + case LASTORE: case DASTORE: + dup2(); + break; + default: + throw new AssertionError("invalid dup"); + } + } + + void dupReturnValue(final int returnOpcode) { + switch (returnOpcode) { + case IRETURN: + case FRETURN: + case ARETURN: + super.visitInsn(DUP); + return; + case LRETURN: + case DRETURN: + super.visitInsn(DUP2); + return; + case RETURN: + return; + default: + throw new IllegalArgumentException("not return"); + } + } + + void dupValue(final Type type) { + switch (type.getSize()) { + case 1: + dup(); + break; + case 2: + dup2(); + break; + default: + throw new AssertionError("invalid dup"); + } + } + + void dupValue(final String desc) { + final int typeCode = desc.charAt(0); + switch (typeCode) { + case '[': + case 'L': + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + super.visitInsn(DUP); + break; + case 'J': + case 'D': + super.visitInsn(DUP2); + break; + default: + throw new RuntimeException("invalid signature"); + } + } + + // push default value of given type desc + void defaultValue(final String desc) { + final int typeCode = desc.charAt(0); + switch (typeCode) { + case '[': + case 'L': + super.visitInsn(ACONST_NULL); + break; + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + super.visitInsn(ICONST_0); + break; + case 'J': + super.visitInsn(LCONST_0); + break; + case 'F': + super.visitInsn(FCONST_0); + break; + case 'D': + super.visitInsn(DCONST_0); + break; + default: + throw new AssertionError("invalid desc " + desc); + } + } + + // invokes, field get/sets + void invokeVirtual(final String owner, final String method, final String desc) { + super.visitMethodInsn(INVOKEVIRTUAL, owner, method, desc); + } + + void invokeSpecial(final String owner, final String method, final String desc) { + super.visitMethodInsn(INVOKESPECIAL, owner, method, desc); + } + + void invokeStatic(final String owner, final String method, final String desc) { + super.visitMethodInsn(INVOKESTATIC, owner, method, desc); + } + + void putStatic(final String owner, final String field, final String desc) { + super.visitFieldInsn(PUTSTATIC, owner, field, desc); + } + + void getStatic(final String owner, final String field, final String desc) { + super.visitFieldInsn(GETSTATIC, owner, field, desc); + } + + void putField(final String owner, final String field, final String desc) { + super.visitFieldInsn(PUTFIELD, owner, field, desc); + } + + void getField(final String owner, final String field, final String desc) { + super.visitFieldInsn(GETFIELD, owner, field, desc); + } + + void memberInfoArray(final String className, final List mis) { + if (mis.isEmpty()) { + pushNull(); + return; + } + + int pos = 0; + push(mis.size()); + newObjectArray(METHODHANDLE_TYPE); + for (final MemberInfo mi : mis) { + dup(); + push(pos++); + visitLdcInsn(new Handle(H_INVOKESTATIC, className, mi.getJavaName(), mi.getJavaDesc())); + arrayStore(TYPE_METHODHANDLE); + } + } + + void computeMaxs() { + // These values are ignored as we create class writer + // with ClassWriter.COMPUTE_MAXS flag. + super.visitMaxs(Short.MAX_VALUE, Short.MAX_VALUE); + } + + // debugging support - print calls + void println(final String msg) { + super.visitFieldInsn(GETSTATIC, + "java/lang/System", + "out", + "Ljava/io/PrintStream;"); + super.visitLdcInsn(msg); + super.visitMethodInsn(INVOKEVIRTUAL, + "java/io/PrintStream", + "println", + "(Ljava/lang/String;)V"); + } + + // print the object on the top of the stack + void printObject() { + super.visitFieldInsn(GETSTATIC, + "java/lang/System", + "out", + "Ljava/io/PrintStream;"); + super.visitInsn(SWAP); + super.visitMethodInsn(INVOKEVIRTUAL, + "java/io/PrintStream", + "println", + "(Ljava/lang/Object;)V"); + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/NullVisitor.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/NullVisitor.java new file mode 100644 index 00000000000..7f585c0392b --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/NullVisitor.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.tools.nasgen; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +/** + * A visitor that does nothing on visitXXX calls. + * + */ +public class NullVisitor extends ClassVisitor { + NullVisitor() { + super(Opcodes.ASM4); + } + + @Override + public MethodVisitor visitMethod( + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) { + return new MethodVisitor(Opcodes.ASM4) { + @Override + public AnnotationVisitor visitAnnotationDefault() { + return new NullAnnotationVisitor(); + } + + @Override + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + return new NullAnnotationVisitor(); + } + }; + } + + @Override + public FieldVisitor visitField( + final int access, + final String name, + final String desc, + final String signature, + final Object value) { + return new FieldVisitor(Opcodes.ASM4) { + @Override + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + return new NullAnnotationVisitor(); + } + }; + } + + @Override + public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { + return new NullAnnotationVisitor(); + } + + private static class NullAnnotationVisitor extends AnnotationVisitor { + NullAnnotationVisitor() { + super(Opcodes.ASM4); + } + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java new file mode 100644 index 00000000000..a8b6e639b4e --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.tools.nasgen; + +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER; +import static jdk.internal.org.objectweb.asm.Opcodes.V1_7; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPE_SUFFIX; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC; + +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * This class generates prototype class for a @ClassInfo annotated class. + * + */ +public class PrototypeGenerator extends ClassGenerator { + private final ScriptClassInfo scriptClassInfo; + private final String className; + private final int memberCount; + + PrototypeGenerator(final ScriptClassInfo sci) { + this.scriptClassInfo = sci; + this.className = scriptClassInfo.getPrototypeClassName(); + this.memberCount = scriptClassInfo.getPrototypeMemberCount(); + } + + byte[] getClassBytes() { + // new class extensing from ScriptObject + cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, className, null, PROTOTYPEOBJECT_TYPE, null); + if (memberCount > 0) { + // add fields + emitFields(); + // add + emitStaticInitializer(); + } + // add + emitConstructor(); + + // add getClassName() + emitGetClassName(scriptClassInfo.getName()); + + cw.visitEnd(); + return cw.toByteArray(); + } + + // --Internals only below this point + private void emitFields() { + // introduce "Function" type instance fields for each + // prototype @Function in script class info + for (MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (memInfo.isPrototypeFunction()) { + addFunctionField(memInfo.getJavaName()); + memInfo = (MemberInfo)memInfo.clone(); + memInfo.setJavaDesc(OBJECT_DESC); + addGetter(className, memInfo); + addSetter(className, memInfo); + } else if (memInfo.isPrototypeProperty()) { + if (memInfo.isStaticFinal()) { + addGetter(scriptClassInfo.getJavaName(), memInfo); + } else { + addField(memInfo.getJavaName(), memInfo.getJavaDesc()); + memInfo = (MemberInfo)memInfo.clone(); + memInfo.setJavaAccess(ACC_PUBLIC); + addGetter(className, memInfo); + addSetter(className, memInfo); + } + } + } + + addMapField(); + } + + private void emitStaticInitializer() { + final MethodGenerator mi = makeStaticInitializer(); + emitStaticInitPrefix(mi, className); + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (memInfo.isPrototypeFunction() || memInfo.isPrototypeProperty()) { + linkerAddGetterSetter(mi, className, memInfo); + } else if (memInfo.isPrototypeGetter()) { + final MemberInfo setter = scriptClassInfo.findSetter(memInfo); + linkerAddGetterSetter(mi, className, memInfo, setter); + } + } + emitStaticInitSuffix(mi, className); + } + + private void emitConstructor() { + final MethodGenerator mi = makeConstructor(); + mi.visitCode(); + mi.loadThis(); + if (memberCount > 0) { + // call "super(map$)" + mi.getStatic(className, MAP_FIELD_NAME, MAP_DESC); + // make sure we use duplicated PropertyMap so that original map + // stays intact and so can be used for many globals in same context + mi.invokeVirtual(MAP_TYPE, MAP_DUPLICATE, MAP_DUPLICATE_DESC); + mi.invokeSpecial(PROTOTYPEOBJECT_TYPE, INIT, SCRIPTOBJECT_INIT_DESC); + // initialize Function type fields + initFunctionFields(mi); + } else { + // call "super()" + mi.invokeSpecial(PROTOTYPEOBJECT_TYPE, INIT, DEFAULT_INIT_DESC); + } + mi.returnVoid(); + mi.computeMaxs(); + mi.visitEnd(); + } + + private void initFunctionFields(final MethodGenerator mi) { + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (! memInfo.isPrototypeFunction()) { + continue; + } + mi.loadThis(); + newFunction(mi, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName())); + mi.putField(className, memInfo.getJavaName(), OBJECT_DESC); + } + } + + /** + * External entry point for PrototypeGenerator if called from the command line + * + * @param args arguments, takes 1 argument which is the class to process + * @throws IOException if class cannot be read + */ + public static void main(final String[] args) throws IOException { + if (args.length != 1) { + System.err.println("Usage: " + ConstructorGenerator.class.getName() + " "); + System.exit(1); + } + + final String className = args[0].replace('.', '/'); + final ScriptClassInfo sci = getScriptClassInfo(className + ".class"); + if (sci == null) { + System.err.println("No @ScriptClass in " + className); + System.exit(2); + throw new AssertionError(); //guard against warning that sci is null below + } + try { + sci.verify(); + } catch (final Exception e) { + System.err.println(e.getMessage()); + System.exit(3); + } + final PrototypeGenerator gen = new PrototypeGenerator(sci); + try (FileOutputStream fos = new FileOutputStream(className + PROTOTYPE_SUFFIX + ".class")) { + fos.write(gen.getClassBytes()); + } + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java new file mode 100644 index 00000000000..b5e285225c5 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.tools.nasgen; + +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import jdk.internal.org.objectweb.asm.Type; +import jdk.nashorn.internal.objects.annotations.Constructor; +import jdk.nashorn.internal.objects.annotations.Function; +import jdk.nashorn.internal.objects.annotations.Getter; +import jdk.nashorn.internal.objects.annotations.Property; +import jdk.nashorn.internal.objects.annotations.ScriptClass; +import jdk.nashorn.internal.objects.annotations.Setter; +import jdk.nashorn.internal.objects.annotations.SpecializedConstructor; +import jdk.nashorn.internal.objects.annotations.SpecializedFunction; +import jdk.nashorn.internal.objects.annotations.Where; +import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind; + +/** + * All annotation information from a class that is annotated with + * the annotation com.sun.oracle.objects.annotations.ScriptClass. + * + */ +public final class ScriptClassInfo { + // descriptots for various annotations + static final String SCRIPT_CLASS_ANNO_DESC = Type.getDescriptor(ScriptClass.class); + static final String CONSTRUCTOR_ANNO_DESC = Type.getDescriptor(Constructor.class); + static final String FUNCTION_ANNO_DESC = Type.getDescriptor(Function.class); + static final String GETTER_ANNO_DESC = Type.getDescriptor(Getter.class); + static final String SETTER_ANNO_DESC = Type.getDescriptor(Setter.class); + static final String PROPERTY_ANNO_DESC = Type.getDescriptor(Property.class); + static final String WHERE_ENUM_DESC = Type.getDescriptor(Where.class); + static final String SPECIALIZED_FUNCTION = Type.getDescriptor(SpecializedFunction.class); + static final String SPECIALIZED_CONSTRUCTOR = Type.getDescriptor(SpecializedConstructor.class); + + static final Map annotations = new HashMap<>(); + + static { + annotations.put(SCRIPT_CLASS_ANNO_DESC, Kind.SCRIPT_CLASS); + annotations.put(FUNCTION_ANNO_DESC, Kind.FUNCTION); + annotations.put(CONSTRUCTOR_ANNO_DESC, Kind.CONSTRUCTOR); + annotations.put(GETTER_ANNO_DESC, Kind.GETTER); + annotations.put(SETTER_ANNO_DESC, Kind.SETTER); + annotations.put(PROPERTY_ANNO_DESC, Kind.PROPERTY); + annotations.put(SPECIALIZED_FUNCTION, Kind.SPECIALIZED_FUNCTION); + annotations.put(SPECIALIZED_CONSTRUCTOR, Kind.SPECIALIZED_CONSTRUCTOR); + } + + // name of the script class + private String name; + // member info for script properties + private List members = Collections.emptyList(); + // java class name that is annotated with @ScriptClass + private String javaName; + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(final String name) { + this.name = name; + } + + /** + * @return the members + */ + public List getMembers() { + return Collections.unmodifiableList(members); + } + + /** + * @param members the members to set + */ + public void setMembers(final List members) { + this.members = members; + } + + MemberInfo getConstructor() { + for (final MemberInfo memInfo : members) { + if (memInfo.getKind() == Kind.CONSTRUCTOR) { + return memInfo; + } + } + return null; + } + + List getSpecializedConstructors() { + final List res = new LinkedList<>(); + for (final MemberInfo memInfo : members) { + if (memInfo.getKind() == Kind.SPECIALIZED_CONSTRUCTOR) { + res.add(memInfo); + } + } + return res; + } + + int getPrototypeMemberCount() { + int count = 0; + for (final MemberInfo memInfo : members) { + if (memInfo.getWhere() == Where.PROTOTYPE || memInfo.isConstructor()) { + count++; + } + } + return count; + } + + int getConstructorMemberCount() { + int count = 0; + for (final MemberInfo memInfo : members) { + if (memInfo.getWhere() == Where.CONSTRUCTOR) { + count++; + } + } + return count; + } + + int getInstancePropertyCount() { + int count = 0; + for (final MemberInfo memInfo : members) { + if (memInfo.getWhere() == Where.INSTANCE) { + count++; + } + } + return count; + } + + MemberInfo find(final String findJavaName, final String findJavaDesc, final int findAccess) { + for (final MemberInfo memInfo : members) { + if (memInfo.getJavaName().equals(findJavaName) && + memInfo.getJavaDesc().equals(findJavaDesc) && + memInfo.getJavaAccess() == findAccess) { + return memInfo; + } + } + return null; + } + + List findSpecializations(final String methodName) { + final List res = new LinkedList<>(); + for (final MemberInfo memInfo : members) { + if (memInfo.getName().equals(methodName) && + memInfo.getKind() == Kind.SPECIALIZED_FUNCTION) { + res.add(memInfo); + } + } + return res; + } + + MemberInfo findSetter(final MemberInfo getter) { + assert getter.getKind() == Kind.GETTER : "getter expected"; + final String getterName = getter.getName(); + final Where getterWhere = getter.getWhere(); + for (final MemberInfo memInfo : members) { + if (memInfo.getKind() == Kind.SETTER && + getterName.equals(memInfo.getName()) && + getterWhere == memInfo.getWhere()) { + return memInfo; + } + } + return null; + } + + /** + * @return the javaName + */ + public String getJavaName() { + return javaName; + } + + /** + * @param javaName the javaName to set + */ + void setJavaName(final String javaName) { + this.javaName = javaName; + } + + String getConstructorClassName() { + return getJavaName() + StringConstants.CONSTRUCTOR_SUFFIX; + } + + String getPrototypeClassName() { + return getJavaName() + StringConstants.PROTOTYPE_SUFFIX; + } + + void verify() { + boolean constructorSeen = false; + for (final MemberInfo memInfo : getMembers()) { + if (memInfo.isConstructor()) { + if (constructorSeen) { + error("more than @Constructor method"); + } + constructorSeen = true; + } + try { + memInfo.verify(); + } catch (final Exception e) { + error(e.getMessage()); + } + } + } + + private void error(final String msg) throws RuntimeException { + throw new RuntimeException(javaName + " : " + msg); + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java new file mode 100644 index 00000000000..43c2bc6c6ea --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.tools.nasgen; + +import static jdk.nashorn.internal.tools.nasgen.ScriptClassInfo.SCRIPT_CLASS_ANNO_DESC; +import static jdk.nashorn.internal.tools.nasgen.ScriptClassInfo.WHERE_ENUM_DESC; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.nashorn.internal.objects.annotations.Where; +import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind; + +/** + * This class collects all @ScriptClass and other annotation information from a + * compiled .class file. Enforces that @Function/@Getter/@Setter/@Constructor + * methods are declared to be 'static'. + */ +public class ScriptClassInfoCollector extends ClassVisitor { + private String scriptClassName; + private List scriptMembers; + private String javaClassName; + + ScriptClassInfoCollector(final ClassVisitor visitor) { + super(Opcodes.ASM4, visitor); + } + + ScriptClassInfoCollector() { + this(new NullVisitor()); + } + + private void addScriptMember(final MemberInfo memInfo) { + if (scriptMembers == null) { + scriptMembers = new ArrayList<>(); + } + scriptMembers.add(memInfo); + } + + @Override + public void visit(final int version, final int access, final String name, final String signature, + final String superName, final String[] interfaces) { + super.visit(version, access, name, signature, superName, interfaces); + javaClassName = name; + } + + @Override + public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { + final AnnotationVisitor delegateAV = super.visitAnnotation(desc, visible); + if (SCRIPT_CLASS_ANNO_DESC.equals(desc)) { + return new AnnotationVisitor(Opcodes.ASM4, delegateAV) { + @Override + public void visit(final String name, final Object value) { + if ("value".equals(name)) { + scriptClassName = (String) value; + } + super.visit(name, value); + } + }; + } + + return delegateAV; + } + + @Override + public FieldVisitor visitField(final int fieldAccess, final String fieldName, final String fieldDesc, final String signature, final Object value) { + final FieldVisitor delegateFV = super.visitField(fieldAccess, fieldName, fieldDesc, signature, value); + + return new FieldVisitor(Opcodes.ASM4, delegateFV) { + @Override + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + final AnnotationVisitor delegateAV = super.visitAnnotation(descriptor, visible); + + if (ScriptClassInfo.PROPERTY_ANNO_DESC.equals(descriptor)) { + final MemberInfo memInfo = new MemberInfo(); + + memInfo.setKind(Kind.PROPERTY); + memInfo.setJavaName(fieldName); + memInfo.setJavaDesc(fieldDesc); + memInfo.setJavaAccess(fieldAccess); + + if ((fieldAccess & Opcodes.ACC_STATIC) != 0) { + memInfo.setValue(value); + } + + addScriptMember(memInfo); + + return new AnnotationVisitor(Opcodes.ASM4, delegateAV) { + // These could be "null" if values are not suppiled, + // in which case we have to use the default values. + private String name; + private Integer attributes; + private String clazz = ""; + private Where where; + + @Override + public void visit(final String annotationName, final Object annotationValue) { + switch (annotationName) { + case "name": + this.name = (String) annotationValue; + break; + case "attributes": + this.attributes = (Integer) annotationValue; + break; + case "clazz": + this.clazz = (annotationValue == null) ? "" : annotationValue.toString(); + break; + default: + break; + } + super.visit(annotationName, annotationValue); + } + + @Override + public void visitEnum(final String enumName, final String desc, final String enumValue) { + if ("where".equals(enumName) && WHERE_ENUM_DESC.equals(desc)) { + this.where = Where.valueOf(enumValue); + } + super.visitEnum(enumName, desc, enumValue); + } + + @Override + public void visitEnd() { + super.visitEnd(); + memInfo.setName(name == null ? fieldName : name); + memInfo.setAttributes(attributes == null + ? MemberInfo.DEFAULT_ATTRIBUTES : attributes); + clazz = clazz.replace('.', '/'); + memInfo.setInitClass(clazz); + memInfo.setWhere(where == null? Where.INSTANCE : where); + } + }; + } + + return delegateAV; + } + }; + } + + private void error(final String javaName, final String javaDesc, final String msg) { + throw new RuntimeException(scriptClassName + "." + javaName + javaDesc + " : " + msg); + } + + @Override + public MethodVisitor visitMethod(final int methodAccess, final String methodName, + final String methodDesc, final String signature, final String[] exceptions) { + + final MethodVisitor delegateMV = super.visitMethod(methodAccess, methodName, methodDesc, + signature, exceptions); + + return new MethodVisitor(Opcodes.ASM4, delegateMV) { + + @Override + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + final AnnotationVisitor delegateAV = super.visitAnnotation(descriptor, visible); + final Kind annoKind = ScriptClassInfo.annotations.get(descriptor); + + if (annoKind != null) { + if ((methodAccess & Opcodes.ACC_STATIC) == 0) { + error(methodName, methodDesc, "nasgen method annotations cannot be on instance methods"); + } + + final MemberInfo memInfo = new MemberInfo(); + + memInfo.setKind(annoKind); + memInfo.setJavaName(methodName); + memInfo.setJavaDesc(methodDesc); + memInfo.setJavaAccess(methodAccess); + + addScriptMember(memInfo); + + return new AnnotationVisitor(Opcodes.ASM4, delegateAV) { + // These could be "null" if values are not suppiled, + // in which case we have to use the default values. + private String name; + private Integer attributes; + private Integer arity; + private Where where; + + @Override + public void visit(final String annotationName, final Object annotationValue) { + switch (annotationName) { + case "name": + this.name = (String)annotationValue; + break; + case "attributes": + this.attributes = (Integer)annotationValue; + break; + case "arity": + this.arity = (Integer)annotationValue; + break; + default: + break; + } + + super.visit(annotationName, annotationValue); + } + + @Override + public void visitEnum(final String enumName, final String desc, final String enumValue) { + if ("where".equals(enumName) && WHERE_ENUM_DESC.equals(desc)) { + this.where = Where.valueOf(enumValue); + } + super.visitEnum(enumName, desc, enumValue); + } + + @Override + public void visitEnd() { + super.visitEnd(); + + if (memInfo.getKind() == Kind.CONSTRUCTOR) { + memInfo.setName(name == null ? scriptClassName : name); + } else { + memInfo.setName(name == null ? methodName : name); + } + memInfo.setAttributes(attributes == null ? MemberInfo.DEFAULT_ATTRIBUTES : attributes); + + memInfo.setArity((arity == null)? MemberInfo.DEFAULT_ARITY : arity); + if (where == null) { + // by default @Getter/@Setter belongs to INSTANCE + // @Function belong to PROTOTYPE. + switch (memInfo.getKind()) { + case GETTER: + case SETTER: + where = Where.INSTANCE; + break; + case SPECIALIZED_CONSTRUCTOR: + case CONSTRUCTOR: + where = Where.CONSTRUCTOR; + break; + case FUNCTION: + where = Where.PROTOTYPE; + break; + case SPECIALIZED_FUNCTION: + //TODO is this correct + default: + break; + } + } + memInfo.setWhere(where); + } + }; + } + + return delegateAV; + } + }; + } + + ScriptClassInfo getScriptClassInfo() { + ScriptClassInfo sci = null; + if (scriptClassName != null) { + sci = new ScriptClassInfo(); + sci.setName(scriptClassName); + if (scriptMembers == null) { + scriptMembers = Collections.emptyList(); + } + sci.setMembers(scriptMembers); + sci.setJavaName(javaClassName); + } + return sci; + } + + /** + * External entry point for ScriptClassInfoCollector if invoked from the command line + * @param args argument vector, args contains a class for which to collect info + * @throws IOException if there were problems parsing args or class + */ + public static void main(final String[] args) throws IOException { + if (args.length != 1) { + System.err.println("Usage: " + ScriptClassInfoCollector.class.getName() + " "); + System.exit(1); + } + + args[0] = args[0].replace('.', '/'); + final ScriptClassInfoCollector scic = new ScriptClassInfoCollector(); + try (final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(args[0] + ".class"))) { + final ClassReader reader = new ClassReader(bis); + reader.accept(scic, 0); + } + final ScriptClassInfo sci = scic.getScriptClassInfo(); + final PrintStream out = System.out; + if (sci != null) { + out.println("script class: " + sci.getName()); + out.println("==================================="); + for (final MemberInfo memInfo : sci.getMembers()) { + out.println("kind : " + memInfo.getKind()); + out.println("name : " + memInfo.getName()); + out.println("attributes: " + memInfo.getAttributes()); + out.println("javaName: " + memInfo.getJavaName()); + out.println("javaDesc: " + memInfo.getJavaDesc()); + out.println("where: " + memInfo.getWhere()); + out.println("====================================="); + } + } else { + out.println(args[0] + " is not a @ScriptClass"); + } + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java new file mode 100644 index 00000000000..c8e97370737 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.tools.nasgen; + +import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.DUP; +import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.NEW; +import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD; +import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.$CLINIT$; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.CLINIT; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.Attribute; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.util.CheckClassAdapter; +import jdk.nashorn.internal.objects.annotations.Where; +import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind; + +/** + * This class instruments the java class annotated with @ScriptClass. + * + * Changes done are: + * + * 1) remove all jdk.nashorn.internal.objects.annotations.* annotations. + * 2) static final @Property fields stay here. Other @Property fields moved to + * respective classes depending on 'where' value of annotation. + * 2) add "Map" type static field named "$map". + * 3) add static initializer block to initialize map. + */ + +public class ScriptClassInstrumentor extends ClassVisitor { + private final ScriptClassInfo scriptClassInfo; + private final int memberCount; + private boolean staticInitFound; + + ScriptClassInstrumentor(final ClassVisitor visitor, final ScriptClassInfo sci) { + super(Opcodes.ASM4, visitor); + if (sci == null) { + throw new IllegalArgumentException("Null ScriptClassInfo, is the class annotated?"); + } + this.scriptClassInfo = sci; + this.memberCount = scriptClassInfo.getInstancePropertyCount(); + } + + @Override + public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { + if (ScriptClassInfo.annotations.containsKey(desc)) { + // ignore @ScriptClass + return null; + } + + return super.visitAnnotation(desc, visible); + } + + @Override + public FieldVisitor visitField(final int fieldAccess, final String fieldName, + final String fieldDesc, final String signature, final Object value) { + final MemberInfo memInfo = scriptClassInfo.find(fieldName, fieldDesc, fieldAccess); + if (memInfo != null && memInfo.getKind() == Kind.PROPERTY && + memInfo.getWhere() != Where.INSTANCE && !memInfo.isStaticFinal()) { + // non-instance @Property fields - these have to go elsewhere unless 'static final' + return null; + } + + final FieldVisitor delegateFV = super.visitField(fieldAccess, fieldName, fieldDesc, + signature, value); + return new FieldVisitor(Opcodes.ASM4, delegateFV) { + @Override + public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { + if (ScriptClassInfo.annotations.containsKey(desc)) { + // ignore script field annotations + return null; + } + + return fv.visitAnnotation(desc, visible); + } + + @Override + public void visitAttribute(final Attribute attr) { + fv.visitAttribute(attr); + } + + @Override + public void visitEnd() { + fv.visitEnd(); + } + }; + } + + @Override + public MethodVisitor visitMethod(final int methodAccess, final String methodName, + final String methodDesc, final String signature, final String[] exceptions) { + + final boolean isConstructor = INIT.equals(methodName); + final boolean isStaticInit = CLINIT.equals(methodName); + + if (isStaticInit) { + staticInitFound = true; + } + + final MethodGenerator delegateMV = new MethodGenerator(super.visitMethod(methodAccess, methodName, methodDesc, + signature, exceptions), methodAccess, methodName, methodDesc); + + return new MethodVisitor(Opcodes.ASM4, delegateMV) { + @Override + public void visitInsn(final int opcode) { + // call $clinit$ just before return from + if (isStaticInit && opcode == RETURN) { + super.visitMethodInsn(INVOKESTATIC, scriptClassInfo.getJavaName(), + $CLINIT$, DEFAULT_INIT_DESC); + } + super.visitInsn(opcode); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { + if (isConstructor && opcode == INVOKESPECIAL && + INIT.equals(name) && SCRIPTOBJECT_TYPE.equals(owner)) { + super.visitFieldInsn(GETSTATIC, scriptClassInfo.getJavaName(), + MAP_FIELD_NAME, MAP_DESC); + super.visitMethodInsn(INVOKESPECIAL, SCRIPTOBJECT_TYPE, INIT, + SCRIPTOBJECT_INIT_DESC); + + if (memberCount > 0) { + // initialize @Property fields if needed + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (memInfo.isInstanceProperty() && !memInfo.getInitClass().isEmpty()) { + final String clazz = memInfo.getInitClass(); + super.visitVarInsn(ALOAD, 0); + super.visitTypeInsn(NEW, clazz); + super.visitInsn(DUP); + super.visitMethodInsn(INVOKESPECIAL, clazz, + INIT, DEFAULT_INIT_DESC); + super.visitFieldInsn(PUTFIELD, scriptClassInfo.getJavaName(), + memInfo.getJavaName(), memInfo.getJavaDesc()); + } + + if (memInfo.isInstanceFunction()) { + super.visitVarInsn(ALOAD, 0); + ClassGenerator.newFunction(delegateMV, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName())); + super.visitFieldInsn(PUTFIELD, scriptClassInfo.getJavaName(), + memInfo.getJavaName(), OBJECT_DESC); + } + } + } + } else { + super.visitMethodInsn(opcode, owner, name, desc); + } + } + + @Override + public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { + if (ScriptClassInfo.annotations.containsKey(desc)) { + // ignore script method annotations + return null; + } + return super.visitAnnotation(desc, visible); + } + }; + } + + @Override + public void visitEnd() { + emitFields(); + emitStaticInitializer(); + emitGettersSetters(); + super.visitEnd(); + } + + private void emitFields() { + // introduce "Function" type instance fields for each + // instance @Function in script class info + final String className = scriptClassInfo.getJavaName(); + for (MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (memInfo.isInstanceFunction()) { + ClassGenerator.addFunctionField(cv, memInfo.getJavaName()); + memInfo = (MemberInfo)memInfo.clone(); + memInfo.setJavaDesc(OBJECT_DESC); + ClassGenerator.addGetter(cv, className, memInfo); + ClassGenerator.addSetter(cv, className, memInfo); + } + } + ClassGenerator.addMapField(this); + } + + void emitGettersSetters() { + if (memberCount > 0) { + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + final String className = scriptClassInfo.getJavaName(); + if (memInfo.isInstanceProperty()) { + ClassGenerator.addGetter(cv, className, memInfo); + if (! memInfo.isFinal()) { + ClassGenerator.addSetter(cv, className, memInfo); + } + } + } + } + } + + private void emitStaticInitializer() { + final String className = scriptClassInfo.getJavaName(); + if (! staticInitFound) { + // no user written and so create one + final MethodVisitor mv = ClassGenerator.makeStaticInitializer(this); + mv.visitCode(); + mv.visitInsn(RETURN); + mv.visitMaxs(Short.MAX_VALUE, 0); + mv.visitEnd(); + } + // Now generate $clinit$ + final MethodGenerator mi = ClassGenerator.makeStaticInitializer(this, $CLINIT$); + ClassGenerator.emitStaticInitPrefix(mi, className); + if (memberCount > 0) { + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (memInfo.isInstanceProperty() || memInfo.isInstanceFunction()) { + ClassGenerator.linkerAddGetterSetter(mi, className, memInfo); + } else if (memInfo.isInstanceGetter()) { + final MemberInfo setter = scriptClassInfo.findSetter(memInfo); + ClassGenerator.linkerAddGetterSetter(mi, className, memInfo, setter); + } + } + } + ClassGenerator.emitStaticInitSuffix(mi, className); + } + + /** + * External entry point for ScriptClassInfoCollector if run from the command line + * + * @param args arguments - one argument is needed, the name of the class to collect info from + * + * @throws IOException if there are problems reading class + */ + public static void main(final String[] args) throws IOException { + if (args.length != 1) { + System.err.println("Usage: " + ScriptClassInfoCollector.class.getName() + " "); + System.exit(1); + } + + final String fileName = args[0].replace('.', '/') + ".class"; + final ScriptClassInfo sci = ClassGenerator.getScriptClassInfo(fileName); + if (sci == null) { + System.err.println("No @ScriptClass in " + fileName); + System.exit(2); + throw new AssertionError(); //guard against warning that sci is null below + } + + try { + sci.verify(); + } catch (final Exception e) { + System.err.println(e.getMessage()); + System.exit(3); + } + + final ClassWriter writer = ClassGenerator.makeClassWriter(); + try (final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName))) { + final ClassReader reader = new ClassReader(bis); + final CheckClassAdapter checker = new CheckClassAdapter(writer); + final ScriptClassInstrumentor instr = new ScriptClassInstrumentor(checker, sci); + reader.accept(instr, 0); + } + + try (FileOutputStream fos = new FileOutputStream(fileName)) { + fos.write(writer.toByteArray()); + } + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java new file mode 100644 index 00000000000..06032733e92 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.tools.nasgen; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Method; +import jdk.internal.org.objectweb.asm.Type; +import jdk.nashorn.internal.objects.PrototypeObject; +import jdk.nashorn.internal.objects.ScriptFunctionImpl; +import jdk.nashorn.internal.runtime.PropertyMap; +import jdk.nashorn.internal.runtime.ScriptFunction; +import jdk.nashorn.internal.runtime.ScriptObject; +import jdk.nashorn.internal.runtime.linker.Lookup; + +/** + * String constants used for code generation/instrumentation. + */ +@SuppressWarnings("javadoc") +public interface StringConstants { + static final Type TYPE_METHOD = Type.getType(Method.class); + static final Type TYPE_METHODHANDLE = Type.getType(MethodHandle.class); + static final Type TYPE_METHODHANDLE_ARRAY = Type.getType(MethodHandle[].class); + static final Type TYPE_OBJECT = Type.getType(Object.class); + static final Type TYPE_CLASS = Type.getType(Class.class); + static final Type TYPE_STRING = Type.getType(String.class); + + // Nashorn types + static final Type TYPE_LOOKUP = Type.getType(Lookup.class); + static final Type TYPE_PROPERTYMAP = Type.getType(PropertyMap.class); + static final Type TYPE_PROTOTYPEOBJECT = Type.getType(PrototypeObject.class); + static final Type TYPE_SCRIPTFUNCTION = Type.getType(ScriptFunction.class); + static final Type TYPE_SCRIPTFUNCTIONIMPL = Type.getType(ScriptFunctionImpl.class); + static final Type TYPE_SCRIPTOBJECT = Type.getType(ScriptObject.class); + + static final String PROTOTYPE = "prototype"; + static final String PROTOTYPE_SUFFIX = "$Prototype"; + static final String CONSTRUCTOR_SUFFIX = "$Constructor"; + // This field name is known to Nashorn runtime (Context). + // Synchronize the name change, if needed at all. + static final String MAP_FIELD_NAME = "$nasgenmap$"; + static final String $CLINIT$ = "$clinit$"; + static final String CLINIT = ""; + static final String INIT = ""; + static final String DEFAULT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE); + + static final String SCRIPTOBJECT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_PROPERTYMAP); + + static final String METHODHANDLE_TYPE = TYPE_METHODHANDLE.getInternalName(); + + static final String OBJECT_TYPE = TYPE_OBJECT.getInternalName(); + static final String OBJECT_DESC = TYPE_OBJECT.getDescriptor(); + static final String OBJECT_ARRAY_DESC = Type.getDescriptor(Object[].class); + + static final String SCRIPTFUNCTION_TYPE = TYPE_SCRIPTFUNCTION.getInternalName(); + static final String SCRIPTFUNCTIONIMPL_TYPE = TYPE_SCRIPTFUNCTIONIMPL.getInternalName(); + static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION = "makeFunction"; + static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC = + Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE); + static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC = + Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE, TYPE_METHODHANDLE_ARRAY); + + static final String SCRIPTFUNCTIONIMPL_INIT_DESC3 = + Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_METHODHANDLE_ARRAY); + static final String SCRIPTFUNCTIONIMPL_INIT_DESC4 = + Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_PROPERTYMAP, TYPE_METHODHANDLE_ARRAY); + static final String SCRIPTFUNCTION_SETARITY = "setArity"; + static final String SCRIPTFUNCTION_SETARITY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE); + static final String PROTOTYPEOBJECT_TYPE = TYPE_PROTOTYPEOBJECT.getInternalName(); + static final String PROTOTYPEOBJECT_SETCONSTRUCTOR = "setConstructor"; + static final String PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT, TYPE_OBJECT); + static final String SCRIPTOBJECT_TYPE = TYPE_SCRIPTOBJECT.getInternalName(); + static final String MAP_TYPE = TYPE_PROPERTYMAP.getInternalName(); + static final String MAP_DESC = TYPE_PROPERTYMAP.getDescriptor(); + static final String MAP_NEWMAP = "newMap"; + static final String MAP_NEWMAP_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP, TYPE_CLASS); + static final String MAP_DUPLICATE = "duplicate"; + static final String MAP_DUPLICATE_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP); + static final String MAP_SETFLAGS = "setFlags"; + static final String LOOKUP_TYPE = TYPE_LOOKUP.getInternalName(); + static final String LOOKUP_GETMETHOD = "getMethod"; + static final String LOOKUP_NEWPROPERTY = "newProperty"; + static final String LOOKUP_NEWPROPERTY_DESC = + Type.getMethodDescriptor(TYPE_PROPERTYMAP, TYPE_PROPERTYMAP, TYPE_STRING, Type.INT_TYPE, TYPE_METHODHANDLE, TYPE_METHODHANDLE); + static final String GETTER_PREFIX = "G$"; + static final String SETTER_PREFIX = "S$"; + + // ScriptObject.getClassName() method. + static final String GET_CLASS_NAME = "getClassName"; + static final String GET_CLASS_NAME_DESC = Type.getMethodDescriptor(TYPE_STRING); +} diff --git a/nashorn/docs/DEVELOPER_README b/nashorn/docs/DEVELOPER_README new file mode 100644 index 00000000000..747379bc87b --- /dev/null +++ b/nashorn/docs/DEVELOPER_README @@ -0,0 +1,445 @@ +This document describes system properties that are used for internal +debugging and instrumentation purposes, along with the system loggers, +which are used for the same thing. + +This document is intended as a developer resource, and it is not +needed as Nashorn documentation for normal usage. Flags and system +properties described herein are subject to change without notice. + +===================================== +1. System properties used internally +===================================== + +This documentation of the system property flags assume that the +default value of the flag is false, unless otherwise specified. + + +SYSTEM PROPERTY: -Dnashorn.callsiteaccess.debug + +See the description of the access logger below. This flag is +equivalent to enabling the access logger with "info" level. + + +SYSTEM PROPERTY: -Dnashorn.compiler.ints.disable + +This flag prevents ints and longs (non double values) from being used +for any primitive representation in the lowered IR. This is default +false, i.e Lower will attempt to use integer variables as long as it +can. For example, var x = 17 would try to use x as an integer, unless +other operations occur later that require coercion to wider type, for +example x *= 17.1; + + +SYSTEM PROPERTY: -Dnashorn.compiler.intarithmetic + +Arithmetic operations in Nashorn (except bitwise ones) typically +coerce the operands to doubles (as per the JavaScript spec). To switch +this off and remain in integer mode, for example for "var x = a&b; var +y = c&d; var z = x*y;", use this flag. This will force the +multiplication of variables that are ints to be done with the IMUL +bytecode and the result "z" to become an int. + +WARNING: Note that is is experimental only to ensure that type support +exists for all primitive types. The generated code is unsound. This +will be the case until we do optimizations based on it. There is a CR +in Nashorn to do better range analysis, and ensure that this is only +done where the operation can't overflow into a wider type. Currently +no overflow checking is done, so at the moment, until range analysis +has been completed, this option is turned off. + +We've experimented by using int arithmetic for everything and putting +overflow checks afterwards, which would recompute the operation with +the correct precision, but have yet to find a configuration where this +is faster than just using doubles directly, even if the int operation +does not overflow. Getting access to a JVM intrinsic that does branch +on overflow would probably alleviate this. + +There is also a problem with this optimistic approach if the symbol +happens to reside in a local variable slot in the bytecode, as those +are strongly typed. Then we would need to split large sections of +control flow, so this is probably not the right way to go, while range +analysis is. There is a large difference between integer bytecode +without overflow checks and double bytecode. The former is +significantly faster. + + +SYSTEM PROPERTY: -Dnashorn.codegen.debug, -Dnashorn.codegen.debug.trace= + +See the description of the codegen logger below. + + +SYSTEM_PROPERTY: -Dnashorn.fields.debug + +See the description on the fields logger below. + + +SYSTEM PROPERTY: -Dnashorn.fields.dual + +When this property is true, Nashorn will attempt to use primitive +fields for AccessorProperties (currently just AccessorProperties, not +spill properties). Memory footprint for script objects will increase, +as we need to maintain both a primitive field (a long) as well as an +Object field for the property value. Ints are represented as the 32 +low bits of the long fields. Doubles are represented as the +doubleToLongBits of their value. This way a single field can be used +for all primitive types. Packing and unpacking doubles to their bit +representation is intrinsified by the JVM and extremely fast. + +While dual fields in theory runs significantly faster than Object +fields due to reduction of boxing and memory allocation overhead, +there is still work to be done to make this a general purpose +solution. Research is ongoing. + +In the future, this might complement or be replaced by experimental +feature sun.misc.TaggedArray, which has been discussed on the mlvm +mailing list. TaggedArrays are basically a way to share data space +between primitives and references, and have the GC understand this. + +As long as only primitive values are written to the fields and enough +type information exists to make sure that any reads don't have to be +uselessly boxed and unboxed, this is significantly faster than the +standard "Objects only" approach that currently is the default. See +test/examples/dual-fields-micro.js for an example that runs twice as +fast with dual fields as without them. Here, the compiler, can +determine that we are dealing with numbers only throughout the entire +property life span of the properties involved. + +If a "real" object (not a boxed primitive) is written to a field that +has a primitive representation, its callsite is relinked and an Object +field is used forevermore for that particular field in that +PropertyMap and its children, even if primitives are later assigned to +it. + +As the amount of compile time type information is very small in a +dynamic language like JavaScript, it is frequently the case that +something has to be treated as an object, because we don't know any +better. In reality though, it is often a boxed primitive is stored to +an AccessorProperty. The fastest way to handle this soundly is to use +a callsite typecheck and avoid blowing the field up to an Object. We +never revert object fields to primitives. Ping-pong:ing back and forth +between primitive representation and Object representation would cause +fatal performance overhead, so this is not an option. + +For a general application the dual fields approach is still slower +than objects only fields in some places, about the same in most cases, +and significantly faster in very few. This is due the program using +primitives, but we still can't prove it. For example "local_var a = +call(); field = a;" may very well write a double to the field, but the +compiler dare not guess a double type if field is a local variable, +due to bytecode variables being strongly typed and later non +interchangeable. To get around this, the entire method would have to +be replaced and a continuation retained to restart from. We believe +that the next steps we should go through are instead: + +1) Implement method specialization based on callsite, as it's quite +frequently the case that numbers are passed around, but currently our +function nodes just have object types visible to the compiler. For +example "var b = 17; func(a,b,17)" is an example where two parameters +can be specialized, but the main version of func might also be called +from another callsite with func(x,y,"string"). + +2) This requires lazy jitting as the functions have to be specialized +per callsite. + +Even though "function square(x) { return x*x }" might look like a +trivial function that can always only take doubles, this is not +true. Someone might have overridden the valueOf for x so that the +toNumber coercion has side effects. To fulfil JavaScript semantics, +the coercion has to run twice for both terms of the multiplication +even if they are the same object. This means that call site +specialization is necessary, not parameter specialization on the form +"function square(x) { var xd = (double)x; return xd*xd; }", as one +might first think. + +Generating a method specialization for any variant of a function that +we can determine by types at compile time is a combinatorial explosion +of byte code (try it e.g. on all the variants of am3 in the Octane +benchmark crypto.js). Thus, this needs to be lazy + +3) Possibly optimistic callsite writes, something on the form + +x = y; //x is a field known to be a primitive. y is only an object as +far as we can tell + +turns into + +try { + x = (int)y; +} catch (X is not an integer field right now | ClassCastException e) { + x = y; +} + +Mini POC shows that this is the key to a lot of dual field performance +in seemingly trivial micros where one unknown object, in reality +actually a primitive, foils it for us. Very common pattern. Once we +are "all primitives", dual fields runs a lot faster than Object fields +only. + +We still have to deal with objects vs primitives for local bytecode +slots, possibly through code copying and versioning. + + +SYSTEM PROPERTY: -Dnashorn.compiler.symbol.trace= + +When this property is set, creation and manipulation of any symbol +named "x" will show information about when the compiler changes its +type assumption, bytecode local variable slot assignment and other +data. This is useful if, for example, a symbol shows up as an Object, +when you believe it should be a primitive. Usually there is an +explanation for this, for example that it exists in the global scope +and type analysis has to be more conservative. In that case, the stack +trace upon type change to object will usually tell us why. + + +SYSTEM PROPERTY: nashorn.lexer.xmlliterals + +If this property it set, it means that the Lexer should attempt to +parse XML literals, which would otherwise generate syntax +errors. Warning: there are currently no unit tests for this +functionality. + +XML literals, when this is enabled, end up as standard LiteralNodes in +the IR. + + +SYSTEM_PROPERTY: nashorn.debug + +If this property is set to true, Nashorn runs in Debug mode. Debug +mode is slightly slower, as for example statistics counters are enabled +during the run. Debug mode makes available a NativeDebug instance +called "Debug" in the global space that can be used to print property +maps and layout for script objects, as well as a "dumpCounters" method +that will print the current values of the previously mentioned stats +counters. + +These functions currently exists for Debug: + +"map" - print(Debug.map(x)) will dump the PropertyMap for object x to +stdout (currently there also exist functions called "embedX", where X +is a value from 0 to 3, that will dump the contents of the embed pool +for the first spill properties in any script object and "spill", that +will dump the contents of the growing spill pool of spill properties +in any script object. This is of course subject to change without +notice, should we change the script object layout. + +"methodHandle" - this method returns the method handle that is used +for invoking a particular script function. + +"identical" - this method compares two script objects for reference +equality. It is a == Java comparison + +"dumpCounters" - will dump the debug counters' current values to +stdout. + +Currently we count number of ScriptObjects in the system, number of +Scope objects in the system, number of ScriptObject listeners added, +removed and dead (without references). + +We also count number of ScriptFunctions, ScriptFunction invocations +and ScriptFunction allocations. + +Furthermore we count PropertyMap statistics: how many property maps +exist, how many times were property maps cloned, how many times did +the property map history cache hit, prevent new allocations, how many +prototype invalidations were done, how many time the property map +proto cache hit. + +Finally we count callsite misses on a per callsite bases, which occur +when a callsite has to be relinked, due to a previous assumption of +object layout being invalidated. + + +SYSTEM PROPERTY: nashorn.methodhandles.debug, +nashorn.methodhandles.debug=create + +If this property is enabled, each MethodHandle related call that uses +the java.lang.invoke package gets its MethodHandle intercepted and an +instrumentation printout of arguments and return value appended to +it. This shows exactly which method handles are executed and from +where. (Also MethodTypes and SwitchPoints). This can be augmented with +more information, for example, instance count, by subclassing or +further extending the TraceMethodHandleFactory implementation in +MethodHandleFactory.java. + +If the property is specialized with "=create" as its option, +instrumentation will be shown for method handles upon creation time +rather than at runtime usage. + + +SYSTEM PROPERTY: nashorn.methodhandles.debug.stacktrace + +This does the same as nashorn.methodhandles.debug, but when enabled +also dumps the stack trace for every instrumented method handle +operation. Warning: This is enormously verbose, but provides a pretty +decent "grep:able" picture of where the calls are coming from. + +See the description of the codegen logger below for a more verbose +description of this option + + +SYSTEM PROPERTY: nashorn.scriptfunction.specialization.disable + +There are several "fast path" implementations of constructors and +functions in the NativeObject classes that, in their original form, +take a variable amount of arguments. Said functions are also declared +to take Object parameters in their original form, as this is what the +JavaScript specification mandates. + +However, we often know quite a lot more at a callsite of one of these +functions. For example, Math.min is called with a fixed number (2) of +integer arguments. The overhead of boxing these ints to Objects and +folding them into an Object array for the generic varargs Math.min +function is an order of magnitude slower than calling a specialized +implementation of Math.min that takes two integers. Specialized +functions and constructors are identified by the tag +@SpecializedFunction and @SpecializedConstructor in the Nashorn +code. The linker will link in the most appropriate (narrowest types, +right number of types and least number of arguments) specialization if +specializations are available. + +Every ScriptFunction may carry specializations that the linker can +choose from. This framework will likely be extended for user defined +functions. The compiler can often infer enough parameter type info +from callsites for in order to generate simpler versions with less +generic Object types. This feature depends on future lazy jitting, as +there tend to be many calls to user defined functions, some where the +callsite can be specialized, some where we mostly see object +parameters even at the callsite. + +If this system property is set to true, the linker will not attempt to +use any specialized function or constructor for native objects, but +just call the generic one. + + +SYSTEM PROPERTY: nashorn.tcs.miss.samplePercent= + +When running with the trace callsite option (-tcs), Nashorn will count +and instrument any callsite misses that require relinking. As the +number of relinks is large and usually produces a lot of output, this +system property can be used to constrain the percentage of misses that +should be logged. Typically this is set to 1 or 5 (percent). 1% is the +default value. + + +SYSTEM_PROPERTY: nashorn.profilefile= + +When running with the profile callsite options (-pcs), Nashorn will +dump profiling data for all callsites to stderr as a shutdown hook. To +instead redirect this to a file, specify the path to the file using +this system property. + + +=============== +2. The loggers. +=============== + +The Nashorn loggers can be used to print per-module or per-subsystem +debug information with different levels of verbosity. The loggers for +a given subsystem are available are enabled by using + +--log=[:] + +on the command line. + +Here identifies the name of the subsystem to be logged +and the optional colon and level argument is a standard +java.util.logging.Level name (severe, warning, info, config, fine, +finer, finest). If the level is left out for a particular subsystem, +it defaults to "info". Any log message logged as the level or a level +that is more important will be output to stderr by the logger. + +Several loggers can be enabled by a single command line option, by +putting a comma after each subsystem/level tuple (or each subsystem if +level is unspecified). The --log option can also be given multiple +times on the same command line, with the same effect. + +For example: --log=codegen,fields:finest is equivalent to +--log=codegen:info --log=fields:finest + +The subsystems that currently support logging are: + + +* compiler + +The compiler is in charge of turning source code and function nodes +into byte code, and installs the classes into a class loader +controlled from the Context. Log messages are, for example, about +things like new compile units being allocated. The compiler has global +settings that all the tiers of codegen (e.g. Lower and CodeGenerator) +use. + + +* codegen + +The code generator is the emitter stage of the code pipeline, and +turns the lowest tier of a FunctionNode into bytecode. Codegen logging +shows byte codes as they are being emitted, line number information +and jumps. It also shows the contents of the bytecode stack prior to +each instruction being emitted. This is a good debugging aid. For +example: + +[codegen] #41 line:2 (f)_afc824e +[codegen] #42 load symbol x slot=2 +[codegen] #43 {1:O} load int 0 +[codegen] #44 {2:I O} dynamic_runtime_call GT:ZOI_I args=2 returnType=boolean +[codegen] #45 signature (Ljava/lang/Object;I)Z +[codegen] #46 {1:Z} ifeq ternary_false_5402fe28 +[codegen] #47 load symbol x slot=2 +[codegen] #48 {1:O} goto ternary_exit_107c1f2f +[codegen] #49 ternary_false_5402fe28 +[codegen] #50 load symbol x slot=2 +[codegen] #51 {1:O} convert object -> double +[codegen] #52 {1:D} neg +[codegen] #53 {1:D} convert double -> object +[codegen] #54 {1:O} ternary_exit_107c1f2f +[codegen] #55 {1:O} return object + +shows a ternary node being generated for the sequence "return x > 0 ? +x : -x" + +The first number on the log line is a unique monotonically increasing +emission id per bytecode. There is no guarantee this is the same id +between runs. depending on non deterministic code +execution/compilation, but for small applications it usually is. If +the system variable -Dnashorn.codegen.debug.trace= is set, where x +is a bytecode emission id, a stack trace will be shown as the +particular bytecode is about to be emitted. This can be a quick way to +determine where it comes from without attaching the debugger. "Who +generated that neg?" + +The --log=codegen option is equivalent to setting the system variable +"nashorn.codegen.debug" to true. + + +* lower + +The lowering annotates a FunctionNode with symbols for each identifier +and transforms high level constructs into lower level ones, that the +CodeGenerator consumes. + +Lower logging typically outputs things like post pass actions, +insertions of casts because symbol types have been changed and type +specialization information. Currently very little info is generated by +this logger. This will probably change. + + +* access + +The --log=access option is equivalent to setting the system variable +"nashorn.callsiteaccess.debug" to true. There are several levels of +the access logger, usually the default level "info" is enough + +It is very simple to create your own logger. Use the DebugLogger class +and give the subsystem name as a constructor argument. + + +* fields + +The --log=fields option (at info level) is equivalent to setting the +system variable "nashorn.fields.debug" to true. At the info level it +will only show info about type assumptions that were invalidated. If +the level is set to finest, it will also trace every AccessorProperty +getter and setter in the program, show arguments, return values +etc. It will also show the internal representation of respective field +(Object in the normal case, unless running with the dual field +representation) \ No newline at end of file diff --git a/nashorn/docs/genshelldoc.js b/nashorn/docs/genshelldoc.js new file mode 100644 index 00000000000..c3cf5c305e6 --- /dev/null +++ b/nashorn/docs/genshelldoc.js @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2010, 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. + */ + +/** + * Generate HTML documentation for shell tool. Re-run this tool to regenerate + * html doc when you change options. + * + * Usage: + * + * jjs -scripting genshelldoc.js > shell.html + */ + +var Options = Packages.jdk.nashorn.internal.runtime.options.Options; +var title = "Nashorn command line shell tool"; + +print(< + + +${title} + + + +

    Usage

    +

    + +jjs <options> <script-files> [ -- <script-arguments> ] + +

    + +

    ${title} options

    + + + + + + + + +PREFIX); + +for each (opt in Options.validOptions) { + +var isTimezone = (opt.type == "timezone"); +var defValue = opt.defaultValue; +if (defValue == null) { + defValue = "<none>"; +} + +if (isTimezone) { + // don't output current user's timezone + defValue = "<default-timezone>" +} + +print(< + + + + + +ROW); + +} + +print(< + + +SUFFIX); diff --git a/nashorn/make/Makefile b/nashorn/make/Makefile new file mode 100644 index 00000000000..7d768708853 --- /dev/null +++ b/nashorn/make/Makefile @@ -0,0 +1,224 @@ +# +# Copyright (c) 2010, 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. +# + +# Makefile for nashorn: wrapper around Ant build.xml file + +# +# On Solaris, the standard 'make' utility will not work with these makefiles. +# This little rule is only understood by Solaris make, and is harmless +# when seen by the GNU make tool. If using Solaris make, this causes the +# make command to fail. +# +SUN_MAKE_TEST:sh = @echo "ERROR: PLEASE USE GNU VERSION OF MAKE"; exit 33 + +# +# Minimal platform defs +# Need FullPath because we can't rely on gnumake abspath, until we use v3.81 +# + +SYSTEM_UNAME := $(shell uname) + +# Where is unwanted output to be delivered? +# On Windows, MKS uses the special file "NUL", cygwin uses the customary unix file. +ifeq ($(SYSTEM_UNAME), Windows_NT) +DEV_NULL = NUL +else +DEV_NULL = /dev/null +endif + +ifneq (,$(findstring CYGWIN,$(SYSTEM_UNAME))) +USING_CYGWIN = true +endif + +ifdef USING_CYGWIN +define FullPath +$(shell cygpath -a -s -m $1 2> $(DEV_NULL)) +endef +else +define FullPath +$(shell cd $1 2> $(DEV_NULL) && pwd) +endef +endif + +# +# Makefile args +# + +ifdef QUIET + ANT_OPTIONS += -quiet +endif + +ifdef VERBOSE + ANT_OPTIONS += -verbose -debug +endif + +ifdef JDK_VERSION + ANT_OPTIONS += -Djdk.version=$(JDK_VERSION) +endif + +ifdef FULL_VERSION + ANT_OPTIONS += -Dfull.version='$(FULL_VERSION)' # will contain spaces +endif + +ifdef MILESTONE +ifneq ($(MILESTONE),fcs) + ANT_OPTIONS += -Dmilestone=$(MILESTONE) +else + ANT_OPTIONS += -Drelease=$(JDK_VERSION) +endif +endif + +ifdef BUILD_NUMBER + ANT_OPTIONS += -Dbuild.number=$(BUILD_NUMBER) +else + ifdef JDK_BUILD_NUMBER + ANT_OPTIONS += -Dbuild.number=$(JDK_BUILD_NUMBER) + endif +endif + +ifeq ($(VARIANT), DBG) + ANT_OPTIONS += -Djavac.debug=true +else + ifeq ($(VARIANT), OPT) + ANT_OPTIONS += -Djavac.debug=false + endif +endif + +ifeq ($(DEBUG_CLASSFILES), true) + ANT_OPTIONS += -Djavac.debug=true + ANT_OPTIONS += -Ddebug.classfiles=true +endif + +# Note: jdk/make/common/Defs.gmk uses LANGUAGE_VERSION (-source NN) +# and the somewhat misnamed CLASS_VERSION (-target NN) +ifdef TARGET_CLASS_VERSION + ANT_OPTIONS += -Djavac.target=$(TARGET_CLASS_VERSION) +else + ifdef JAVAC_TARGET_ARG + ANT_OPTIONS += -Djavac.target=$(JAVAC_TARGET_ARG) + endif +endif + +ifdef SOURCE_LANGUAGE_VERSION + ANT_OPTIONS += -Djavac.source=$(SOURCE_LANGUAGE_VERSION) +else + ifdef JAVAC_SOURCE_ARG + ANT_OPTIONS += -Djavac.source=$(JAVAC_SOURCE_ARG) + endif +endif + +ifdef ALT_BOOTDIR + ANT_OPTIONS += -Dboot.java.home=$(ALT_BOOTDIR) + ANT_JAVA_HOME = JAVA_HOME=$(ALT_BOOTDIR) +endif + +# To facilitate bootstrapping, much of langtools can be compiled with (just) +# a boot JDK. However, some source files need to be compiled against +# new JDK API. In a bootstrap build, an import JDK may not be available, +# so build.xml can also build against the source files in a jdk repo, +# in which case it will automatically generate stub files for the new JDK API. +ifdef JDK_TOPDIR + ANT_OPTIONS += -Dimport.jdk=$(JDK_TOPDIR) +else + ifdef ALT_JDK_TOPDIR + ANT_OPTIONS += -Dimport.jdk=$(ALT_JDK_TOPDIR) + else + ifdef ALT_JDK_IMPORT_PATH + ANT_OPTIONS += -Dimport.jdk=$(ALT_JDK_IMPORT_PATH) + endif + endif +endif + +ifdef ALT_OUTPUTDIR + OUTPUTDIR = $(ALT_OUTPUTDIR) + ANT_OPTIONS += -Dbuild.dir=$(ALT_OUTPUTDIR)/build + ANT_OPTIONS += -Ddist.dir=$(ALT_OUTPUTDIR)/dist +else + OUTPUTDIR = .. +endif +#ABS_OUTPUTDIR = $(abspath $(OUTPUTDIR)) +ABS_OUTPUTDIR = $(call FullPath,$(OUTPUTDIR)) + +ANT_TMPDIR = $(ABS_OUTPUTDIR)/build/ant-tmp +ANT_OPTS = ANT_OPTS=-Djava.io.tmpdir='$(ANT_TMPDIR)' + +ifdef FINDBUGS_HOME + ANT_OPTIONS += -Dfindbugs.home=$(FINDBUGS_HOME) +endif + +ifdef ANT_HOME + ANT = $(ANT_HOME)/bin/ant + ifneq ($(shell test -x $(ANT) && echo OK), OK) + $(error $(ANT) not found -- please update ANT_HOME) + endif +else + ANT = ant + ifneq ($(shell test -x "`which $(ANT)`" && echo OK), OK) + $(error 'ant' not found -- please set ANT_HOME or put 'ant' on your PATH) + endif +endif + +# Default target and expected 'do everything' target +# comments docs to avoid too many ASM warnings +# all: test docs + +all: test + +# Standard make clobber target +clobber: clean + +# All ant targets of interest +ANT_TARGETS = clean jar javadoc shelldoc docs test test262 test262parallel # for now + +# Create diagnostics log (careful, ant 1.8.0 -diagnostics always does an exit 1) +$(OUTPUTDIR)/build/ant-diagnostics.log: + @mkdir -p $(OUTPUTDIR)/build $(ANT_TMPDIR) + @$(RM) $@ + $(ANT_JAVA_HOME) $(ANT_OPTS) $(ANT) -diagnostics > $@ ; \ + $(ANT_JAVA_HOME) $(ANT_OPTS) $(ANT) -version >> $@ + +# Create a make target for each +$(ANT_TARGETS): $(OUTPUTDIR)/build/ant-diagnostics.log + @ mkdir -p $(OUTPUTDIR)/build $(ANT_TMPDIR) + $(ANT_JAVA_HOME) $(ANT_OPTS) $(ANT) $(ANT_OPTIONS) $@ + +#------------------------------------------------------------------- +# +# Targets for Oracle's internal JPRT build system + +CD = cd +ZIP = zip + +JPRT_ARCHIVE_BUNDLE=$(ABS_OUTPUTDIR)/$(JPRT_BUILD_FLAVOR)-bundle.zip + +jprt_build_product jprt_build_debug jprt_build_fastdebug: all + ( $(CD) $(OUTPUTDIR) && \ + $(ZIP) -q -r $(JPRT_ARCHIVE_BUNDLE) build dist ) + +#------------------------------------------------------------------- + +# Declare these phony (not filenames) +.PHONY: $(ANT_TARGETS) all clobber \ + jprt_build_product jprt_build_debug jprt_build_fastdebug diff --git a/nashorn/make/build-benchmark.xml b/nashorn/make/build-benchmark.xml new file mode 100644 index 00000000000..b6dce19565e --- /dev/null +++ b/nashorn/make/build-benchmark.xml @@ -0,0 +1,348 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nashorn/make/build-nasgen.xml b/nashorn/make/build-nasgen.xml new file mode 100644 index 00000000000..fe5a67820bb --- /dev/null +++ b/nashorn/make/build-nasgen.xml @@ -0,0 +1,86 @@ + + + + Builds and runs nasgen. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml new file mode 100644 index 00000000000..79669a8020d --- /dev/null +++ b/nashorn/make/build.xml @@ -0,0 +1,355 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${line.separator} + + + + + + + + + + + + +
    + + +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \/ + /// + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Representation test failed - output differs! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diff --git a/nashorn/make/nbproject/ide-file-targets.xml b/nashorn/make/nbproject/ide-file-targets.xml new file mode 100644 index 00000000000..3a957ccd8a2 --- /dev/null +++ b/nashorn/make/nbproject/ide-file-targets.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + Must set property 'debug.class' + + + + + + + + + + + + + + + + + Must set property 'run.class' + + + + + + + + + diff --git a/nashorn/make/nbproject/ide-targets.xml b/nashorn/make/nbproject/ide-targets.xml new file mode 100644 index 00000000000..281672d8b5a --- /dev/null +++ b/nashorn/make/nbproject/ide-targets.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/nashorn/make/nbproject/jdk.xml b/nashorn/make/nbproject/jdk.xml new file mode 100644 index 00000000000..b6fa7ebba63 --- /dev/null +++ b/nashorn/make/nbproject/jdk.xml @@ -0,0 +1,179 @@ + + + + + + Permits selection of a JDK to use when building and running project. + See: http://www.netbeans.org/issues/show_bug.cgi?id=64160 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nbjdk.active=${nbjdk.active} nbjdk.home=${nbjdk.home} nbjdk.java=${nbjdk.java} nbjdk.javac=${nbjdk.javac} nbjdk.javadoc=${nbjdk.javadoc} nbjdk.bootclasspath=${nbjdk.bootclasspath} nbjdk.valid=${nbjdk.valid} have-jdk-1.4=${have-jdk-1.4} have-jdk-1.5=${have-jdk-1.5} + + + + + Warning: nbjdk.active=${nbjdk.active} or nbjdk.home=${nbjdk.home} is an invalid Java platform; ignoring and using ${jdkhome.presumed} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nashorn/make/nbproject/nbjdk.properties b/nashorn/make/nbproject/nbjdk.properties new file mode 100644 index 00000000000..6260c35a3d8 --- /dev/null +++ b/nashorn/make/nbproject/nbjdk.properties @@ -0,0 +1,24 @@ +# +# Copyright (c) 2010, 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. +# +nbjdk.active=JDK_1.8 + diff --git a/nashorn/make/nbproject/nbjdk.xml b/nashorn/make/nbproject/nbjdk.xml new file mode 100644 index 00000000000..cbd7af38a5f --- /dev/null +++ b/nashorn/make/nbproject/nbjdk.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nashorn/make/nbproject/project.xml b/nashorn/make/nbproject/project.xml new file mode 100644 index 00000000000..ee88965a853 --- /dev/null +++ b/nashorn/make/nbproject/project.xml @@ -0,0 +1,177 @@ + + + + org.netbeans.modules.ant.freeform + + + nashorn + + + + nashorn + + + + + . + UTF-8 + + + + ../src + + + + ../test/src + + + + ../buildtools/nasgen/src + + + + java + ../test/src + UTF-8 + + + + java + ../src + UTF-8 + + + + java + ../buildtools/nasgen/src + UTF-8 + + + + + + jar + + + + clean + + + + javadoc + + + + test + + + + clean + jar + + + + run + + + + debug-nb + + + + debug-selected-file-in-src + + debug.class + test/src + \.java$ + java-name + + + + + + + + run-selected-file-in-src + + run.class + test/src + \.java$ + java-name + + + + + + + + + + + ../test/src + + + + ../src + + + + ../buildtools/nasgen/src + + + build.xml + + + + + + + + + + + + + + + + + ../test/src + + ../test/lib/testng.jar:../build/classes:../src + 1.7 + + + ../src + ../build/dynalink/dynalink.jar + 1.7 + + + ../buildtools/nasgen/src + ../build/classes:../src + 1.7 + + + + diff --git a/nashorn/make/project.properties b/nashorn/make/project.properties new file mode 100644 index 00000000000..64ec4083406 --- /dev/null +++ b/nashorn/make/project.properties @@ -0,0 +1,223 @@ +# +# Copyright (c) 2010, 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. +# + +application.title=nashorn + +# source and target levels +build.compiler=modern +javac.source=1.7 +javac.target=1.7 + +# nashorn version information +nashorn.version=0.1 +nashorn.fullversion=0.1 +nashorn.product.name=Oracle Nashorn + +# This directory is removed when the project is cleaned: +build.dir=build +build.classes.dir=${build.dir}/classes +build.zip=${build.dir}/nashorn.zip +build.gzip=${build.dir}/nashorn.tar.gz + +# nashorn Shell tool +nashorn.shell.tool=jdk.nashorn.tools.Shell + +# nasgen tool +nasgen.tool=jdk.nashorn.internal.tools.nasgen.Main + +# parallel test runner tool +parallel.test.runner=jdk.nashorn.internal.test.framework.ParallelTestRunner + +# test classes directory +build.test.classes.dir=${build.dir}/test/classes +# test results directory +build.test.results.dir=${build.dir}/test/reports + +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/nashorn.jar +dist.javadoc.dir=${dist.dir}/javadoc + +# directory where asm project lives +asm.dir=../asm +asm.src.dir=${asm.dir}/src + +# jars refererred +file.reference.testng.jar=test/lib/testng.jar + +# Set testng verbose level +# From TestNG docs: "the verbosity level (0 to 10 where 10 is most detailed) +# Actually, this is a lie: you can specify -1 and this will put TestNG in +# debug mode (no longer slicing off stack traces and all)." + +testng.verbose=2 + +# TestNG listeners - we want to replace TestNG's own JUnit +# reporter, but want everything else provided by default +# Unfortunately, we've to clone the other default reporters here. + +testng.listeners=\ + org.testng.reporters.SuiteHTMLReporter, \ + org.testng.reporters.jq.Main, \ + org.testng.reporters.FailedReporter, \ + org.testng.reporters.XMLReporter \ + org.testng.reporters.EmailableReporter, \ + jdk.nashorn.internal.test.framework.JSJUnitReportReporter + +# Define the version of Dynalink that is used. Version types are either +# 'snapshot' or 'release'. When it is 'snapshot', the version must have +# "-SNAPSHOT" suffix and the jar version will have a timestamp in it. When +# it's 'release', the version has no suffix, and the jar version is +# identical to version - fun with Maven central. +dynalink.version=0.5-SNAPSHOT +dynalink.version.type=snapshot +dynalink.jar.version=0.5-20121218.140128-11 +dynalink.dir.name=dynalink +dynalink.dir=build/${dynalink.dir.name} +dynalink.jar=${dynalink.dir}/dynalink.jar + +javac.debug=true +javac.encoding=ascii +javac.classpath=\ + ${build.classes.dir}:\ + ${dynalink.jar} +javac.test.classpath=\ + ${build.classes.dir}:\ + ${build.test.classes.dir}:\ + ${file.reference.testng.jar} + +meta.inf.dir=${src.dir}/META-INF + +run.classpath=\ + ${build.classes.dir} + +# test scripts to run +test.dir=test +test.script.dir=test/script +test.basic.dir=test/script/basic +test.error.dir=test/script/error +test.sandbox.dir=test/script/sandbox +test.external.dir=test/script/external +test262.dir=${test.external.dir}/test262 +test262.suite.dir=${test262.dir}/test/suite + +test-sys-prop.test.dir=${test.dir} +test-sys-prop.test.js.roots=${test.basic.dir} ${test.error.dir} ${test.sandbox.dir} +test-sys-prop.test262.suite.dir=${test262.suite.dir} +test-sys-prop.es5conform.testcases.dir=${test.external.dir}/ES5Conform/TestCases +test-sys-prop.test.basic.dir=${test.basic.dir} + +# framework root for our script tests +test-sys-prop.test.js.framework=${test.script.dir}/assert.js + +# Control the verbosity of ParserTest +test-sys-prop.parsertest.verbose=false + +# turn on/off scripting mode for parser tests +test-sys-prop.parsertest.scripting=true + +# turn on/off test262 scripts for parser tests +test-sys-prop.parsertest.test262=false + +# Control the verbosity of the CompilerTest +test-sys-prop.compilertest.verbose=false + +# turn on/off scripting mode for compiler tests +test-sys-prop.compilertest.scripting=true + +# turn on/off test262 scripts for compiler tests +test-sys-prop.compilertest.test262=false + +# test directory to be excluded. +test-sys-prop.test.js.exclude.dir=${test.script.dir}/currently-failing ${test.external.dir} + +# run everything that's js in here, without checking file headers for test annotations +test-sys-prop.test.js.unchecked.dir=${test262.dir} + +# test root for octane +octane-test-sys-prop.test.js.roots=${test.external.dir}/octane/benchmarks + +# framework root for octane +octane-test-sys-prop.test.js.framework=${test.basic.dir}/run-octane.js + +# list of tests to be excluded +octane-test-sys-prop.test.js.exclude.list=base.js + +# test root for sunspider +sunspider-test-sys-prop.test.js.roots=${test.external.dir}/sunspider/ + +# framework root for sunspider +sunspider-test-sys-prop.test.js.framework=${test.basic.dir}/runsunspider.js + +# list of tests to be excluded +sunspider-test-sys-prop.test.js.exclude.list= + +# execute our script tests in shared nashorn context or not? +test-sys-prop.test.js.shared.context=false + +# execute test262 tests in shared nashorn context or not? +test262-test-sys-prop.test.js.shared.context=true + +# test262 test root +test262-test-sys-prop.test.js.roots=${test262.suite.dir} +# test262 enable/disable strict mode tests +test262-test-sys-prop.test.js.enable.strict.mode=true + +# file containing test262 tests to be excluded +# test262-test-sys-prop.test.js.excludes.file=${test262.dir}/test/config/excludelist.xml + +# list of test262 test dirs to be excluded +test262-test-sys-prop.test.js.exclude.dir=\ + ${test262.suite.dir}/intl402/ + +# test262 test frameworks +test262-test-sys-prop.test.js.framework=\ + -timezone=PST \ + ${test.script.dir}/test262.js \ + ${test262.dir}/test/harness/framework.js \ + ${test262.dir}/test/harness/sta.js + +run.test.classpath=\ + ${file.reference.testng.jar}:\ + ${build.test.classes.dir} +src.dir=src +test.src.dir=test/src + +# -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods +# add '-Dtest.js.outofprocess' to run each test in a new sub-process +run.test.jvmargs=-server -Xmx3G -XX:-TieredCompilation -esa -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8 +#-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M +run.test.jvmargs.octane=-Xms2G -Xmx2G ${run.test.jvmargs} + +run.test.jvmsecurityargs=-Xverify:all -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy + +# path of rhino.jar for benchmarks +rhino.jar= + +v8.shell=d8 + +#path to rhino jar file +octaneperf-sys-prop.rhino.jar=${rhino.jar} + +#timeout for performance tests in minutes +octaneperf-sys-prop.timeout.value=10 diff --git a/nashorn/samples/counters.js b/nashorn/samples/counters.js new file mode 100644 index 00000000000..eb55d2870cf --- /dev/null +++ b/nashorn/samples/counters.js @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2010, 2012, 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 file can be run along with any script you want to run + * to print aggregate stat counters from nashorn. + * + * Usage: jjs counters.js + */ + +Debug.dumpCounters(); diff --git a/nashorn/samples/letter.js b/nashorn/samples/letter.js new file mode 100644 index 00000000000..d45bd086b45 --- /dev/null +++ b/nashorn/samples/letter.js @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010, 2012, 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. + */ + +/** + * Demonstrates "heredoc" feature with "scripting" mode. + * + * Usage: jjs -scripting letter.js -- + */ + +# This is shell-style line comment +var obj = { sender: $ARG[0], recipient: $ARG[1] }; + +// JavaScript style line comment is ok too. +print(<"); +} + +with (imports) { + var reader = new BufferedReader(new InputStreamReader(System["in"])); + var line = null; + prompt(); + while ((line = reader.readLine()) != null) { + if (line != "") { + var args = line.split(" "); + try { + if (args[0] == "eval") { + var code = line.substring("eval".length); + var res = eval(code); + if (res != undefined) { + print(res); + } + } else { + var argList = new ArrayList(); + for (i in args) { argList.add(args[i]); } + var procBuilder = new ProcessBuilder(argList); + procBuilder.redirectErrorStream(); + var proc = procBuilder.start(); + var out = new BufferedReader(new InputStreamReader(proc.getInputStream())); + var line = null; + while ((line = out.readLine()) != null) { + System.out.println(line); + } + proc.waitFor(); + } + } catch (e) { + print(e); + } + } + prompt(); + } +} diff --git a/nashorn/samples/test.js b/nashorn/samples/test.js new file mode 100644 index 00000000000..e1d30b0ac51 --- /dev/null +++ b/nashorn/samples/test.js @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010, 2012, 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. + */ + +print("Hello World"); diff --git a/nashorn/samples/uniq.js b/nashorn/samples/uniq.js new file mode 100644 index 00000000000..157c4f59451 --- /dev/null +++ b/nashorn/samples/uniq.js @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2010, 2012, 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. + */ + +/** + * Prints unique lines from a given file. + */ + +if (arguments.length != 1) { + print("Usage: jjs uniq.js -- "); + java.lang.System.exit(1); +} + +var imports = new JavaImporter(java.io); + +var uniqueLines = {}; +with (imports) { + var reader = new BufferedReader(new FileReader(arguments[0])); + while ((line = reader.readLine()) != null) { + // using a JS object as a map... + uniqueLines[line] = true; + } +} + +// now print the collected lines +for (i in uniqueLines) { + print(i); +} diff --git a/nashorn/src/META-INF/MANIFEST.MF b/nashorn/src/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..b61190e5ba9 --- /dev/null +++ b/nashorn/src/META-INF/MANIFEST.MF @@ -0,0 +1,5 @@ +Manifest-Version: 1.0 +Main-Class: jdk.nashorn.tools.Shell + +Name: jdk/nashorn/ +Implementation-Vendor: Oracle Corporation diff --git a/nashorn/src/META-INF/services/javax.script.ScriptEngineFactory b/nashorn/src/META-INF/services/javax.script.ScriptEngineFactory new file mode 100644 index 00000000000..ec7da013a99 --- /dev/null +++ b/nashorn/src/META-INF/services/javax.script.ScriptEngineFactory @@ -0,0 +1,25 @@ +# +# Copyright (c) 2010, 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. +# +jdk.nashorn.api.scripting.NashornScriptEngineFactory diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornException.java b/nashorn/src/jdk/nashorn/api/scripting/NashornException.java new file mode 100644 index 00000000000..f1a42648b7e --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornException.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.api.scripting; + +/** + * This is base exception for all Nashorn exceptions. These originate from user's + * ECMAScript code. Example: script parse errors, exceptions thrown from scripts. + * Note that ScriptEngine methods like "eval", "invokeMethod", "invokeFunction" + * will wrap this as ScriptException and throw it. But, there are cases where user + * may need to access this exception (or implementation defined subtype of this). + * For example, if java interface is implemented by a script object or Java access + * to script object properties via java.util.Map interface. In these cases, user + * code will get an instance of this or implementation defined subclass. + */ +@SuppressWarnings("serial") +public class NashornException extends RuntimeException { + // script file name + private String fileName; + // script line number + private int line; + // script column number + private int column; + + /** + * Constructor + * + * @param msg exception message + */ + protected NashornException(final String msg) { + super(msg); + } + + /** + * Constructor + * @param msg exception message + * @param cause exception cause + */ + protected NashornException(final String msg, final Throwable cause) { + super(msg, cause); + } + + /** + * Constructor + * + * @param cause exception cause + */ + protected NashornException(final Throwable cause) { + super(cause); + } + + /** + * Get the source file name for this {@code NashornException} + * @return the file name + */ + public final String getFileName() { + return fileName; + } + + /** + * Set the source file name for this {@code NashornException} + * @param fileName file name + */ + protected final void setFileName(final String fileName) { + this.fileName = fileName; + } + + /** + * Get the line number for this {@code NashornException} + * @return the line number + */ + public final int getLineNumber() { + return line; + } + + /** + * Set the line number for this {@code NashornException} + * @param line line number + */ + protected final void setLineNumber(final int line) { + this.line = line; + } + + /** + * Get the column for this {@code NashornException} + * @return the column + */ + public final int getColumnNumber() { + return column; + } + + /** + * Set the column number for this {@code NashornException} + * @param column the column + */ + public final void setColumnNumber(final int column) { + this.column = column; + } +} diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java new file mode 100644 index 00000000000..3fde40aae94 --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java @@ -0,0 +1,521 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.api.scripting; + +import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError; +import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; +import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; +import static jdk.nashorn.internal.runtime.linker.Lookup.MH; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import javax.script.AbstractScriptEngine; +import javax.script.Bindings; +import javax.script.Compilable; +import javax.script.CompiledScript; +import javax.script.Invocable; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptException; +import javax.script.SimpleBindings; +import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.ErrorManager; +import jdk.nashorn.internal.runtime.GlobalObject; +import jdk.nashorn.internal.runtime.Property; +import jdk.nashorn.internal.runtime.ScriptFunction; +import jdk.nashorn.internal.runtime.ScriptObject; +import jdk.nashorn.internal.runtime.ScriptRuntime; +import jdk.nashorn.internal.runtime.Source; +import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; +import jdk.nashorn.internal.runtime.options.Options; + +/** + * JSR-223 compliant script engine for Nashorn. Instances are not created directly, but rather returned through + * {@link NashornScriptEngineFactory#getScriptEngine()}. Note that this engine implements the {@link Compilable} and + * {@link Invocable} interfaces, allowing for efficient precompilation and repeated execution of scripts. + * @see NashornScriptEngineFactory + */ + +public final class NashornScriptEngine extends AbstractScriptEngine implements Compilable, Invocable { + + private final ScriptEngineFactory factory; + private final Context nashornContext; + private final ScriptObject global; + + // default options passed to Nashorn Options object + private static final String[] DEFAULT_OPTIONS = new String[] { "-scripting", "-af", "-doe" }; + + NashornScriptEngine(final NashornScriptEngineFactory factory) { + this(factory, DEFAULT_OPTIONS); + } + + @SuppressWarnings("LeakingThisInConstructor") + NashornScriptEngine(final NashornScriptEngineFactory factory, final String[] args) { + this.factory = factory; + final Options options = new Options("nashorn"); + options.process(args); + + // throw ParseException on first error from script + final ErrorManager errors = new Context.ThrowErrorManager(); + // create new Nashorn Context and get global object + this.nashornContext = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Context run() { + try { + return new Context(options, errors); + } catch (final RuntimeException e) { + if (Context.DEBUG) { + e.printStackTrace(); + } + throw e; + } + } + }); + + // create new global object + this.global = nashornContext.createGlobal(); + + // current ScriptContext exposed as "context" + global.addOwnProperty("context", Property.NOT_ENUMERABLE, context); + // current ScriptEngine instance exposed as "engine". We added @SuppressWarnings("LeakingThisInConstructor") as + // NetBeans identifies this assignment as such a leak - this is a false positive as we're setting this property + // in the Global of a Context we just created - both the Context and the Global were just created and can not be + // seen from another thread outside of this constructor. + global.addOwnProperty("engine", Property.NOT_ENUMERABLE, this); + // global script arguments + global.addOwnProperty("arguments", Property.NOT_ENUMERABLE, UNDEFINED); + + // evaluate engine initial script + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Void run() throws ScriptException { + evalEngineScript(); + return null; + } + }); + } catch (final PrivilegedActionException e) { + if (Context.DEBUG) { + e.printStackTrace(); + } + throw new RuntimeException(e); + } + } + + @Override + public Object eval(final Reader reader, final ScriptContext ctxt) throws ScriptException { + try { + return evalImpl(Source.readFully(reader), ctxt); + } catch (final IOException e) { + throw new ScriptException(e); + } + } + + @Override + public Object eval(final String script, final ScriptContext ctxt) throws ScriptException { + return evalImpl(script.toCharArray(), ctxt); + } + + /* + * FIXME: This is not exactly right. Script execution should actually + * put the variables in ENGINE_SCOPE bindings. But, it is difficult + * (not possible?) with the way ScriptObject is implemented. So, for now + * giving access to script variables by accessing it from "globals". This + * way at least engine.get("foo") will work whenever "foo" is a global var + * defined by eval'ed scripts. + */ + @Override + public Object get(final String key) { + Object value = super.get(key); + if (value == null) { + value = ScriptObjectMirror.wrap(global.get(key), global); + } + return (value == UNDEFINED) ? null : value; + } + + @Override + public ScriptEngineFactory getFactory() { + return factory; + } + + @Override + public Bindings createBindings() { + return new SimpleBindings(); + } + + // Compilable methods + + @Override + public CompiledScript compile(final Reader reader) throws ScriptException { + try { + return asCompiledScript(compileImpl(Source.readFully(reader), context)); + } catch (final IOException e) { + throw new ScriptException(e); + } + } + + @Override + public CompiledScript compile(final String str) throws ScriptException { + return asCompiledScript(compileImpl(str.toCharArray(), context)); + } + + // Invocable methods + + @Override + public Object invokeFunction(final String name, final Object... args) + throws ScriptException, NoSuchMethodException { + return invokeImpl(null, name, args); + } + + @Override + public Object invokeMethod(final Object self, final String name, final Object... args) + throws ScriptException, NoSuchMethodException { + if (self == null) { + throw new IllegalArgumentException("script object can not be null"); + } + return invokeImpl(self, name, args); + } + + private T getInterfaceInner(final Object self, final Class clazz) { + final Object realSelf; + if(self == null) { + realSelf = global; + } else if (!(self instanceof ScriptObject)) { + realSelf = ScriptObjectMirror.unwrap(self, global); + } else { + realSelf = self; + } + try { + final ScriptObject oldGlobal = Context.getGlobal(); + try { + if(oldGlobal != global) { + setNashornGlobal(global); + } + return clazz.cast(JavaAdapterFactory.getConstructor(realSelf.getClass(), clazz).invoke(realSelf)); + } finally { + if(oldGlobal != global) { + setNashornGlobal(oldGlobal); + } + } + } catch(final RuntimeException|Error e) { + throw e; + } catch(final Throwable t) { + throw new RuntimeException(t); + } + } + + @Override + public T getInterface(final Class clazz) { + return getInterfaceInner(null, clazz); + } + + @Override + public T getInterface(final Object self, final Class clazz) { + if (self == null) { + throw new IllegalArgumentException("script object can not be null"); + } + return getInterfaceInner(self, clazz); + } + + // These are called from the "engine.js" script + + /** + * This hook is used to search js global variables exposed from Java code. + * + * @param self 'this' passed from the script + * @param ctxt current ScriptContext in which name is searched + * @param name name of the variable searched + * @return the value of the named variable + */ + public Object __noSuchProperty__(final Object self, final ScriptContext ctxt, final String name) { + final int scope = ctxt.getAttributesScope(name); + if (scope != -1) { + return ScriptObjectMirror.unwrap(ctxt.getAttribute(name, scope), global); + } + + if (self == UNDEFINED) { + // scope access and so throw ReferenceError + referenceError(global, "not.defined", name); + } + + return UNDEFINED; + } + + /** + * This hook is used to call js global functions exposed from Java code. + * + * @param self 'this' passed from the script + * @param ctxt current ScriptContext in which method is searched + * @param name name of the method + * @param args arguments to be passed to the method + * @return return value of the called method + */ + public Object __noSuchMethod__(final Object self, final ScriptContext ctxt, final String name, final Object args) { + final int scope = ctxt.getAttributesScope(name); + Object value; + + if (scope != -1) { + value = ctxt.getAttribute(name, scope); + } else { + if (self == UNDEFINED) { + referenceError(global, "not.defined", name); + } else { + typeError(global, "no.such.function", name, ScriptRuntime.safeToString(global)); + } + return UNDEFINED; + } + + value = ScriptObjectMirror.unwrap(value, global); + + if (value instanceof Method) { + final Method method = (Method) value; + final int mods = method.getModifiers(); + if (Modifier.isStatic(mods) && Modifier.isPublic(mods)) { + value = MH.find((Method)value); + } + } + + if (value instanceof MethodHandle) { + value = ((GlobalObject)global).newScriptFunction(name, (MethodHandle)value, null, false); + } + + if (!(value instanceof ScriptFunction)) { + typeError(global, "not.a.function", name); + } + + if (value instanceof ScriptFunction) { + return ScriptObjectMirror.unwrap(ScriptRuntime.apply((ScriptFunction)value, global, args), global); + } + + typeError(global, "not.a.function", ScriptRuntime.safeToString(name)); + + return UNDEFINED; + } + + private void evalEngineScript() throws ScriptException { + final URL url = NashornScriptEngine.class.getResource("resources/engine.js"); + try { + final InputStream is = url.openStream(); + put(ScriptEngine.FILENAME, url); + try (final InputStreamReader isr = new InputStreamReader(is)) { + eval(isr); + } + } catch (final IOException e) { + throw new ScriptException(e); + } finally { + put(ScriptEngine.FILENAME, null); + } + } + + // scripts should see "context" and "engine" as variables + private void setContextVariables(final ScriptContext ctxt) { + ctxt.setAttribute("context", ctxt, ScriptContext.ENGINE_SCOPE); + // current ScriptContext exposed as "context" + global.set("context", ctxt, false); + Object args = ctxt.getAttribute("arguments"); + // if no arguments passed, make it empty array + if (args == null) { + args = ScriptRuntime.EMPTY_ARRAY; + } + args = ((GlobalObject)global).wrapAsObject(args); + global.set("arguments", args, false); + } + + private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException { + final ScriptObject oldGlobal = Context.getGlobal(); + final boolean globalChanged = (oldGlobal != global); + + Object self = selfObject; + + try { + if (globalChanged) { + setNashornGlobal(global); + } + + ScriptObject sobj; + Object value; + + self = ScriptObjectMirror.unwrap(self, global); + + // FIXME: should convert when self is not ScriptObject + if (self instanceof ScriptObject) { + sobj = (ScriptObject)self; + value = sobj.get(name); + } else if (self == null) { + self = global; + sobj = global; + value = sobj.get(name); + } else { + // Find the java method and make a ScriptFunction of it. + final Method[] methods = self.getClass().getMethods(); + Method target = null; + + for (final Method mth : methods) { + // choose the right overload by number of arguments -- don't + // care overload resolution for now.. + if (mth.getName().equals(name) && + mth.getParameterTypes().length == args.length) { + target = mth; + break; + } + } + if (target == null) { + throw new NoSuchMethodException(name); + } + final GlobalObject gobj = (GlobalObject) global; + value = gobj.newScriptFunction(name, MH.find(target), null, false); + } + + if (value instanceof ScriptFunction) { + final Object res; + try { + res = ScriptRuntime.apply((ScriptFunction)value, self, ScriptObjectMirror.unwrapArray(args, global)); + } catch (final Exception e) { + throwAsScriptException(e); + throw new AssertionError("should not reach here"); + } + return ScriptObjectMirror.wrap(res, global); + } + + throw new NoSuchMethodException(name); + } finally { + if (globalChanged) { + setNashornGlobal(oldGlobal); + } + } + } + + private Object evalImpl(final char[] buf, final ScriptContext ctxt) throws ScriptException { + return evalImpl(compileImpl(buf, ctxt), ctxt); + } + + private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt) throws ScriptException { + if (script == null) { + return null; + } + final ScriptObject oldGlobal = Context.getGlobal(); + final boolean globalChanged = (oldGlobal != global); + try { + if (globalChanged) { + setNashornGlobal(global); + } + + setContextVariables(ctxt); + Object res = ScriptRuntime.apply(script, global); + res = ScriptObjectMirror.wrap(res, global); + return (res == UNDEFINED) ? null : res; + } catch (final Exception e) { + throwAsScriptException(e); + throw new AssertionError("should not reach here"); + } finally { + if (globalChanged) { + setNashornGlobal(oldGlobal); + } + } + } + + private static void throwAsScriptException(final Exception e) throws ScriptException { + if (e instanceof ScriptException) { + throw (ScriptException)e; + } else if (e instanceof NashornException) { + final NashornException ne = (NashornException)e; + final ScriptException se = new ScriptException( + ne.getMessage(), ne.getFileName(), + ne.getLineNumber(), ne.getColumnNumber()); + se.initCause(e); + throw se; + } else if (e instanceof RuntimeException) { + throw (RuntimeException)e; + } else { + // wrap any other exception as ScriptException + throw new ScriptException(e); + } + } + + private CompiledScript asCompiledScript(final ScriptFunction script) { + return new CompiledScript() { + @Override + public Object eval(final ScriptContext ctxt) throws ScriptException { + return evalImpl(script, ctxt); + } + @Override + public ScriptEngine getEngine() { + return NashornScriptEngine.this; + } + }; + } + + private ScriptFunction compileImpl(final char[] buf, final ScriptContext ctxt) throws ScriptException { + final ScriptObject oldGlobal = Context.getGlobal(); + final boolean globalChanged = (oldGlobal != global); + try { + final Object val = ctxt.getAttribute(ScriptEngine.FILENAME); + final String fileName = (val != null) ? val.toString() : ""; + + // !!HACK!! do not evaluate "init.js" from jrunscript tool!! + if ("".equals(fileName)) { + return null; + } + + final Source source = new Source(fileName, buf); + if (globalChanged) { + setNashornGlobal(global); + } + + setContextVariables(ctxt); + return nashornContext.compileScript(source, global, nashornContext._strict); + } catch (final Exception e) { + throwAsScriptException(e); + throw new AssertionError("should not reach here"); + } finally { + if (globalChanged) { + setNashornGlobal(oldGlobal); + } + } + } + + // don't make this public!! + static void setNashornGlobal(final ScriptObject global) { + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Void run() { + Context.setGlobal(global); + return null; + } + }); + } +} diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java new file mode 100644 index 00000000000..2bb6a3484d7 --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.api.scripting; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import jdk.nashorn.internal.runtime.Version; + +/** + * JSR-223 compliant script engine factory for Nashorn. The engine answers for: + *
      + *
    • names {@code "nashorn"}, {@code "Nashorn"}, {@code "js"}, {@code "JS"}, {@code "JavaScript"}, + * {@code "javascript"}, {@code "ECMAScript"}, and {@code "ecmascript"};
    • + *
    • MIME types {@code "application/javascript"}, {@code "application/ecmascript"}, {@code "text/javascript"}, and + * {@code "text/ecmascript"};
    • + *
    • as well as for the extension {@code "js"}.
    • + *
    + * Programs executing in engines created using {@link #getScriptEngine(String[])} will have the passed arguments + * accessible as a global variable named {@code "arguments"}. + */ +public final class NashornScriptEngineFactory implements ScriptEngineFactory { + @Override + public String getEngineName() { + return (String) getParameter(ScriptEngine.ENGINE); + } + + @Override + public String getEngineVersion() { + return (String) getParameter(ScriptEngine.ENGINE_VERSION); + } + + @Override + public List getExtensions() { + return Collections.unmodifiableList(extensions); + } + + @Override + public String getLanguageName() { + return (String) getParameter(ScriptEngine.LANGUAGE); + } + + @Override + public String getLanguageVersion() { + return (String) getParameter(ScriptEngine.LANGUAGE_VERSION); + } + + @Override + public String getMethodCallSyntax(final String obj, final String method, final String... args) { + final StringBuilder sb = new StringBuilder().append(obj).append('.').append(method).append('('); + final int len = args.length; + + if (len > 0) { + sb.append(args[0]); + } + for (int i = 1; i < len; i++) { + sb.append(',').append(args[i]); + } + sb.append(')'); + + return sb.toString(); + } + + @Override + public List getMimeTypes() { + return Collections.unmodifiableList(mimeTypes); + } + + @Override + public List getNames() { + return Collections.unmodifiableList(names); + } + + @Override + public String getOutputStatement(final String toDisplay) { + return "print(" + toDisplay + ")"; + } + + @Override + public Object getParameter(final String key) { + switch (key) { + case ScriptEngine.NAME: + return "javascript"; + case ScriptEngine.ENGINE: + return "Oracle Nashorn"; + case ScriptEngine.ENGINE_VERSION: + return Version.version(); + case ScriptEngine.LANGUAGE: + return "ECMAScript"; + case ScriptEngine.LANGUAGE_VERSION: + return "ECMA - 262 Edition 5.1"; + case "THREADING": + // The engine implementation is not thread-safe. Can't be + // used to execute scripts concurrently on multiple threads. + return null; + default: + throw new IllegalArgumentException("Invalid key"); + } + } + + @Override + public String getProgram(final String... statements) { + final StringBuilder sb = new StringBuilder(); + + for (final String statement : statements) { + sb.append(statement).append(';'); + } + + return sb.toString(); + } + + @Override + public ScriptEngine getScriptEngine() { + return new NashornScriptEngine(this); + } + + /** + * Create a new Script engine initialized by given arguments. + * + * @param args arguments array passed to script engine. + * @return newly created script engine. + */ + public ScriptEngine getScriptEngine(final String[] args) { + return new NashornScriptEngine(this, args); + } + + // -- Internals only below this point + + private static final List names; + private static final List mimeTypes; + private static final List extensions; + + static { + names = immutableList( + "nashorn", "Nashorn", + "js", "JS", + "JavaScript", "javascript", + "ECMAScript", "ecmascript" + ); + + mimeTypes = immutableList( + "application/javascript", + "application/ecmascript", + "text/javascript", + "text/ecmascript" + ); + + extensions = immutableList("js"); + } + + private static List immutableList(final String... elements) { + return Collections.unmodifiableList(Arrays.asList(elements)); + } +} diff --git a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java new file mode 100644 index 00000000000..44021fada90 --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.api.scripting; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; +import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.ScriptFunction; +import jdk.nashorn.internal.runtime.ScriptObject; +import netscape.javascript.JSObject; + +/** + * Mirror object that wraps a given ScriptObject instance. User can + * access ScriptObject via the java.util.Map interface. + */ +final class ScriptObjectMirror extends JSObject implements Map { + private final ScriptObject sobj; + private final ScriptObject global; + + ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) { + this.sobj = sobj; + this.global = global; + } + + @Override + public boolean equals(final Object other) { + if (other instanceof ScriptObjectMirror) { + return sobj.equals(((ScriptObjectMirror)other).sobj); + } + + return false; + } + + @Override + public int hashCode() { + return sobj.hashCode(); + } + + private V inGlobal(final Callable callable) { + final ScriptObject oldGlobal = Context.getGlobal(); + final boolean globalChanged = (oldGlobal != global); + if (globalChanged) { + NashornScriptEngine.setNashornGlobal(global); + } + try { + return callable.call(); + } catch (final RuntimeException e) { + throw e; + } catch (final Exception e) { + throw new AssertionError("Cannot happen", e); + } finally { + if (globalChanged) { + NashornScriptEngine.setNashornGlobal(oldGlobal); + } + } + } + + // JSObject methods + @Override + public Object call(final String methodName, final Object args[]) { + final Object val = sobj.get(methodName); + final ScriptObject oldGlobal = Context.getGlobal(); + final boolean globalChanged = (oldGlobal != global); + + if (val instanceof ScriptFunction) { + final Object[] modifiedArgs = unwrapArray(args, global); + if (modifiedArgs != null) { + for (int i = 0; i < modifiedArgs.length; i++) { + final Object arg = modifiedArgs[i]; + if (arg instanceof ScriptObject) { + modifiedArgs[i] = wrap(arg, oldGlobal); + } + } + } + + try { + if (globalChanged) { + NashornScriptEngine.setNashornGlobal(global); + } + return wrap(((ScriptFunction)val).invoke(sobj, modifiedArgs), global); + } catch (final RuntimeException | Error e) { + throw e; + } catch (final Throwable t) { + throw new RuntimeException(t); + } finally { + if (globalChanged) { + NashornScriptEngine.setNashornGlobal(oldGlobal); + } + } + } + + throw new RuntimeException("No such method: " + methodName); + } + + @Override + public Object eval(final String s) { + return inGlobal(new Callable() { + @Override + public Object call() { + return wrap(global.getContext().eval(global, s, null, null, false), global); + } + }); + } + + @Override + public Object getMember(final String name) { + return get(name); + } + + @Override + public Object getSlot(final int index) { + return get(Integer.valueOf(index)); + } + + @Override + public void removeMember(final String name) { + remove(name); + } + + @Override + public void setMember(final String name, final Object value) { + put(name, wrap(value, Context.getGlobal())); + } + + @Override + public void setSlot(final int index, final Object value) { + put(Integer.valueOf(index), wrap(value, Context.getGlobal())); + } + + @Override + public void clear() { + inGlobal(new Callable() { + @Override public Object call() { + sobj.clear(); + return null; + }}); + } + + @Override + public boolean containsKey(final Object key) { + return inGlobal(new Callable() { + @Override public Boolean call() { + return sobj.containsKey(unwrap(key, global)); + }}); + } + + @Override + public boolean containsValue(final Object value) { + return inGlobal(new Callable() { + @Override public Boolean call() { + return sobj.containsValue(unwrap(value, global)); + }}); + } + + @Override + public Set> entrySet() { + return inGlobal(new Callable>>() { + @Override public Set> call() { + final Iterator iter = sobj.propertyIterator(); + final Set> entries = new HashSet<>(); + + while (iter.hasNext()) { + final Object key = wrap(iter.next(), global); + final Object value = wrap(sobj.get(key), global); + entries.add(new AbstractMap.SimpleImmutableEntry<>(key, value)); + } + + return Collections.unmodifiableSet(entries); + } + }); + } + + @Override + public Object get(final Object key) { + return inGlobal(new Callable() { @Override public Object call() { + return wrap(sobj.get(key), global); + }}); + } + + @Override + public boolean isEmpty() { + return inGlobal(new Callable() { @Override public Boolean call() { + return sobj.isEmpty(); + }}); + } + + @Override + public Set keySet() { + return inGlobal(new Callable>() { @Override public Set call() { + final Iterator iter = sobj.propertyIterator(); + final Set keySet = new HashSet<>(); + + while (iter.hasNext()) { + keySet.add(wrap(iter.next(), global)); + } + + return Collections.unmodifiableSet(keySet); + }}); + } + + @Override + public Object put(final Object key, final Object value) { + return inGlobal(new Callable() { + @Override public Object call() { + return sobj.put(unwrap(key, global), unwrap(value, global)); + }}); + } + + @Override + public void putAll(final Map map) { + final boolean strict = sobj.getContext()._strict; + inGlobal(new Callable() { @Override public Object call() { + for (final Map.Entry entry : map.entrySet()) { + sobj.set(unwrap(entry.getKey(), global), unwrap(entry.getValue(), global), strict); + } + return null; + }}); + } + + @Override + public Object remove(final Object key) { + return inGlobal(new Callable() { + @Override public Object call() { + return wrap(sobj.remove(unwrap(key, global)), global); + } + }); + } + + @Override + public int size() { + return inGlobal(new Callable() { + @Override public Integer call() { + return sobj.size(); + } + }); + } + + @Override + public Collection values() { + return inGlobal(new Callable>() { @Override public Collection call() { + final List values = new ArrayList<>(size()); + final Iterator iter = sobj.valueIterator(); + + while (iter.hasNext()) { + values.add(wrap(iter.next(), global)); + } + + return Collections.unmodifiableList(values); + }}); + } + + static Object wrap(final Object obj, final ScriptObject homeGlobal) { + return (obj instanceof ScriptObject) ? new ScriptObjectMirror((ScriptObject)obj, homeGlobal) : obj; + } + + static Object unwrap(final Object obj, final ScriptObject homeGlobal) { + if (obj instanceof ScriptObjectMirror) { + final ScriptObjectMirror mirror = (ScriptObjectMirror)obj; + return (mirror.global == homeGlobal)? mirror.sobj : obj; + } + + return obj; + } + + static Object[] wrapArray(final Object[] args, final ScriptObject homeGlobal) { + if (args == null || args.length == 0) { + return args; + } + + final Object[] newArgs = new Object[args.length]; + int index = 0; + for (final Object obj : args) { + newArgs[index] = wrap(obj, homeGlobal); + index++; + } + return newArgs; + } + + static Object[] unwrapArray(final Object[] args, final ScriptObject homeGlobal) { + if (args == null || args.length == 0) { + return args; + } + + final Object[] newArgs = new Object[args.length]; + int index = 0; + for (final Object obj : args) { + newArgs[index] = unwrap(obj, homeGlobal); + index++; + } + return newArgs; + } +} diff --git a/nashorn/src/jdk/nashorn/api/scripting/package-info.java b/nashorn/src/jdk/nashorn/api/scripting/package-info.java new file mode 100644 index 00000000000..32472901236 --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/package-info.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2010, 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. + */ + +/** + * This package provides the {@code javax.script} integration, which is the preferred way to use Nashorn. + * You will ordinarily do this to obtain an instance of a Nashorn script engine: + *
    + * import javax.script.*;
    + * ...
    + * ScriptEngine nashornEngine = new ScriptEngineManager().getEngineByName("Nashorn");
    + * 
    + *

    Nashorn script engines implement the optional {@link javax.script.Invocable} and {@link javax.script.Compilable} + * interfaces, allowing for efficient pre-compilation and repeated execution of scripts. See + * {@link jdk.nashorn.api.scripting.NashornScriptEngineFactory} for further details. + */ +package jdk.nashorn.api.scripting; diff --git a/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js b/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js new file mode 100644 index 00000000000..49e8d45b853 --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2010, 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. + */ + +/** + * This script file is executed by script engine at the construction + * of the engine. The functions here assume global variables "context" + * of type javax.script.ScriptContext and "engine" of the type + * jdk.nashorn.api.scripting.NashornScriptEngine. + * + **/ + +Object.defineProperty(this, "__noSuchProperty__", { + configurable: true, + enumerable: false, + writable: true, + value: function (name) { + 'use strict'; + return engine.__noSuchProperty__(this, context, name); + } +}); + +Object.defineProperty(this, "__noSuchMethod__", { + configurable: true, + enumerable: false, + writable: true, + value: function (name, args) { + 'use strict'; + return engine.__noSuchMethod__(this, context, name, args); + } +}); + +function print(str) { + var writer = context.getWriter(); + if (! (writer instanceof java.io.PrintWriter)) { + writer = new java.io.PrintWriter(writer); + } + writer.println(String(str)); +} diff --git a/nashorn/src/jdk/nashorn/internal/codegen/AccessSpecializer.java b/nashorn/src/jdk/nashorn/internal/codegen/AccessSpecializer.java new file mode 100644 index 00000000000..56a3e7ecc45 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/codegen/AccessSpecializer.java @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.codegen; + +import java.util.HashSet; +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.AccessNode; +import jdk.nashorn.internal.ir.Assignment; +import jdk.nashorn.internal.ir.BinaryNode; +import jdk.nashorn.internal.ir.CallNode; +import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.IdentNode; +import jdk.nashorn.internal.ir.IndexNode; +import jdk.nashorn.internal.ir.Node; +import jdk.nashorn.internal.ir.ReferenceNode; +import jdk.nashorn.internal.ir.Symbol; +import jdk.nashorn.internal.ir.TypeOverride; +import jdk.nashorn.internal.ir.UnaryNode; +import jdk.nashorn.internal.ir.VarNode; +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; +import jdk.nashorn.internal.ir.visitor.NodeVisitor; +import jdk.nashorn.internal.parser.Token; +import jdk.nashorn.internal.parser.TokenType; +import jdk.nashorn.internal.runtime.Debug; +import jdk.nashorn.internal.runtime.DebugLogger; + +/** + * This is a post pass for Lower, that removes casts for accessors to objects in + * Scope, and replaces the accessor type with a narrower one with possible. + * + * Any node that implements TypeOverride will be subject to access specialization. + * + * TypeOverride basically means "type inference has determined that the field x + * is an object, but if you do x & 17, it can be read as an int, which we hope + * coincides with its internal representation. In that case there is no boxing + * that may or may not be removed by the JVM and less data bandwidth. + * + * Ideally this should not be a post pass, but it requires slot AND scope info, and has + * to be run where it is, which is called from {@link CodeGenerator}. + * + * @see TypeOverride + */ + +final class AccessSpecializer extends NodeOperatorVisitor implements Transform { + /** Debug logger for access specialization. Enable it with --log=access:level + or -Dnashorn.specializations.debug */ + private static final DebugLogger LOG = new DebugLogger("access", "nashorn.callsiteaccess.debug"); + private static final boolean DEBUG = LOG.isEnabled(); + + @Override + public Node enter(final FunctionNode node) { + if (node.isTransformApplied(AccessSpecializer.class)) { + return null; + } + + return node; + } + + @Override + public Node leave(final FunctionNode node) { + node.registerTransform(AccessSpecializer.class); + return node; + } + + @Override + public Node leave(final VarNode varNode) { + if (varNode.isAssignment()) { + return leaveAssign(varNode); + } + + return varNode; + } + + @Override + public Node leave(final CallNode callNode) { + final Node function = callNode.getFunction(); + if (function instanceof ReferenceNode) { + changeType(callNode, ((ReferenceNode)function).getReference().getType()); + } + return callNode; + } + + @Override + public Node leaveASSIGN(final BinaryNode binaryNode) { + return leaveAssign(binaryNode); + } + + @Override + public Node leaveASSIGN_ADD(final BinaryNode binaryNode) { + return leaveAssign(binaryNode); + } + + @Override + public Node leaveASSIGN_BIT_AND(final BinaryNode binaryNode) { + return leaveAssign(binaryNode); + } + + @Override + public Node leaveASSIGN_BIT_OR(final BinaryNode binaryNode) { + return leaveAssign(binaryNode); + } + + @Override + public Node leaveASSIGN_BIT_XOR(final BinaryNode binaryNode) { + return leaveAssign(binaryNode); + } + + @Override + public Node leaveASSIGN_DIV(final BinaryNode binaryNode) { + return leaveAssign(binaryNode); + } + + @Override + public Node leaveASSIGN_MOD(final BinaryNode binaryNode) { + return leaveAssign(binaryNode); + } + + @Override + public Node leaveASSIGN_MUL(final BinaryNode binaryNode) { + return leaveAssign(binaryNode); + } + + @Override + public Node leaveASSIGN_SAR(final BinaryNode binaryNode) { + return leaveAssign(binaryNode); + } + + @Override + public Node leaveASSIGN_SHL(final BinaryNode binaryNode) { + return leaveAssign(binaryNode); + } + + @Override + public Node leaveASSIGN_SHR(final BinaryNode binaryNode) { + return leaveAssign(binaryNode); + } + + @Override + public Node leaveASSIGN_SUB(final BinaryNode binaryNode) { + return leaveAssign(binaryNode); + } + + @Override + public Node leaveCOMMALEFT(final BinaryNode binaryNode) { + return propagateResultType(binaryNode, binaryNode.lhs().getType()); + } + + @Override + public Node leaveCOMMARIGHT(final BinaryNode binaryNode) { + return propagateResultType(binaryNode, binaryNode.rhs().getType()); + } + + @Override + public Node leaveCONVERT(final UnaryNode unaryNode) { + final Type castTo = unaryNode.getType(); + + Node rhs = unaryNode.rhs(); + + // Go through all conversions until we find the first non-convert node. + while (rhs.tokenType() == TokenType.CONVERT) { + rhs = ((UnaryNode)rhs).rhs(); + } + + // If this node can be type changed + if (canHaveCallSiteType(rhs) && isSupportedCallSiteType(castTo)) { + /* + * Just add a callsite type and throw away the cast, appropriate + * getter/setter is selected, which will do the conversion for us + */ + changeType(rhs, castTo); + fine("*** cast: converting " + debugNode(unaryNode) + " to " + debugNode(rhs)); + + return rhs; + } + + // Micro optimization for node hygiene and pattern detection - remove unnecessary same type cast + if (unaryNode.getType().isEquivalentTo(rhs.getType())) { + return rhs; + } + + return unaryNode; + } + + @Override + public Node leaveDECINC(final UnaryNode unaryNode) { + assert unaryNode.isAssignment(); + + final Node dest = unaryNode.getAssignmentDest(); + if (canHaveCallSiteType(dest) && isSupportedCallSiteType(unaryNode.getType())) { + changeTypeInAssignment(dest, unaryNode.getType()); + } + + return unaryNode; + } + + /** + * Is this a node that can have its type overridden. This is true for + * AccessNodes, IndexNodes and IdentNodes + * + * @param node the node to check + * @return true if node can have a callsite type + */ + private static boolean canHaveCallSiteType(final Node node) { + return node instanceof TypeOverride && ((TypeOverride)node).canHaveCallSiteType(); + } + + /** + * Is the specialization type supported. Currently we treat booleans as objects + * and have no special boolean type accessor, thus booleans are ignored. + * TODO - support booleans? NASHORN-590 + * + * @param castTo the type to check + * @return true if call site type is supported + */ + private static boolean isSupportedCallSiteType(final Type castTo) { + return castTo.isNumeric(); // don't specializable for boolean + } + + /** + * Turn a node into a covert node + * + * @param node the node + * @return the node as a convert node + */ + private static Node convert(final Node node) { + return new UnaryNode(node.getSource(), + Token.recast(node.getToken(), TokenType.CONVERT), + node); + } + + private static Node leaveAssign(final Node node) { + assert node.isAssignment() : node + " is not an assignment"; + + + final Node lhs = ((Assignment)node).getAssignmentDest(); + Node rhs = ((Assignment)node).getAssignmentSource(); + + /** + * Nodes with local variable slots are assumed to be of their optimal type + * already and aren't affected here. This is not strictly true, for instance + * with doubles instead of in a bounded loop. TODO - range check: NASHORN-363 + * + * This is also not strictly true for var y = x = 55; where y has no other uses + * Then y can be an int, but lower conservatively does an object of the assign to + * scope + */ + final Symbol lhsSymbol = lhs.getSymbol(); + + if (lhsSymbol.hasSlot() && !lhsSymbol.isScope()) { + finest(lhs.getSymbol() + " has slot!"); + if (!lhs.getType().isEquivalentTo(rhs.getType())) { + finest("\tslot assignment: " +lhs.getType()+ " " +rhs.getType() + " " + debugNode(node)); + + final Node c = convert(rhs); + c.setSymbol(lhsSymbol); + ((Assignment)node).setAssignmentSource(c); + + fine("*** slot assignment turned to : " + debugNode(node)); + } else { + finest("aborted - type equivalence between lhs and rhs"); + } + + return node; + } + + // e.g. __DIR__, __LINE__, __FILE__ - don't try to change these + if (lhs instanceof IdentNode && ((IdentNode)lhs).isSpecialIdentity()) { + return node; + } + + /** + * Try to cast to the type of the right hand side, now pruned. E.g. an (object)17 should + * now be just 17, an int. + */ + Type castTo = rhs.getType(); + + // If LHS can't get a new type, neither can rhs - retain the convert + if (!canHaveCallSiteType(lhs)) { + return node; + } + + // Take the narrowest type of the entire cast sequence + while (rhs.tokenType() == TokenType.CONVERT) { + rhs = ((UnaryNode)rhs).rhs(); + castTo = Type.narrowest(rhs.getType(), castTo); //e.g. (object)(int) -> int even though object is outermost + } + + // If castTo is wider than widestOperationType, castTo can be further slowed down + final Type widestOperationType = node.getWidestOperationType(); + finest("node wants to be " + castTo + " and its widest operation is " + widestOperationType); + + if (widestOperationType != castTo && Type.widest(castTo, widestOperationType) == castTo) { + info("###" + node + " castTo was " + castTo + " but could be downgraded to " + node.getWidestOperationType()); + castTo = node.getWidestOperationType(); + if (rhs instanceof TypeOverride) { + changeType(rhs, castTo); + } + } + + /* + * If this is a self modifying op, we can't be narrower than the widest optype + * or e.g. x = x + 12 and x += 12 will turn into different things + */ + if (node.isSelfModifying()) { + castTo = Type.widest(widestOperationType, castTo); + } + + // We only specialize for numerics, not for booleans. + if (isSupportedCallSiteType(castTo)) { + if (rhs.getType() != castTo) { + finest("cast was necessary, abort: " + node + " " + rhs.getType() + " != " + castTo); + return node; + } + + finest("assign: " + debugNode(node)); + + changeTypeInAssignment(lhs, castTo); + ((Assignment)node).setAssignmentSource(rhs); + + info("### modified to " + debugNode(node) + " (given type override " + castTo + ")"); + + propagateResultType(node, castTo); + } + + return node; + } + + private static Node propagateResultType(final Node node, final Type type) { + //warning! this CANNOT be done for non temporaries as they are used in other computations + if (isSupportedCallSiteType(type)) { + if (node.getSymbol().isTemp()) { + finest("changing temporary type: " + debugNode(node) + " to " + type); + node.getSymbol().setTypeOverride(type); + info("### node modified to " + debugNode(node) + " (given type override " + type + ")"); + } + } + return node; + } + + private static void changeTypeInAssignment(final Node dest, final Type newType) { + if (changeType(dest, newType)) { + finest("changed assignment " + dest + " " + dest.getSymbol()); + assert !newType.isObject(); + + final HashSet exclude = new HashSet<>(); + + dest.accept(new NodeVisitor() { + + private void setCanBePrimitive(final Symbol symbol) { + fine("*** can be primitive symbol " + symbol + " " + Debug.id(symbol)); + symbol.setCanBePrimitive(newType); + } + + @Override + public Node enter(final IdentNode identNode) { + if (!exclude.contains(identNode)) { + setCanBePrimitive(identNode.getSymbol()); + } + return null; + } + + @Override + public Node enter(final AccessNode accessNode) { + setCanBePrimitive(accessNode.getProperty().getSymbol()); + return null; + } + + @Override + public Node enter(final IndexNode indexNode) { + exclude.add(indexNode.getBase()); //prevent array base node to be flagged as primitive, but k in a[k++] is fine + return indexNode; + } + + }); + } + } + + private static boolean changeType(final Node node, final Type newType) { + if (!node.getType().equals(newType)) { + ((TypeOverride)node).setType(newType); + return true; + } + return false; + } + + private static String debugNode(final Node node) { + if (DEBUG) { + return node.toString(); + } + return ""; + } + + private static void info(final String str) { + LOG.info(str); + } + + private static void fine(final String str) { + LOG.fine(str); + } + + private static void finest(final String str) { + LOG.finest(str); + } + +} diff --git a/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java b/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java new file mode 100644 index 00000000000..e15633f801e --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.codegen; + +import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.EQ; +import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.GE; +import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.GT; +import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.LE; +import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.LT; +import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.NE; + +import jdk.nashorn.internal.codegen.MethodEmitter.Label; +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.BinaryNode; +import jdk.nashorn.internal.ir.Node; +import jdk.nashorn.internal.ir.TernaryNode; +import jdk.nashorn.internal.ir.UnaryNode; + +/** + * Branch optimizer for CodeGenerator. Given a jump condition this helper + * class attempts to simplify the control flow + */ +final class BranchOptimizer { + + private final CodeGenerator codegen; + private final MethodEmitter method; + + BranchOptimizer(final CodeGenerator codegen, final MethodEmitter method) { + this.codegen = codegen; + this.method = method; + } + + void execute(final Node node, final Label label, final boolean state) { + branchOptimizer(node, label, state); + } + + private void load(final Node node) { + codegen.load(node); + } + + private void branchOptimizer(final UnaryNode unaryNode, final Label label, final boolean state) { + final Node rhs = unaryNode.rhs(); + + switch (unaryNode.tokenType()) { + case NOT: + branchOptimizer(rhs, label, !state); + return; + case CONVERT: + if (unaryNode.getType().isBoolean()) { + branchOptimizer(rhs, label, state); + return; + } + break; + default: + break; + } + + // convert to boolean + load(unaryNode); + method.convert(Type.BOOLEAN); + if (state) { + method.ifne(label); + } else { + method.ifeq(label); + } + } + + private void branchOptimizer(final BinaryNode binaryNode, final Label label, final boolean state) { + final Node lhs = binaryNode.lhs(); + final Node rhs = binaryNode.rhs(); + + switch (binaryNode.tokenType()) { + case AND: + if (state) { + final Label skip = new Label("skip"); + branchOptimizer(lhs, skip, false); + branchOptimizer(rhs, label, true); + method.label(skip); + } else { + branchOptimizer(lhs, label, false); + branchOptimizer(rhs, label, false); + } + return; + + case OR: + if (state) { + branchOptimizer(lhs, label, true); + branchOptimizer(rhs, label, true); + } else { + final Label skip = new Label("skip"); + branchOptimizer(lhs, skip, true); + branchOptimizer(rhs, label, false); + method.label(skip); + } + return; + + case EQ: + case EQ_STRICT: + assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol(); + load(lhs); + load(rhs); + method.conditionalJump(state ? EQ : NE, true, label); + return; + + case NE: + case NE_STRICT: + assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol(); + load(lhs); + load(rhs); + method.conditionalJump(state ? NE : EQ, true, label); + return; + + case GE: + assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol(); + load(lhs); + load(rhs); + method.conditionalJump(state ? GE : LT, !state, label); + return; + + case GT: + assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol(); + load(lhs); + load(rhs); + method.conditionalJump(state ? GT : LE, !state, label); + return; + + case LE: + assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol(); + load(lhs); + load(rhs); + method.conditionalJump(state ? LE : GT, state, label); + return; + + case LT: + assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol() + " in " + binaryNode; + load(lhs); + load(rhs); + method.conditionalJump(state ? LT : GE, state, label); + return; + + default: + break; + } + + load(binaryNode); + method.convert(Type.BOOLEAN); + if (state) { + method.ifne(label); + } else { + method.ifeq(label); + } + } + + private void branchOptimizer(final Node node, final Label label, final boolean state) { + if (!(node instanceof TernaryNode)) { + + if (node instanceof BinaryNode) { + branchOptimizer((BinaryNode)node, label, state); + return; + } + + if (node instanceof UnaryNode) { + branchOptimizer((UnaryNode)node, label, state); + return; + } + } + + load(node); + method.convert(Type.BOOLEAN); + if (state) { + method.ifne(label); + } else { + method.ifeq(label); + } + } +} diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java b/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java new file mode 100644 index 00000000000..9b95cf836f9 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java @@ -0,0 +1,620 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.codegen; + +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKEINTERFACE; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESPECIAL; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKEVIRTUAL; +import static jdk.internal.org.objectweb.asm.Opcodes.H_NEWINVOKESPECIAL; +import static jdk.internal.org.objectweb.asm.Opcodes.V1_7; +import static jdk.nashorn.internal.codegen.CompilerConstants.CLINIT; +import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS; +import static jdk.nashorn.internal.codegen.CompilerConstants.GET_ARRAY_PREFIX; +import static jdk.nashorn.internal.codegen.CompilerConstants.GET_ARRAY_SUFFIX; +import static jdk.nashorn.internal.codegen.CompilerConstants.GET_MAP; +import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING; +import static jdk.nashorn.internal.codegen.CompilerConstants.INIT; +import static jdk.nashorn.internal.codegen.CompilerConstants.SET_MAP; +import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE; +import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE; +import static jdk.nashorn.internal.codegen.CompilerConstants.className; +import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; +import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; +import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor; + +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Set; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.util.TraceClassVisitor; +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.PropertyMap; +import jdk.nashorn.internal.runtime.ScriptObject; +import jdk.nashorn.internal.runtime.Source; + +/** + * The interface responsible for speaking to ASM, emitting classes, + * fields and methods. + *

    + * This file contains the ClassEmitter, which is the master object + * responsible for writing byte codes. It utilizes a MethodEmitter + * for method generation, which also the NodeVisitors own, to keep + * track of the current code generator and what it is doing. + *

    + * There is, however, nothing stopping you from using this in a + * completely self contained environment, for example in ObjectGenerator + * where there are no visitors or external hooks. + *

    + * MethodEmitter makes it simple to generate code for methods without + * having to do arduous type checking. It maintains a type stack + * and will pick the appropriate operation for all operations sent to it + * We also allow chained called to a MethodEmitter for brevity, e.g. + * it is legal to write _new(className).dup() or + * load(slot).load(slot2).xor().store(slot3); + *

    + * If running with assertions enabled, any type conflict, such as different + * bytecode stack sizes or operating on the wrong type will be detected + * and an error thrown. + *

    + * There is also a very nice debug interface that can emit formatted + * bytecodes that have been written. This is enabled by setting the + * environment "nashorn.codegen.debug" to true, or --log=codegen: + *

    + * A ClassEmitter implements an Emitter - i.e. it needs to have + * well defined start and end calls for whatever it is generating. Assertions + * detect if this is not true + * + * @see Compiler + * @see CodeGenerator + */ +public class ClassEmitter implements Emitter { + + /** Sanity check flag - have we started on a class? */ + private boolean classStarted; + + /** Sanity check flag - have we ended this emission? */ + private boolean classEnded; + + /** + * Sanity checks - which methods have we currently + * started for generation in this class? + */ + private final HashSet methodsStarted; + + /** The ASM classwriter that we use for all bytecode operations */ + protected final ClassWriter cw; + + /** The context */ + protected final Context context; + + /** Default flags for class generation - oublic class */ + private static final EnumSet DEFAULT_METHOD_FLAGS = EnumSet.of(Flag.PUBLIC); + + /** Compile unit class name. */ + private String unitClassName; + + /** Set of constants access methods required. */ + private Set> constantMethodNeeded; + + /** + * Constructor - only used internally in this class as it breaks + * abstraction towards ASM or other code generator below + * + * @param context context + * @param cw ASM classwriter + */ + private ClassEmitter(final Context context, final ClassWriter cw) { + assert context != null; + + this.context = context; + this.cw = cw; + this.methodsStarted = new HashSet<>(); + } + + /** + * Constructor + * + * @param context context + * @param className name of class to weave + * @param superClassName super class name for class + * @param interfaceNames names of interfaces implemented by this class, or null if none + */ + public ClassEmitter(final Context context, final String className, final String superClassName, final String... interfaceNames) { + this(context, new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS)); + cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, className, null, superClassName, interfaceNames); + } + + /** + * Constructor from the compiler + * + * @param compiler Compiler + * @param unitClassName Compile unit class name. + * @param strictMode Should we generate this method in strict mode + */ + ClassEmitter(final Compiler compiler, final String unitClassName, final boolean strictMode) { + this(compiler.getContext(), + new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) { + private static final String OBJECT_CLASS = "java/lang/Object"; + + @Override + protected String getCommonSuperClass(final String type1, final String type2) { + try { + return super.getCommonSuperClass(type1, type2); + } catch (final RuntimeException e) { + if (isScriptObject(Compiler.SCRIPTS_PACKAGE, type1) && isScriptObject(Compiler.SCRIPTS_PACKAGE, type2)) { + return className(ScriptObject.class); + } + return OBJECT_CLASS; + } + } + }); + + this.unitClassName = unitClassName; + this.constantMethodNeeded = new HashSet<>(); + + cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, unitClassName, null, Compiler.pathName(jdk.nashorn.internal.scripts.JS$.class.getName()), null); + cw.visitSource(compiler.getSource().getName(), null); + + defineCommonStatics(strictMode); + } + + /** + * Define the static fields common in all scripts. + * @param strictMode Should we generate this method in strict mode + */ + private void defineCommonStatics(final boolean strictMode) { + // source - used to store the source data (text) for this script. Shared across + // compile units. Set externally by the compiler. + field(EnumSet.of(Flag.PUBLIC, Flag.STATIC), SOURCE.tag(), Source.class); + + // constants - used to the constants array for this script. Shared across + // compile units. Set externally by the compiler. + field(EnumSet.of(Flag.PUBLIC, Flag.STATIC), CONSTANTS.tag(), Object[].class); + + // strictMode - was this script compiled in strict mode. Set externally by the compiler. + field(EnumSet.of(Flag.PUBLIC, Flag.STATIC, Flag.FINAL), STRICT_MODE.tag(), boolean.class, strictMode); + } + + /** + * Define static utilities common needed in scripts. These are per compile unit + * and therefore have to be defined here and not in code gen. + */ + private void defineCommonUtilities() { + assert unitClassName != null; + + if (constantMethodNeeded.contains(String.class)) { + // $getString - get the ith entry from the constants table and cast to String. + final MethodEmitter getStringMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), GET_STRING.tag(), String.class, int.class); + getStringMethod.begin(); + getStringMethod.getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor()) + .load(Type.INT, 0) + .arrayload() + .checkcast(String.class) + ._return(); + getStringMethod.end(); + } + + if (constantMethodNeeded.contains(PropertyMap.class)) { + // $getMap - get the ith entry from the constants table and cast to PropertyMap. + final MethodEmitter getMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), GET_MAP.tag(), PropertyMap.class, int.class); + getMapMethod.begin(); + getMapMethod.loadConstants(unitClassName) + .load(Type.INT, 0) + .arrayload() + .checkcast(PropertyMap.class) + ._return(); + getMapMethod.end(); + + // $setMap - overwrite an existing map. + final MethodEmitter setMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), SET_MAP.tag(), void.class, int.class, PropertyMap.class); + setMapMethod.begin(); + setMapMethod.loadConstants(unitClassName) + .load(Type.INT, 0) + .load(Type.OBJECT, 1) + .arraystore(); + setMapMethod.returnVoid(); + setMapMethod.end(); + } + + // $getXXXX$array - get the ith entry from the constants table and cast to XXXX[]. + for (final Class cls : constantMethodNeeded) { + if (cls.isArray()) { + defineGetArrayMethod(cls); + } + } + } + + /** + * Constructs a primitive specific method for getting the ith entry from the constants table and cast. + * @param cls Array class. + */ + private void defineGetArrayMethod(final Class cls) { + assert unitClassName != null; + + final String methodName = getArrayMethodName(cls); + final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, cls, int.class); + + getArrayMethod.begin(); + getArrayMethod.getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor()) + .load(Type.INT, 0) + .arrayload() + .checkcast(cls) + .dup() + .arraylength() + .invoke(staticCallNoLookup(Arrays.class, "copyOf", cls, cls, int.class)) + ._return(); + getArrayMethod.end(); + } + + /** + * Generate the name of a get array from constant pool method. + * @param cls Name of array class. + * @return Method name. + */ + static String getArrayMethodName(final Class cls) { + assert cls.isArray(); + return GET_ARRAY_PREFIX.tag() + cls.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.tag(); + } + + /** + * Ensure a get constant method is issued for the class. + * @param cls Class of constant. + */ + public void needGetConstantMethod(final Class cls) { + constantMethodNeeded.add(cls); + } + + /** + * Inspect class name and decide whether we are generating a ScriptObject class + * + * @param scriptPrefix the script class prefix for the current script + * @param type the type to check + * + * @return true if type is ScriptObject + */ + private static boolean isScriptObject(final String scriptPrefix, final String type) { + if (type.startsWith(scriptPrefix)) { + return true; + } else if (type.equals(CompilerConstants.className(ScriptObject.class))) { + return true; + } else if (type.startsWith(Compiler.OBJECTS_PACKAGE)) { + return true; + } + + return false; + } + + /** + * Call at beginning of class emission + * @see Emitter + */ + @Override + public void begin() { + classStarted = true; + } + + /** + * Call at end of class emission + * @see Emitter + */ + @Override + public void end() { + assert classStarted; + + if (unitClassName != null) { + defineCommonUtilities(); + } + + cw.visitEnd(); + classStarted = false; + classEnded = true; + assert methodsStarted.isEmpty() : "methodsStarted not empty " + methodsStarted; + } + + /** + * Disassemble an array of byte code. + * + * @param context the context + * @param bytecode byte array representing bytecode + */ + public static void disassemble(final Context context, final byte[] bytecode) { + new ClassReader(bytecode).accept(new TraceClassVisitor(context.getErr()), 0); + } + + /** + * Verify an array of byte code as a valid Java class + * + * @param context the context + * @param bytecode the bytecode array + */ + public static void verify(final Context context, final byte[] bytecode) { + context.verify(bytecode); + } + + /** + * @return context used for class emission + */ + Context getContext() { + return context; + } + + /** + * Call back from MethodEmitter for method start + * + * @see MethodEmitter + * + * @param method method emitter. + */ + void beginMethod(final MethodEmitter method) { + assert !methodsStarted.contains(method); + methodsStarted.add(method); + } + + /** + * Call back from MethodEmitter for method end + * + * @see MethodEmitter + * + * @param method + */ + void endMethod(final MethodEmitter method) { + assert methodsStarted.contains(method); + methodsStarted.remove(method); + } + + /** + * Add a new method to the class - defaults to public method + * + * @param methodName name of method + * @param rtype return type of the method + * @param ptypes parameter types the method + * + * @return method emitter to use for weaving this method + */ + public MethodEmitter method(final String methodName, final Class rtype, final Class... ptypes) { + return method(DEFAULT_METHOD_FLAGS, methodName, rtype, ptypes); //TODO why public default ? + } + + /** + * Add a new method to the class - defaults to public method + * + * @param methodFlags access flags for the method + * @param methodName name of method + * @param rtype return type of the method + * @param ptypes parameter types the method + * + * @return method emitter to use for weaving this method + */ + public MethodEmitter method(final EnumSet methodFlags, final String methodName, final Class rtype, final Class... ptypes) { + return new MethodEmitter(this, cw.visitMethod(Flag.getValue(methodFlags), methodName, methodDescriptor(rtype, ptypes), null, null)); + } + + /** + * Add a new method to the class - defaults to public method + * + * @param methodName name of method + * @param descriptor descriptor of method + * + * @return method emitter to use for weaving this method + */ + public MethodEmitter method(final String methodName, final String descriptor) { + return method(DEFAULT_METHOD_FLAGS, methodName, descriptor); + } + + /** + * Add a new method to the class - defaults to public method + * + * @param methodFlags access flags for the method + * @param methodName name of method + * @param descriptor descriptor of method + * + * @return method emitter to use for weaving this method + */ + public MethodEmitter method(final EnumSet methodFlags, final String methodName, final String descriptor) { + return new MethodEmitter(this, cw.visitMethod(Flag.getValue(methodFlags), methodName, descriptor, null, null)); + } + + /** + * Add a new method to the class, representing a function node + * + * @param functionNode the function node to generate a method for + * @return method emitter to use for weaving this method + */ + public MethodEmitter method(final FunctionNode functionNode) { + final MethodVisitor mv = cw.visitMethod( + ACC_PUBLIC | ACC_STATIC | (functionNode.isVarArg() ? ACC_VARARGS : 0), + functionNode.getName(), + FunctionSignature.functionSignature(functionNode), + null, + null); + + return new MethodEmitter(this, mv, functionNode); + } + + /** + * Start generating the method in the class + * + * @return method emitter to use for weaving + */ + public MethodEmitter clinit() { + return method(EnumSet.of(Flag.STATIC), CLINIT.tag(), void.class); + } + + /** + * Start generating an ()V method in the class + * + * @return method emitter to use for weaving ()V + */ + public MethodEmitter init() { + return method(INIT.tag(), void.class); + } + + /** + * Start generating an ()V method in the class + * + * @param ptypes parameter types for constructor + * @return method emitter to use for weaving ()V + */ + public MethodEmitter init(final Class... ptypes) { + return method(INIT.tag(), void.class, ptypes); + } + + /** + * Start generating an (...)V method in the class + * + * @param flags access flags for the constructor + * @param ptypes parameter types for the constructor + * + * @return method emitter to use for weaving (...)V + */ + public MethodEmitter init(final EnumSet flags, final Class... ptypes) { + return method(flags, INIT.tag(), void.class, ptypes); + } + + /** + * Add a field to the class, initialized to a value + * + * @param fieldFlags flags, e.g. should it be static or public etc + * @param fieldName name of field + * @param fieldType the type of the field + * @param value the value + * + * @see ClassEmitter.Flag + */ + public final void field(final EnumSet fieldFlags, final String fieldName, final Class fieldType, final Object value) { + cw.visitField(Flag.getValue(fieldFlags), fieldName, typeDescriptor(fieldType), null, value).visitEnd(); + } + + /** + * Add a field to the class + * + * @param fieldFlags access flags for the field + * @param fieldName name of field + * @param fieldType type of the field + * + * @see ClassEmitter.Flag + */ + public final void field(final EnumSet fieldFlags, final String fieldName, final Class fieldType) { + field(fieldFlags, fieldName, fieldType, null); + } + + /** + * Add a field to the class - defaults to public + * + * @param fieldName name of field + * @param fieldType type of field + */ + public final void field(final String fieldName, final Class fieldType) { + field(EnumSet.of(Flag.PUBLIC), fieldName, fieldType, null); + } + + /** + * Return a bytecode array from this ClassEmitter. The ClassEmitter must + * have been ended (having its end function called) for this to work. + * + * @return byte code array for generated class, null if class generation hasn't been ended with {@link ClassEmitter#end()} + */ + public byte[] toByteArray() { + assert classEnded; + if (!classEnded) { + return null; + } + + return cw.toByteArray(); + } + + /** + * Abstraction for flags used in class emission + * + * We provide abstraction separating these from the underlying bytecode + * emitter. + * + * Flags are provided for method handles, protection levels, static/virtual + * fields/methods. + */ + public static enum Flag { + /** method handle with static access */ + HANDLE_STATIC(H_INVOKESTATIC), + /** method handle with new invoke special access */ + HANDLE_NEWSPECIAL(H_NEWINVOKESPECIAL), + /** method handle with invoke special access */ + HANDLE_SPECIAL(H_INVOKESPECIAL), + /** method handle with invoke virtual access */ + HANDLE_VIRTUAL(H_INVOKEVIRTUAL), + /** method handle with invoke interface access */ + HANDLE_INTERFACE(H_INVOKEINTERFACE), + + /** final access */ + FINAL(ACC_FINAL), + /** static access */ + STATIC(ACC_STATIC), + /** public access */ + PUBLIC(ACC_PUBLIC), + /** private access */ + PRIVATE(ACC_PRIVATE); + + private int value; + + private Flag(final int value) { + this.value = value; + } + + /** + * Get the value of this flag + * @return the int value + */ + public int getValue() { + return value; + } + + /** + * Return the corresponding ASM flag value for an enum set of flags + * + * @param flags enum set of flags + * @return an integer value representing the flags intrinsic values or:ed together + */ + public static int getValue(final EnumSet flags) { + int v = 0; + for (final Flag flag : flags) { + v |= flag.getValue(); + } + return v; + } + } + +} diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java new file mode 100644 index 00000000000..71dc3a7bcb4 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -0,0 +1,3266 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.codegen; + +import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.PRIVATE; +import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.STATIC; +import static jdk.nashorn.internal.codegen.CompilerConstants.GET_MAP; +import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING; +import static jdk.nashorn.internal.codegen.CompilerConstants.LEAF; +import static jdk.nashorn.internal.codegen.CompilerConstants.QUICK_PREFIX; +import static jdk.nashorn.internal.codegen.CompilerConstants.REGEX_PREFIX; +import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; +import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_ARRAY_ARG; +import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX; +import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup; +import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; +import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; +import static jdk.nashorn.internal.codegen.CompilerConstants.staticField; +import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor; +import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL; +import static jdk.nashorn.internal.ir.Symbol.IS_TEMP; +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_FAST_SCOPE; +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_FUNCTION_DECLARATION; +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_SCOPE; +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; +import jdk.nashorn.internal.codegen.ClassEmitter.Flag; +import jdk.nashorn.internal.codegen.CompilerConstants.Call; +import jdk.nashorn.internal.codegen.MethodEmitter.Condition; +import jdk.nashorn.internal.codegen.MethodEmitter.Label; +import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode; +import jdk.nashorn.internal.codegen.objects.FieldObjectCreator; +import jdk.nashorn.internal.codegen.objects.FunctionObjectCreator; +import jdk.nashorn.internal.codegen.objects.MapCreator; +import jdk.nashorn.internal.codegen.objects.ObjectMapCreator; +import jdk.nashorn.internal.codegen.types.ArrayType; +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.AccessNode; +import jdk.nashorn.internal.ir.BaseNode; +import jdk.nashorn.internal.ir.BinaryNode; +import jdk.nashorn.internal.ir.Block; +import jdk.nashorn.internal.ir.BreakNode; +import jdk.nashorn.internal.ir.CallNode; +import jdk.nashorn.internal.ir.CaseNode; +import jdk.nashorn.internal.ir.CatchNode; +import jdk.nashorn.internal.ir.ContinueNode; +import jdk.nashorn.internal.ir.DoWhileNode; +import jdk.nashorn.internal.ir.EmptyNode; +import jdk.nashorn.internal.ir.ExecuteNode; +import jdk.nashorn.internal.ir.ForNode; +import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.IdentNode; +import jdk.nashorn.internal.ir.IfNode; +import jdk.nashorn.internal.ir.IndexNode; +import jdk.nashorn.internal.ir.LineNumberNode; +import jdk.nashorn.internal.ir.LiteralNode; +import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; +import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit; +import jdk.nashorn.internal.ir.Node; +import jdk.nashorn.internal.ir.ObjectNode; +import jdk.nashorn.internal.ir.PropertyNode; +import jdk.nashorn.internal.ir.ReferenceNode; +import jdk.nashorn.internal.ir.ReturnNode; +import jdk.nashorn.internal.ir.RuntimeNode; +import jdk.nashorn.internal.ir.RuntimeNode.Request; +import jdk.nashorn.internal.ir.SplitNode; +import jdk.nashorn.internal.ir.SwitchNode; +import jdk.nashorn.internal.ir.Symbol; +import jdk.nashorn.internal.ir.TernaryNode; +import jdk.nashorn.internal.ir.ThrowNode; +import jdk.nashorn.internal.ir.TryNode; +import jdk.nashorn.internal.ir.UnaryNode; +import jdk.nashorn.internal.ir.VarNode; +import jdk.nashorn.internal.ir.WhileNode; +import jdk.nashorn.internal.ir.WithNode; +import jdk.nashorn.internal.ir.debug.ASTWriter; +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; +import jdk.nashorn.internal.ir.visitor.NodeVisitor; +import jdk.nashorn.internal.parser.Lexer.RegexToken; +import jdk.nashorn.internal.parser.TokenType; +import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.ECMAException; +import jdk.nashorn.internal.runtime.PropertyMap; +import jdk.nashorn.internal.runtime.Scope; +import jdk.nashorn.internal.runtime.ScriptFunction; +import jdk.nashorn.internal.runtime.ScriptObject; +import jdk.nashorn.internal.runtime.ScriptRuntime; +import jdk.nashorn.internal.runtime.Source; +import jdk.nashorn.internal.runtime.Undefined; +import jdk.nashorn.internal.runtime.linker.LinkerCallSite; + +/** + * This is the lowest tier of the code generator. It takes lowered ASTs emitted + * from Lower and emits Java byte code. The byte code emission logic is broken + * out into MethodEmitter. MethodEmitter works internally with a type stack, and + * keeps track of the contents of the byte code stack. This way we avoid a large + * number of special cases on the form + *

    + * {@code
    + * if (type == INT) {
    + *     visitInsn(ILOAD, slot);
    + * } else if (type == DOUBLE) {
    + *     visitInsn(DOUBLE, slot);
    + * }
    + * }
    + * 
    + * This quickly became apparent when the code generator was generalized to work + * with all types, and not just numbers or objects. + *

    + * The CodeGenerator visits nodes only once, tags them as resolved and emits + * bytecode for them. + */ +public final class CodeGenerator extends NodeOperatorVisitor { + + /** Current compiler */ + private final Compiler compiler; + + /** Compiler context */ + private final Context context; + + /** Call site flags given to the code generator to be used for all generated call sites */ + private final int callSiteFlags; + + /** How many regexp fields have been emitted */ + private int regexFieldCount; + + /** Map of shared scope call sites */ + private final Map scopeCalls = new HashMap<>(); + + /** When should we stop caching regexp expressions in fields to limit bytecode size? */ + private static final int MAX_REGEX_FIELDS = 2 * 1024; + + /** + * Constructor. + * + * @param compiler + */ + CodeGenerator(final Compiler compiler) { + this.compiler = compiler; + this.context = compiler.getContext(); + this.callSiteFlags = context._callsite_flags; + } + + /** + * Get the compiler + * + * @return the compiler used + */ + public Compiler getCompiler() { + return compiler; + } + + /** + * Gets the call site flags, adding the strict flag if the current function + * being generated is in strict mode + * + * @return the correct flags for a call site in the current function + */ + public int getCallSiteFlags() { + return getCurrentFunctionNode().isStrictMode() ? callSiteFlags | CALLSITE_STRICT : callSiteFlags; + } + + /** + * Load an identity node + * + * @param identNode an identity node to load + * @return the method generator used + */ + private MethodEmitter loadIdent(final IdentNode identNode) { + final Symbol symbol = identNode.getSymbol(); + + if (!symbol.isScope()) { + assert symbol.hasSlot() && symbol.getSlot() != 0 || symbol.isThis(); + return method.load(symbol); + } + + final String name = symbol.getName(); + + if (CompilerConstants.__FILE__.name().equals(name)) { + return method.load(identNode.getSource().getName()); + } else if (CompilerConstants.__DIR__.name().equals(name)) { + return method.load(identNode.getSource().getBase()); + } else if (CompilerConstants.__LINE__.name().equals(name)) { + return method.load(identNode.getSource().getLine(identNode.position())).convert(Type.OBJECT); + } else { + assert identNode.getSymbol().isScope() : identNode + " is not in scope!"; + + final int flags = CALLSITE_SCOPE | getCallSiteFlags(); + method.loadScope(); + + if (symbol.isFastScope(getCurrentFunctionNode())) { + // Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope. + if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD) { + return loadSharedScopeVar(identNode.getType(), symbol, flags); + } + return loadFastScopeVar(identNode.getType(), symbol, flags, identNode.isFunction()); + } + return method.dynamicGet(identNode.getType(), identNode.getName(), flags, identNode.isFunction()); + } + } + + private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) { + method.load(symbol.isFastScope(getCurrentFunctionNode()) ? getScopeProtoDepth(getCurrentBlock(), symbol) : -1); + final SharedScopeCall scopeCall = getScopeGet(valueType, symbol, flags | CALLSITE_FAST_SCOPE); + scopeCall.generateInvoke(method); + return method; + } + + private MethodEmitter loadFastScopeVar(final Type valueType, final Symbol symbol, final int flags, final boolean isMethod) { + loadFastScopeProto(symbol, false); + method.dynamicGet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE, isMethod); + return method; + } + + private MethodEmitter storeFastScopeVar(final Type valueType, final Symbol symbol, final int flags) { + loadFastScopeProto(symbol, true); + method.dynamicSet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE); + return method; + } + + private static int getScopeProtoDepth(final Block currentBlock, final Symbol symbol) { + if (currentBlock == symbol.getBlock()) { + return 0; + } + + final int delta = currentBlock.needsScope() ? 1 : 0; + final Block parentBlock = currentBlock.getParent(); + + if (parentBlock != null) { + final int result = getScopeProtoDepth(parentBlock, symbol); + if (result != -1) { + return delta + result; + } + } + + if (currentBlock instanceof FunctionNode) { + for (final Block lookupBlock : ((FunctionNode)currentBlock).getReferencingParentBlocks()) { + final int result = getScopeProtoDepth(lookupBlock, symbol); + if (result != -1) { + return delta + result; + } + } + } + + return -1; + } + + private void loadFastScopeProto(final Symbol symbol, final boolean swap) { + final int depth = getScopeProtoDepth(getCurrentBlock(), symbol); + assert depth != -1; + if(depth > 0) { + if (swap) { + method.swap(); + } + for (int i = 0; i < depth; i++) { + method.invoke(ScriptObject.GET_PROTO); + } + if (swap) { + method.swap(); + } + } + } + + /** + * Generate code that loads this node to the stack. This method is only + * public to be accessible from the maps sub package. Do not call externally + * + * @param node node to load + * + * @return the method emitter used + */ + public MethodEmitter load(final Node node) { + return load(node, false); + } + + private MethodEmitter load(final Node node, final boolean baseAlreadyOnStack) { + final Symbol symbol = node.getSymbol(); + + // If we lack symbols, we just generate what we see. + if (symbol == null) { + node.accept(this); + return method; + } + + /* + * The load may be of type IdentNode, e.g. "x", AccessNode, e.g. "x.y" + * or IndexNode e.g. "x[y]". Both AccessNodes and IndexNodes are + * BaseNodes and the logic for loading the base object is reused + */ + final CodeGenerator codegen = this; + + node.accept(new NodeVisitor(compileUnit, method) { + @Override + public Node enter(final IdentNode identNode) { + loadIdent(identNode); + return null; + } + + @Override + public Node enter(final AccessNode accessNode) { + if (!baseAlreadyOnStack) { + load(accessNode.getBase()).convert(Type.OBJECT); + } + assert method.peekType().isObject(); + method.dynamicGet(node.getType(), accessNode.getProperty().getName(), getCallSiteFlags(), accessNode.isFunction()); + return null; + } + + @Override + public Node enter(final IndexNode indexNode) { + if (!baseAlreadyOnStack) { + load(indexNode.getBase()); + load(indexNode.getIndex()); + } + method.dynamicGetIndex(node.getType(), getCallSiteFlags(), indexNode.isFunction()); + return null; + } + + @Override + public Node enterDefault(final Node otherNode) { + otherNode.accept(codegen); // generate code for whatever we are looking at. + method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there) + return null; + } + }); + + return method; + } + + @Override + public Node enter(final AccessNode accessNode) { + if (accessNode.testResolved()) { + return null; + } + + load(accessNode); + + return null; + } + + /** + * Initialize a specific set of vars to undefined. This has to be done at + * the start of each method for local variables that aren't passed as + * parameters. + * + * @param symbols list of symbols. + */ + private void initSymbols(final Iterable symbols) { + final LinkedList numbers = new LinkedList<>(); + final LinkedList objects = new LinkedList<>(); + + for (final Symbol symbol : symbols) { + /* + * The following symbols are guaranteed to be defined and thus safe + * from having unsigned written to them: parameters internals this + * + * Otherwise we must, unless we perform control/escape analysis, + * assign them undefined. + */ + final boolean isInternal = symbol.isParam() || symbol.isInternal() || symbol.isThis() || !symbol.canBeUndefined(); + + if (symbol.hasSlot() && !isInternal) { + assert symbol.getSymbolType().isNumber() || symbol.getSymbolType().isObject() : "no potentially undefined narrower local vars than doubles are allowed: " + symbol + " in " + getCurrentFunctionNode(); + if (symbol.getSymbolType().isNumber()) { + numbers.add(symbol); + } else if (symbol.getSymbolType().isObject()) { + objects.add(symbol); + } + } + } + + initSymbols(numbers, Type.NUMBER); + initSymbols(objects, Type.OBJECT); + } + + private void initSymbols(final LinkedList symbols, final Type type) { + if (symbols.isEmpty()) { + return; + } + + method.loadUndefined(type); + while (!symbols.isEmpty()) { + final Symbol symbol = symbols.removeFirst(); + if (!symbols.isEmpty()) { + method.dup(); + } + method.store(symbol); + } + } + + /** + * Create symbol debug information. + * + * @param block block containing symbols. + */ + private void symbolInfo(final Block block) { + for (final Symbol symbol : block.getFrame().getSymbols()) { + method.localVariable(symbol, block.getEntryLabel(), block.getBreakLabel()); + } + } + + @Override + public Node enter(final Block block) { + if (block.testResolved()) { + return null; + } + + method.label(block.getEntryLabel()); + initLocals(block); + + return block; + } + + @Override + public Node leave(final Block block) { + method.label(block.getBreakLabel()); + symbolInfo(block); + + if (block.needsScope()) { + popBlockScope(block); + } + + return block; + } + + private void popBlockScope(final Block block) { + final Label exitLabel = new Label("block_exit"); + final Label recoveryLabel = new Label("block_catch"); + final Label skipLabel = new Label("skip_catch"); + + /* pop scope a la try-finally */ + method.loadScope(); + method.invoke(ScriptObject.GET_PROTO); + method.storeScope(); + method._goto(skipLabel); + method.label(exitLabel); + + method._catch(recoveryLabel); + method.loadScope(); + method.invoke(ScriptObject.GET_PROTO); + method.storeScope(); + method.athrow(); + method.label(skipLabel); + method._try(block.getEntryLabel(), exitLabel, recoveryLabel, Throwable.class); + } + + @Override + public Node enter(final BreakNode breakNode) { + if (breakNode.testResolved()) { + return null; + } + + for (int i = 0; i < breakNode.getScopeNestingLevel(); i++) { + closeWith(); + } + + method.splitAwareGoto(breakNode.getTargetLabel()); + + return null; + } + + private MethodEmitter loadArgs(final List args) { + return loadArgs(args, null, false, args.size()); + } + + private MethodEmitter loadArgs(final List args, final String signature, final boolean isVarArg, final int argCount) { + // arg have already been converted to objects here. + if (isVarArg || argCount > LinkerCallSite.ARGLIMIT) { + loadArgsArray(args); + return method; + } + + // pad with undefined if size is too short. argCount is the real number of args + int n = 0; + final Type[] params = signature == null ? null : Type.getMethodArguments(signature); + for (final Node arg : args) { + assert arg != null; + load(arg); + if (params != null) { + method.convert(params[n]); + } + n++; + if (n >= argCount) { + break; + } + } + + while (n < argCount) { + method.loadUndefined(Type.OBJECT); + n++; + } + + return method; + } + + /** + * Create a new function object, including generating its stub code. + * + * @param functionNode FunctionNode to utilize. + */ + private void newFunctionObject(final FunctionNode functionNode) { + // Turn thisProperties into keys and symbols for the FunctionAnalyzer + final Map thisProperties = functionNode.getThisProperties(); + + final List keys = new ArrayList<>(); + final List symbols = new ArrayList<>(); + + for (final Entry entry : thisProperties.entrySet()) { + keys.add(entry.getKey()); + symbols.add(entry.getValue().getSymbol()); + } + + new FunctionObjectCreator(this, functionNode, keys, symbols).makeObject(method); + } + + @Override + public Node enter(final CallNode callNode) { + if (callNode.testResolved()) { + return null; + } + + final List args = callNode.getArgs(); + final Node function = callNode.getFunction(); + final FunctionNode currentFunction = getCurrentFunctionNode(); + final Block currentBlock = getCurrentBlock(); + + function.accept(new NodeVisitor(compileUnit, method) { + + private void sharedScopeCall(final IdentNode identNode, final int flags) { + final Symbol symbol = identNode.getSymbol(); + int scopeCallFlags = flags; + method.loadScope(); + if (symbol.isFastScope(currentFunction)) { + method.load(getScopeProtoDepth(currentBlock, symbol)); + scopeCallFlags |= CALLSITE_FAST_SCOPE; + } else { + method.load(-1); // Bypass fast-scope code in shared callsite + } + loadArgs(args); + final Type[] paramTypes = method.getTypesFromStack(args.size()); + final SharedScopeCall scopeCall = getScopeCall(symbol, identNode.getType(), callNode.getType(), paramTypes, scopeCallFlags); + scopeCall.generateInvoke(method); + } + + private void scopeCall(final IdentNode node, final int flags) { + load(node); + method.convert(Type.OBJECT); // foo() makes no sense if foo == 3 + // ScriptFunction will see CALLSITE_SCOPE and will bind scope accordingly. + method.loadNull(); + loadArgs(args); + method.dynamicCall(callNode.getType(), args.size(), flags); + } + + private void evalCall(final IdentNode node, final int flags) { + load(node); + method.convert(Type.OBJECT); // foo() makes no sense if foo == 3 + + final Label not_eval = new Label("not_eval"); + final Label eval_done = new Label("eval_done"); + + // check if this is the real built-in eval + method.dup(); + globalIsEval(); + + method.ifeq(not_eval); + // We don't need ScriptFunction object for 'eval' + method.pop(); + + method.loadScope(); // Load up self (scope). + + final CallNode.EvalArgs evalArgs = callNode.getEvalArgs(); + // load evaluated code + load(evalArgs.code); + method.convert(Type.OBJECT); + // special/extra 'eval' arguments + load(evalArgs.evalThis); + method.load(evalArgs.location); + method.load(evalArgs.strictMode); + method.convert(Type.OBJECT); + + // direct call to Global.directEval + globalDirectEval(); + method.convert(callNode.getType()); + method._goto(eval_done); + + method.label(not_eval); + // This is some scope 'eval' or global eval replaced by user + // but not the built-in ECMAScript 'eval' function call + method.loadNull(); + loadArgs(args); + method.dynamicCall(callNode.getType(), args.size(), flags); + + method.label(eval_done); + } + + @Override + public Node enter(final IdentNode node) { + final Symbol symbol = node.getSymbol(); + + if (symbol.isScope()) { + final int flags = getCallSiteFlags() | CALLSITE_SCOPE; + final int useCount = symbol.getUseCount(); + + // Threshold for generating shared scope callsite is lower for fast scope symbols because we know + // we can dial in the correct scope. However, we als need to enable it for non-fast scopes to + // support huge scripts like mandreel.js. + if (callNode.isEval()) { + evalCall(node, flags); + } else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD + || (!symbol.isFastScope(currentFunction) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD) + || callNode.inWithBlock()) { + scopeCall(node, flags); + } else { + sharedScopeCall(node, flags); + } + assert method.peekType().equals(callNode.getType()); + } else { + enterDefault(node); + } + + return null; + } + + @Override + public Node enter(final AccessNode node) { + load(node.getBase()); + method.convert(Type.OBJECT); + method.dup(); + method.dynamicGet(node.getType(), node.getProperty().getName(), getCallSiteFlags(), true); + method.swap(); + loadArgs(args); + method.dynamicCall(callNode.getType(), args.size(), getCallSiteFlags()); + assert method.peekType().equals(callNode.getType()); + + return null; + } + + @Override + public Node enter(final ReferenceNode node) { + final FunctionNode callee = node.getReference(); + final boolean isVarArg = callee.isVarArg(); + final int argCount = isVarArg ? -1 : callee.getParameters().size(); + + final String signature = new FunctionSignature(true, callee.needsCallee(), callee.getReturnType(), isVarArg ? null : callee.getParameters()).toString(); + + if (callee.isStrictMode()) { // self is undefined + method.loadUndefined(Type.OBJECT); + } else { // get global from scope (which is the self) + globalInstance(); + } + + if (callee.needsCallee()) { // TODO: always true + newFunctionObject(callee); // TODO: if callee not needed, function object is used only to pass scope (could be optimized). if neither the scope nor the function object is needed by the callee, we can pass null instead. + } + + loadArgs(args, signature, isVarArg, argCount); + method.invokeStatic(callee.getCompileUnit().getUnitClassName(), callee.getName(), signature); + assert method.peekType().equals(callee.getReturnType()) : method.peekType() + " != " + callee.getReturnType(); + + return null; + } + + @Override + public Node enter(final IndexNode node) { + load(node.getBase()); + method.convert(Type.OBJECT); + method.dup(); + load(node.getIndex()); + final Type indexType = node.getIndex().getType(); + if (indexType.isObject() || indexType.isBoolean()) { + method.convert(Type.OBJECT); //TODO + } + method.dynamicGetIndex(node.getType(), getCallSiteFlags(), true); + method.swap(); + loadArgs(args); + method.dynamicCall(callNode.getType(), args.size(), getCallSiteFlags()); + assert method.peekType().equals(callNode.getType()); + + return null; + } + + @Override + protected Node enterDefault(final Node node) { + // Load up function. + load(function); + method.convert(Type.OBJECT); //TODO, e.g. booleans can be used as functions + method.loadNull(); // ScriptFunction will figure out the correct this when it sees CALLSITE_SCOPE + + loadArgs(args); + method.dynamicCall(callNode.getType(), args.size(), getCallSiteFlags() | CALLSITE_SCOPE); + assert method.peekType().equals(callNode.getType()); + + return null; + } + }); + + method.store(callNode.getSymbol()); + + return null; + } + + @Override + public Node enter(final ContinueNode continueNode) { + if (continueNode.testResolved()) { + return null; + } + + for (int i = 0; i < continueNode.getScopeNestingLevel(); i++) { + closeWith(); + } + + method.splitAwareGoto(continueNode.getTargetLabel()); + + return null; + } + + @Override + public Node enter(final DoWhileNode doWhileNode) { + return enter((WhileNode)doWhileNode); + } + + @Override + public Node enter(final EmptyNode emptyNode) { + return null; + } + + @Override + public Node enter(final ExecuteNode executeNode) { + if (executeNode.testResolved()) { + return null; + } + + final Node expression = executeNode.getExpression(); + expression.accept(this); + + return null; + } + + @Override + public Node enter(final ForNode forNode) { + if (forNode.testResolved()) { + return null; + } + + final Node test = forNode.getTest(); + final Block body = forNode.getBody(); + final Node modify = forNode.getModify(); + + final Label breakLabel = forNode.getBreakLabel(); + final Label continueLabel = forNode.getContinueLabel(); + final Label loopLabel = new Label("loop"); + + Node init = forNode.getInit(); + + if (forNode.isForIn()) { + final Symbol iter = forNode.getIterator(); + + // We have to evaluate the optional initializer expression + // of the iterator variable of the for-in statement. + if (init instanceof VarNode) { + init.accept(this); + init = ((VarNode)init).getName(); + } + + load(modify); + assert modify.getType().isObject(); + method.invoke(forNode.isForEach() ? ScriptRuntime.TO_VALUE_ITERATOR : ScriptRuntime.TO_PROPERTY_ITERATOR); + method.store(iter); + method._goto(continueLabel); + method.label(loopLabel); + + new Store(init) { + @Override + protected void evaluate() { + method.load(iter); + method.invoke(interfaceCallNoLookup(Iterator.class, "next", Object.class)); + } + }.store(); + + body.accept(this); + + method.label(continueLabel); + method.load(iter); + method.invoke(interfaceCallNoLookup(Iterator.class, "hasNext", boolean.class)); + method.ifne(loopLabel); + method.label(breakLabel); + } else { + if (init != null) { + init.accept(this); + } + + final Label testLabel = new Label("test"); + + method._goto(testLabel); + method.label(loopLabel); + body.accept(this); + method.label(continueLabel); + + if (!body.isTerminal() && modify != null) { + load(modify); + } + + method.label(testLabel); + if (test != null) { + new BranchOptimizer(this, method).execute(test, loopLabel, true); + } else { + method._goto(loopLabel); + } + + method.label(breakLabel); + } + + return null; + } + + private void initLocals(final Block block) { + initLocals(block, null); + } + + /** + * Initialize the slots in a frame to undefined. + * + * @param block block with local vars. + */ + private void initLocals(final Block block, final AccessSpecializer accessSpecializer) { + final FunctionNode function = block.getFunction(); + final boolean isFunctionNode = block == function; + + /* + * Get the symbols from the frame and realign the frame so that all + * slots get correct numbers. The slot numbering is not fixed until + * after initLocals has been run + */ + final Frame frame = block.getFrame(); + final List symbols = frame.getSymbols(); + + /* Fix the predefined slots so they have numbers >= 0, like varargs. */ + frame.realign(); + + /* + * Determine if block needs scope, if not, just do initSymbols for this block. + */ + if (block.needsScope()) { + /* + * Determine if function is varargs and consequently variables have to + * be in the scope. + */ + final boolean isVarArg = function.isVarArg(); + final boolean varsInScope = function.varsInScope(); + + // TODO for LET we can do better: if *block* does not contain any eval/with, we don't need its vars in scope. + + final List nameList = new ArrayList<>(); + final List locals = new ArrayList<>(); + + // note that in the case of a varargs vector the arguments in the vector should NOT have local slots + // this was a bug: see NASHORN-21 + if (isVarArg) { + for (final IdentNode param : function.getParameters()) { + param.getSymbol().setNeedsSlot(false); + } + } + + // If there are variable arguments, we need to load them (functions only). + if (isFunctionNode && isVarArg) { + method.loadVarArgs(); + method.loadCallee(); + method.load(function.getParameters().size()); + globalAllocateArguments(); + method.storeArguments(); + } + + // Initalize symbols and values + final List newSymbols = new ArrayList<>(); + final List values = new ArrayList<>(); + + for (final Symbol symbol : symbols) { + if (symbol.isInternal() || symbol.isThis()) { + continue; + } + + if (symbol.isVar() && (varsInScope || symbol.isScope())) { + nameList.add(symbol.getName()); + newSymbols.add(symbol); + values.add(null); + symbol.setIsScope(); + symbol.setNeedsSlot(false); + } else if (symbol.isVar()) { + assert symbol.hasSlot() : symbol + " should have a slot only, no scope"; + locals.add(symbol); + } else if (symbol.isParam() && (varsInScope || isVarArg || symbol.isScope())) { + nameList.add(symbol.getName()); + newSymbols.add(symbol); + values.add(isVarArg ? null : symbol); + symbol.setIsScope(); + if (isVarArg) { + symbol.setNeedsSlot(false); + } + } + } + + /* Correct slot numbering again */ + frame.realign(); + + // we may have locals that need to be initialized + initSymbols(locals); + + if (isFunctionNode) { + initScope(); + } + + if (accessSpecializer != null) { + ((FunctionNode)block).accept(accessSpecializer); + } + + /* + * Create a new object based on the symbols and values, generate + * bootstrap code for object + */ + final FieldObjectCreator foc = new FieldObjectCreator(this, nameList, newSymbols, values, true, isVarArg) { + @Override + protected Type getValueType(final Symbol value) { + return value.getSymbolType(); + } + + @Override + protected void loadValue(final Symbol value) { + method.load(value); + } + }; + foc.makeObject(method); + + // runScript(): merge scope into global + if (isFunctionNode && function.isScript()) { + method.invoke(ScriptRuntime.MERGE_SCOPE); + } + + method.storeScope(); + } else { + initSymbols(symbols); + + if (isFunctionNode) { + initScope(); + } + } + + // Debugging: print symbols? @see --print-symbols flag + printSymbols(block, (isFunctionNode ? "Function " : "Block in ") + (function.getIdent() == null ? "" : function.getIdent().getName())); + } + + private void initScope() { + method.loadCallee(); + method.invoke(ScriptFunction.GET_SCOPE); + method.storeScope(); + } + + @Override + public Node enter(final FunctionNode functionNode) { + if (functionNode.testResolved()) { + return null; + } + + compileUnit = functionNode.getCompileUnit(); + assert compileUnit != null; + + method = compileUnit.getClassEmitter().method(functionNode); + functionNode.setMethodEmitter(method); + // Mark end for variable tables. + method.begin(); + method.label(functionNode.getEntryLabel()); + + initLocals(functionNode, new AccessSpecializer()); + + return functionNode; + } + + @Override + public Node leave(final FunctionNode functionNode) { + // Mark end for variable tables. + method.label(functionNode.getBreakLabel()); + + if (!functionNode.needsScope()) { + method.markerVariable(LEAF.tag(), functionNode.getEntryLabel(), functionNode.getBreakLabel()); + } + + symbolInfo(functionNode); + try { + method.end(); // wrap up this method + } catch (final Throwable t) { + Context.printStackTrace(t); + final VerifyError e = new VerifyError("Code generation bug in \"" + functionNode.getName() + "\": likely stack misaligned: " + t + " " + functionNode.getSource().getName()); + e.initCause(t); + throw e; + } + + return functionNode; + } + + @Override + public Node enter(final IdentNode identNode) { + return null; + } + + @Override + public Node enter(final IfNode ifNode) { + if (ifNode.testResolved()) { + return null; + } + + final Node test = ifNode.getTest(); + final Block pass = ifNode.getPass(); + final Block fail = ifNode.getFail(); + + final Label failLabel = new Label("if_fail"); + final Label afterLabel = fail == null ? failLabel : new Label("if_done"); + + new BranchOptimizer(this, method).execute(test, failLabel, false); + + boolean passTerminal = false; + boolean failTerminal = false; + + pass.accept(this); + if (!pass.hasTerminalFlags()) { + method._goto(afterLabel); //don't fallthru to fail block + } else { + passTerminal = pass.isTerminal(); + } + + if (fail != null) { + method.label(failLabel); + fail.accept(this); + failTerminal = fail.isTerminal(); + } + + //if if terminates, put the after label there + if (!passTerminal || !failTerminal) { + method.label(afterLabel); + } + + return null; + } + + @Override + public Node enter(final IndexNode indexNode) { + if (indexNode.testResolved()) { + return null; + } + + load(indexNode); + + return null; + } + + @Override + public Node enter(final LineNumberNode lineNumberNode) { + if (lineNumberNode.testResolved()) { + return null; + } + + final Label label = new Label("line:" + lineNumberNode.getLineNumber() + " (" + getCurrentFunctionNode().getName() + ")"); + method.label(label); + method.lineNumber(lineNumberNode.getLineNumber(), label); + + return null; + } + + /** + * Load a list of nodes as an array of a specific type + * The array will contain the visited nodes. + * + * @param arrayLiteralNode the array of contents + * @param arrayType the type of the array, e.g. ARRAY_NUMBER or ARRAY_OBJECT + * + * @return the method generator that was used + */ + private MethodEmitter loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) { + assert arrayType == Type.INT_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY; + + final Node[] nodes = arrayLiteralNode.getValue(); + final Object presets = arrayLiteralNode.getPresets(); + final int[] postsets = arrayLiteralNode.getPostsets(); + final Class type = arrayType.getTypeClass(); + final List units = arrayLiteralNode.getUnits(); + + loadConstant(presets); + + final Type elementType = arrayType.getElementType(); + + if (units != null) { + final CompileUnit savedCompileUnit = compileUnit; + final MethodEmitter savedMethod = method; + + try { + for (final ArrayUnit unit : units) { + compileUnit = unit.getCompileUnit(); + + final String className = compileUnit.getUnitClassName(); + final String name = compiler.uniqueName(SPLIT_PREFIX.tag()); + final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type); + + method = compileUnit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature); + method.setFunctionNode(getCurrentFunctionNode()); + method.begin(); + + fixScopeSlot(); + + method.load(arrayType, SPLIT_ARRAY_ARG.slot()); + + for (int i = unit.getLo(); i < unit.getHi(); i++) { + storeElement(nodes, elementType, postsets[i]); + } + + method._return(); + method.end(); + + savedMethod.loadThis(); + savedMethod.swap(); + savedMethod.loadCallee(); + savedMethod.swap(); + savedMethod.loadScope(); + savedMethod.swap(); + savedMethod.invokeStatic(className, name, signature); + } + } finally { + compileUnit = savedCompileUnit; + method = savedMethod; + } + + return method; + } + + for (final int postset : postsets) { + storeElement(nodes, elementType, postset); + } + + return method; + } + + private void storeElement(final Node[] nodes, final Type elementType, final int index) { + method.dup(); + method.load(index); + + final Node element = nodes[index]; + + if (element == null) { + method.loadEmpty(elementType); + } else { + assert elementType.isEquivalentTo(element.getType()) : "array element type doesn't match array type"; + load(element); + } + + method.arraystore(); + } + + private MethodEmitter loadArgsArray(final List args) { + final Object[] array = new Object[args.size()]; + loadConstant(array); + + for (int i = 0; i < args.size(); i++) { + method.dup(); + method.load(i); + load(args.get(i)).convert(Type.OBJECT); //has to be upcast to object or we fail + method.arraystore(); + } + + return method; + } + + /** + * Load a constant from the constant array. This is only public to be callable from the objects + * subpackage. Do not call directly. + * + * @param string string to load + */ + public void loadConstant(final String string) { + final String unitClassName = compileUnit.getUnitClassName(); + final ClassEmitter classEmitter = compileUnit.getClassEmitter(); + final int index = compiler.getConstantData().add(string); + + method.load(index); + method.invokeStatic(unitClassName, GET_STRING.tag(), methodDescriptor(String.class, int.class)); + classEmitter.needGetConstantMethod(String.class); + } + + /** + * Load a constant from the constant array. This is only public to be callable from the objects + * subpackage. Do not call directly. + * + * @param object object to load + */ + public void loadConstant(final Object object) { + final String unitClassName = compileUnit.getUnitClassName(); + final ClassEmitter classEmitter = compileUnit.getClassEmitter(); + final int index = compiler.getConstantData().add(object); + final Class cls = object.getClass(); + + if (cls == PropertyMap.class) { + method.load(index); + method.invokeStatic(unitClassName, GET_MAP.tag(), methodDescriptor(PropertyMap.class, int.class)); + classEmitter.needGetConstantMethod(PropertyMap.class); + } else if (cls.isArray()) { + method.load(index); + final String methodName = ClassEmitter.getArrayMethodName(cls); + method.invokeStatic(unitClassName, methodName, methodDescriptor(cls, int.class)); + classEmitter.needGetConstantMethod(cls); + } else { + method.loadConstants(unitClassName).load(index).arrayload(); + if (cls != Object.class) { + method.checkcast(cls); + } + } + } + + // literal values + private MethodEmitter load(final LiteralNode node) { + final Object value = node.getValue(); + + if (value == null) { + method.loadNull(); + } else if (value instanceof Undefined) { + method.loadUndefined(Type.OBJECT); + } else if (value instanceof String) { + final String string = (String)value; + + if (string.length() > (MethodEmitter.LARGE_STRING_THRESHOLD / 3)) { // 3 == max bytes per encoded char + loadConstant(string); + } else { + method.load(string); + } + } else if (value instanceof RegexToken) { + loadRegex((RegexToken)value); + } else if (value instanceof Boolean) { + method.load((Boolean)value); + } else if (value instanceof Integer) { + method.load((Integer)value); + } else if (value instanceof Long) { + method.load((Long)value); + } else if (value instanceof Double) { + method.load((Double)value); + } else if (node instanceof ArrayLiteralNode) { + final ArrayType type = (ArrayType)node.getType(); + loadArray((ArrayLiteralNode)node, type); + globalAllocateArray(type); + } else { + assert false : "Unknown literal for " + node.getClass() + " " + value.getClass() + " " + value; + } + + return method; + } + + private MethodEmitter loadRegexToken(final RegexToken value) { + method.load(value.getExpression()); + method.load(value.getOptions()); + return globalNewRegExp(); + } + + private MethodEmitter loadRegex(final RegexToken regexToken) { + if (regexFieldCount > MAX_REGEX_FIELDS) { + return loadRegexToken(regexToken); + } + // emit field + final String regexName = compiler.uniqueName(REGEX_PREFIX.tag()); + final ClassEmitter classEmitter = compileUnit.getClassEmitter(); + + classEmitter.field(EnumSet.of(PRIVATE, STATIC), regexName, Object.class); + regexFieldCount++; + + // get field, if null create new regex, finally clone regex object + method.getStatic(compileUnit.getUnitClassName(), regexName, typeDescriptor(Object.class)); + method.dup(); + final Label cachedLabel = new Label("cached"); + method.ifnonnull(cachedLabel); + + method.pop(); + loadRegexToken(regexToken); + method.dup(); + method.putStatic(compileUnit.getUnitClassName(), regexName, typeDescriptor(Object.class)); + + method.label(cachedLabel); + globalRegExpCopy(); + + return method; + } + + @SuppressWarnings("rawtypes") + @Override + public Node enter(final LiteralNode literalNode) { + load(literalNode).store(literalNode.getSymbol()); + return null; + } + + @Override + public Node enter(final ObjectNode objectNode) { + if (objectNode.testResolved()) { + return null; + } + + final List elements = objectNode.getElements(); + final int size = elements.size(); + + final List keys = new ArrayList<>(); + final List symbols = new ArrayList<>(); + final List values = new ArrayList<>(); + + boolean hasGettersSetters = false; + + for (int i = 0; i < size; i++) { + final PropertyNode propertyNode = (PropertyNode)elements.get(i); + final Node value = propertyNode.getValue(); + final String key = propertyNode.getKeyName(); + final Symbol symbol = value == null ? null : propertyNode.getSymbol(); + + if (value == null) { + hasGettersSetters = true; + } + + keys.add(key); + symbols.add(symbol); + values.add(value); + } + + new FieldObjectCreator(this, keys, symbols, values) { + @Override + protected Type getValueType(final Node node) { + return node.getType(); + } + + @Override + protected void loadValue(final Node node) { + load(node); + } + + /** + * Ensure that the properties start out as object types so that + * we can do putfield initializations instead of dynamicSetIndex + * which would be the case to determine initial property type + * otherwise. + * + * Use case, it's very expensive to do a million var x = {a:obj, b:obj} + * just to have to invalidate them immediately on initialization + * + * see NASHORN-594 + */ + @Override + protected MapCreator newMapCreator(final Class fieldObjectClass) { + return new ObjectMapCreator(fieldObjectClass, keys, symbols); + } + + }.makeObject(method); + + method.dup(); + globalObjectPrototype(); + method.invoke(ScriptObject.SET_PROTO); + + if (!hasGettersSetters) { + method.store(objectNode.getSymbol()); + return null; + } + + for (final Node element : elements) { + final PropertyNode propertyNode = (PropertyNode)element; + final Object key = propertyNode.getKey(); + final ReferenceNode getter = (ReferenceNode)propertyNode.getGetter(); + final ReferenceNode setter = (ReferenceNode)propertyNode.getSetter(); + + if (getter == null && setter == null) { + continue; + } + + method.dup().loadKey(key); + + if (getter == null) { + method.loadNull(); + } else { + getter.accept(this); + } + + if (setter == null) { + method.loadNull(); + } else { + setter.accept(this); + } + + method.invoke(ScriptObject.SET_USER_ACCESSORS); + } + + method.store(objectNode.getSymbol()); + + return null; + } + + @Override + public Node enter(final ReferenceNode referenceNode) { + if (referenceNode.testResolved()) { + return null; + } + + newFunctionObject(referenceNode.getReference()); + + return null; + } + + @Override + public Node enter(final ReturnNode returnNode) { + if (returnNode.testResolved()) { + return null; + } + + // Set the split return flag in the scope if this is a split method fragment. + if (method.getSplitNode() != null) { + assert method.getSplitNode().hasReturn() : "unexpected return in split node"; + + method.loadScope(); + method.checkcast(Scope.class); + method.load(0); + method.invoke(Scope.SET_SPLIT_STATE); + } + + final Node expression = returnNode.getExpression(); + if (expression != null) { + load(expression); + } else { + method.loadUndefined(getCurrentFunctionNode().getReturnType()); + } + + method._return(getCurrentFunctionNode().getReturnType()); + + return null; + } + + private static boolean isNullLiteral(final Node node) { + return node instanceof LiteralNode && ((LiteralNode) node).isNull(); + } + + private boolean nullCheck(final RuntimeNode runtimeNode, final List args, final String signature) { + final Request request = runtimeNode.getRequest(); + + if (!Request.isEQ(request) && !Request.isNE(request)) { + return false; + } + + assert args.size() == 2 : "EQ or NE or TYPEOF need two args"; + + Node lhs = args.get(0); + Node rhs = args.get(1); + + if (isNullLiteral(lhs)) { + final Node tmp = lhs; + lhs = rhs; + rhs = tmp; + } + + if (isNullLiteral(rhs)) { + final Label trueLabel = new Label("trueLabel"); + final Label falseLabel = new Label("falseLabel"); + final Label endLabel = new Label("end"); + + load(lhs); + method.dup(); + if (Request.isEQ(request)) { + method.ifnull(trueLabel); + } else if (Request.isNE(request)) { + method.ifnonnull(trueLabel); + } else { + assert false : "Invalid request " + request; + } + + method.label(falseLabel); + load(rhs); + method.invokeStatic(CompilerConstants.className(ScriptRuntime.class), request.toString(), signature); + method._goto(endLabel); + + method.label(trueLabel); + // if NE (not strict) this can be "undefined != null" which is supposed to be false + if (request == Request.NE) { + method.loadUndefined(Type.OBJECT); + final Label isUndefined = new Label("isUndefined"); + final Label afterUndefinedCheck = new Label("afterUndefinedCheck"); + method.if_acmpeq(isUndefined); + // not undefined + method.load(true); + method._goto(afterUndefinedCheck); + method.label(isUndefined); + method.load(false); + method.label(afterUndefinedCheck); + } else { + method.pop(); + method.load(true); + } + method.label(endLabel); + method.convert(runtimeNode.getType()); + method.store(runtimeNode.getSymbol()); + + return true; + } + + return false; + } + + private boolean specializationCheck(final RuntimeNode.Request request, final Node node, final List args) { + if (!request.canSpecialize()) { + return false; + } + + assert args.size() == 2; + final Node lhs = args.get(0); + final Node rhs = args.get(1); + + final Type returnType = node.getType(); + load(lhs); + load(rhs); + + Request finalRequest = request; + + final Request reverse = Request.reverse(request); + if (method.peekType().isObject() && reverse != null) { + if (!method.peekType(1).isObject()) { + method.swap(); + finalRequest = reverse; + } + } + + method.dynamicRuntimeCall( + new SpecializedRuntimeNode( + finalRequest, + new Type[] { + method.peekType(1), + method.peekType() + }, + returnType).getInitialName(), + returnType, + finalRequest); + + method.convert(node.getType()); + method.store(node.getSymbol()); + + return true; + } + + @Override + public Node enter(final RuntimeNode runtimeNode) { + if (runtimeNode.testResolved()) { + return null; + } + + /* + * First check if this should be something other than a runtime node + * AccessSpecializer might have changed the type + */ + if (runtimeNode.isPrimitive()) { + + final Node lhs = runtimeNode.getArgs().get(0); + Node rhs = null; + + if (runtimeNode.getArgs().size() > 1) { + rhs = runtimeNode.getArgs().get(1); + } + + final Type type = runtimeNode.getType(); + final Symbol symbol = runtimeNode.getSymbol(); + + switch (runtimeNode.getRequest()) { + case EQ: + case EQ_STRICT: + return enterCmp(lhs, rhs, Condition.EQ, type, symbol); + case NE: + case NE_STRICT: + return enterCmp(lhs, rhs, Condition.NE, type, symbol); + case LE: + return enterCmp(lhs, rhs, Condition.LE, type, symbol); + case LT: + return enterCmp(lhs, rhs, Condition.LT, type, symbol); + case GE: + return enterCmp(lhs, rhs, Condition.GE, type, symbol); + case GT: + return enterCmp(lhs, rhs, Condition.GT, type, symbol); + case ADD: + return enterNumericAdd(lhs, rhs, type, symbol); + default: + // it's ok to send this one on with only primitive arguments, maybe INSTANCEOF(true, true) or similar + // assert false : runtimeNode + " has all primitive arguments. This is an inconsistent state"; + break; + } + } + + // Get the request arguments. + final List args = runtimeNode.getArgs(); + + if (nullCheck(runtimeNode, args, new FunctionSignature(false, runtimeNode.getType(), args).toString())) { + return null; + } + + if (specializationCheck(runtimeNode.getRequest(), runtimeNode, args)) { + return null; + } + + for (final Node arg : runtimeNode.getArgs()) { + load(arg).convert(Type.OBJECT); //TODO this should not be necessary below Lower + } + + method.invokeStatic( + CompilerConstants.className(ScriptRuntime.class), + runtimeNode.getRequest().toString(), + new FunctionSignature( + false, + runtimeNode.getType(), + runtimeNode.getArgs().size()).toString()); + method.convert(runtimeNode.getType()); + method.store(runtimeNode.getSymbol()); + + return null; + } + + @Override + public Node enter(final SplitNode splitNode) { + if (splitNode.testResolved()) { + return null; + } + + final CompileUnit splitCompileUnit = splitNode.getCompileUnit(); + + final FunctionNode fn = getCurrentFunctionNode(); + final String className = splitCompileUnit.getUnitClassName(); + final String name = splitNode.getName(); + + final Class rtype = fn.getReturnType().getTypeClass(); + final Class[] ptypes = fn.isVarArg() ? + new Class[] {Object.class, ScriptFunction.class, ScriptObject.class, Object.class} : + new Class[] {Object.class, ScriptFunction.class, ScriptObject.class}; + + setCurrentCompileUnit(splitCompileUnit); + splitNode.setCompileUnit(splitCompileUnit); + + final Call splitCall = staticCallNoLookup( + className, + name, + methodDescriptor(rtype, ptypes)); + + setCurrentMethodEmitter( + splitCompileUnit.getClassEmitter().method( + EnumSet.of(Flag.PUBLIC, Flag.STATIC), + name, + rtype, + ptypes)); + + method.setFunctionNode(fn); + method.setSplitNode(splitNode); + splitNode.setMethodEmitter(method); + + final MethodEmitter caller = splitNode.getCaller(); + caller.loadThis(); + caller.loadCallee(); + caller.loadScope(); + if (fn.isVarArg()) { + caller.loadArguments(); + } + caller.invoke(splitCall); + caller.storeResult(); + + method.begin(); + + method.loadUndefined(fn.getReturnType()); + method.storeResult(); + + fixScopeSlot(); + + return splitNode; + } + + private void fixScopeSlot() { + if (getCurrentFunctionNode().getScopeNode().getSymbol().getSlot() != SCOPE.slot()) { + // TODO hack to move the scope to the expected slot (that's needed because split methods reuse the same slots as the root method) + method.load(Type.typeFor(ScriptObject.class), SCOPE.slot()); + method.storeScope(); + } + } + + @Override + public Node leave(final SplitNode splitNode) { + try { + // Wrap up this method. + method.loadResult(); + method._return(getCurrentFunctionNode().getReturnType()); + method.end(); + } catch (final Throwable t) { + Context.printStackTrace(t); + final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + compiler.getSource().getName()); + e.initCause(t); + throw e; + } + + // Handle return from split method if there was one. + final MethodEmitter caller = splitNode.getCaller(); + final List

    nametypedefaultdescription
    ${opt.name} ${opt.shortName == null? "" : opt.shortName}${opt.type}${defValue}${opt.description}
    + + + +
    + +

    Java Scripting Programmer's Guide

    + +
    + + + +

    Who is the Java Scripting API For?

    +Some useful characteristics of scripting languages +are: +
      +
    • Convenience: Most scripting languages are +dynamically typed. You can usually create new variables without +declaring the variable type, and you can reuse variables to store +objects of different types. Also, scripting languages tend to +perform many type conversions automatically, for example, +converting the number 10 to the text "10" as necessary.
    • +
    • Developing rapid prototypes: You can avoid the +edit-compile-run cycle and just use edit-run!
    • +
    • Application extension/customization: You can +"externalize" parts of your application - like configuration +scripts, business logic/rules and math expressions for financial +applications.
    • +
    • "Command line" shells for applications -for +debugging, runtime/deploy time configuration etc. Most applications +have a web-based GUI configuaration tool these days. But +sysadmins/deployers frequently prefer command line tools. Instead +of inventing ad-hoc scripting language for that purpose, a +"standard" scripting language can be used.
    • +
    +

    The JavaTM Scripting API +is a scripting language indepedent framework for using script +engines from Java code. With the Java Scripting API, it is possible +to write customizable/extendable applications in the Java language +and leave the customization scripting language choice to the end +user. The Java application developer need not choose the extension +language during development. If you write your application with +JSR-223 API, then your users can use any JSR-223 compliant +scripting language.

    +
    + +

    Scripting Package

    +

    The Java Scripting functionality is in the javax.script +package. This is a relatively small, simple API. The starting point +of the scripting API is the ScriptEngineManager class. +A ScriptEngineManager object can discover script engines through +the jar file service discovery mechanism. It can also instantiate +ScriptEngine objects that interpret scripts written in a specific +scripting language. The simplest way to use the scripting API is as +follows:

    +
      +
    1. Create a ScriptEngineManager +object.
    2. +
    3. Get a ScriptEngine object from the +manager.
    4. +
    5. Evaluate script using the ScriptEngine's +eval methods.
    6. +
    +

    Now, it is time to look at some sample code. While it is +not mandatory, it may be useful to know a bit of JavaScript to read +these examples.

    +
    + +

    Examples

    + +

    "Hello, World"

    +

    From the ScriptEngineManager instance, we +request a JavaScript engine instance using +getEngineByName method. On the script engine, the +eval method is called to execute a given String as +JavaScript code! For brevity, in this as well as in subsequent +examples, we have not shown exception handling. There are checked +and runtime exceptions thrown from javax.script API. +Needless to say, you have to handle the exceptions +appropriately.

    +
    +
    +// EvalScript.java
    +
    +import javax.script.*;
    +public class EvalScript {
    +    public static void main(String[] args) throws Exception {
    +        // create a script engine manager
    +        ScriptEngineManager factory = new ScriptEngineManager();
    +        // create a JavaScript engine
    +        ScriptEngine engine = factory.getEngineByName("nashorn");
    +        // evaluate JavaScript code from String
    +        engine.eval("print('Hello, World')");
    +    }
    +}
    +
    +
    +
    + +

    Evaluating a Script File

    +

    In this example, we call the eval method that +accepts java.io.Reader for the input source. The +script read by the given reader is executed. This way it is +possible to execute scripts from files, URLs and resources by +wrapping the relevant input stream objects as readers.

    +
    +
    +// EvalFile.java
    +
    +import javax.script.*;
    +
    +public class EvalFile {
    +    public static void main(String[] args) throws Exception {
    +        // create a script engine manager
    +        ScriptEngineManager factory = new ScriptEngineManager();
    +        // create JavaScript engine
    +        ScriptEngine engine = factory.getEngineByName("nashorn");
    +        // evaluate JavaScript code from given file - specified by first argument
    +        engine.eval(new java.io.FileReader(args[0]));
    +    }
    +}
    +
    +
    +Let us assume that we have the file named test.js with the +following text: +
    
    +print("This is hello from test.js");
    +
    +
    +We can run the above Java as +
    
    +java EvalFile test.js
    +
    +
    +
    + +

    Script Variables

    +

    When you embed script engines and scripts with your Java +application, you may want to expose your application objects as +global variables to scripts. This example demonstrates how you can +expose your application objects as global variables to a script. We +create a java.io.File in the application and expose +the same as a global variable with the name "file". The script can +access the variable - for example, it can call public methods on +it. Note that the syntax to access Java objects, methods and fields +is dependent on the scripting language. JavaScript supports the +most "natural" Java-like syntax.

    +
    
    +// ScriptVars.java
    +
    +import javax.script.*;
    +import java.io.*;
    +
    +public class ScriptVars { 
    +    public static void main(String[] args) throws Exception {
    +        ScriptEngineManager manager = new ScriptEngineManager();
    +        ScriptEngine engine = manager.getEngineByName("nashorn");
    +
    +        File f = new File("test.txt");
    +        // expose File object as variable to script
    +        engine.put("file", f);
    +
    +        // evaluate a script string. The script accesses "file" 
    +        // variable and calls method on it
    +        engine.eval("print(file.getAbsolutePath())");
    +    }
    +}
    +
    +
    +
    +
    + +

    Invoking Script Functions and Methods

    +

    Sometimes you may want to call a specific scripting function +repeatedly - for example, your application menu functionality might +be implemented by a script. In your menu's action event handler you +may want to call a specific script function. The following example +demonstrates invoking a specific script function from Java +code.

    +
    
    +// InvokeScriptFunction.java
    +
    +import javax.script.*;
    +
    +public class InvokeScriptFunction {
    +    public static void main(String[] args) throws Exception {
    +        ScriptEngineManager manager = new ScriptEngineManager();
    +        ScriptEngine engine = manager.getEngineByName("nashorn");
    +
    +        // JavaScript code in a String
    +        String script = "function hello(name) { print('Hello, ' + name); }";
    +        // evaluate script
    +        engine.eval(script);
    +
    +        // javax.script.Invocable is an optional interface.
    +        // Check whether your script engine implements it or not!
    +        // Note that the JavaScript engine implements Invocable interface.
    +        Invocable inv = (Invocable) engine;
    +
    +        // invoke the global function named "hello"
    +        inv.invokeFunction("hello", "Scripting!!" );
    +    }
    +}
    +
    +
    +
    +

    If your scripting language is object based (like JavaScript) or +object-oriented, then you can invoke a script method on a script +object.

    +
    
    +// InvokeScriptMethod.java
    +
    +import javax.script.*;
    +
    +public class InvokeScriptMethod {
    +    public static void main(String[] args) throws Exception {
    +        ScriptEngineManager manager = new ScriptEngineManager();
    +        ScriptEngine engine = manager.getEngineByName("nashorn");
    +
    +        // JavaScript code in a String. This code defines a script object 'obj'
    +        // with one method called 'hello'.        
    +        String script = "var obj = new Object(); obj.hello = function(name) { print('Hello, ' + name); }";
    +        // evaluate script
    +        engine.eval(script);
    +
    +        // javax.script.Invocable is an optional interface.
    +        // Check whether your script engine implements or not!
    +        // Note that the JavaScript engine implements Invocable interface.
    +        Invocable inv = (Invocable) engine;
    +
    +        // get script object on which we want to call the method
    +        Object obj = engine.get("obj");
    +
    +        // invoke the method named "hello" on the script object "obj"
    +        inv.invokeMethod(obj, "hello", "Script Method !!" );
    +    }
    +}
    +
    +
    +
    +
    + +

    Implementing Java Interfaces by Scripts

    +

    Instead of calling specific script functions from Java, +sometimes it is convenient to implement a Java interface by script +functions or methods. Also, by using interfaces we can avoid having +to use the javax.script API in many places. We can get +an interface implementor object and pass it to various Java APIs. +The following example demonstrates implementing the +java.lang.Runnable interface with a script.

    +
    
    +// RunnableImpl.java
    +
    +import javax.script.*;
    +
    +public class RunnableImpl {
    +    public static void main(String[] args) throws Exception {
    +        ScriptEngineManager manager = new ScriptEngineManager();
    +        ScriptEngine engine = manager.getEngineByName("nashorn");
    +
    +        // JavaScript code in a String
    +        String script = "function run() { print('run called'); }";
    +
    +        // evaluate script
    +        engine.eval(script);
    +
    +        Invocable inv = (Invocable) engine;
    +
    +        // get Runnable interface object from engine. This interface methods
    +        // are implemented by script functions with the matching name.
    +        Runnable r = inv.getInterface(Runnable.class);
    +
    +        // start a new thread that runs the script implemented
    +        // runnable interface
    +        Thread th = new Thread(r);
    +        th.start();
    +        th.join();
    +    }
    +}
    +
    +
    +

    If your scripting language is object-based or object-oriented, +it is possible to implement a Java interface by script methods on +script objects. This avoids having to call script global functions +for interface methods. The script object can store the "state" +associated with the interface implementor.

    +
    
    +// RunnableImplObject.java
    +
    +import javax.script.*;
    +
    +public class RunnableImplObject {
    +    public static void main(String[] args) throws Exception {
    +        ScriptEngineManager manager = new ScriptEngineManager();
    +        ScriptEngine engine = manager.getEngineByName("nashorn");
    +
    +        // JavaScript code in a String
    +        String script = "var obj = new Object(); obj.run = function() { print('run method called'); }";
    +
    +        // evaluate script
    +        engine.eval(script);
    +
    +        // get script object on which we want to implement the interface with
    +        Object obj = engine.get("obj");
    +
    +        Invocable inv = (Invocable) engine;
    +
    +        // get Runnable interface object from engine. This interface methods
    +        // are implemented by script methods of object 'obj'
    +        Runnable r = inv.getInterface(obj, Runnable.class);
    +
    +        // start a new thread that runs the script implemented
    +        // runnable interface
    +        Thread th = new Thread(r);
    +        th.start();
    +        th.join();
    +    }
    +}
    +
    +
    +
    + +

    Multiple Scopes for Scripts

    +

    In the script variables example, we +saw how to expose application objects as script global variables. +It is possible to expose multiple global "scopes" for scripts. A +single scope is an instance of javax.script.Bindings. +This interface is derived from java.util.Map<String, +Object>. A scope a set of name-value pairs where name is +any non-empty, non-null String. +javax.script.ScriptContext interface supports multiple +scopes with associated Bindings for each +scope. By default, every script engine has a default script +context. The default script context has atleast one scope called +"ENGINE_SCOPE". Various scopes supported by a script context are +available through getScopes method.

    +
    
    +// MultiScopes.java
    +
    +import javax.script.*;
    +
    +public class MultiScopes {
    +    public static void main(String[] args) throws Exception {
    +        ScriptEngineManager manager = new ScriptEngineManager();
    +        ScriptEngine engine = manager.getEngineByName("nashorn");
    +
    +        engine.put("x", "hello");
    +        // print global variable "x"
    +        engine.eval("print(x);");
    +        // the above line prints "hello"
    +
    +        // Now, pass a different script context
    +        ScriptContext newContext = new SimpleScriptContext();
    +        newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
    +        Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE);
    +
    +        // add new variable "x" to the new engineScope        
    +        engineScope.put("x", "world");
    +
    +        // execute the same script - but this time pass a different script context
    +        engine.eval("print(x);", newContext);
    +        // the above line prints "world"
    +    }
    +}
    +
    +
    +
    +
    + +

    JavaScript Script Engine

    +

    Oracle's implementation of JDK 8 is co-bundled with the Nashorn ECMAScript +script engine. +


    + +

    JavaScript to Java Communication

    +

    For the most part, accessing Java classes, objects and methods +is straightforward. In particular field and method access from +JavaScript is the same as it is from Java. We highlight important +aspects of JavaScript Java access here. +The following examples are JavaScript snippets accessing Java. This +section requires knowledge of JavaScript. This section can be +skipped if you are planning to use some other JSR-223 scripting +language rather than JavaScript.

    +
    + +

    Accessing Java Classes

    +
    +
    +// javatypes.js
    +
    + var arrayListType = Java.type("java.util.ArrayList")
    + var intType = Java.type("int")
    + var stringArrayType = Java.type("java.lang.String[]")
    + var int2DArrayType = Java.type("int[][]")
    +
    +
    + +Note that the name of the type is always a string for a fully qualified name. You can use any of these types to create new instances, e.g.: + +
    
    + var anArrayList = new Java.type("java.util.ArrayList")
    +
    + +or + +
    
    + var ArrayList = Java.type("java.util.ArrayList")
    + var anArrayList = new ArrayList
    + var anArrayListWithSize = new ArrayList(16)
    +
    + +In the special case of inner classes, you need to use the JVM fully qualified name, meaning using $ sign in the class name: + +
    
    + var ftype = Java.type("java.awt.geom.Arc2D$Float")
    +
    + + +However, once you retrieved the outer class, you can access the inner class as a property on it: + +
    
    + var arctype = Java.type("java.awt.geom.Arc2D")
    + var ftype = arctype.Float
    +
    +

    +You can access both static and non-static inner classes. If you want to create an instance of a non-static inner class, remember to pass an instance of its outer class as the first argument to the constructor. +

    +
    + +

    Importing Java Packages, Classes

    +

    The built-in functions importPackage (in compatibility script) and +importClass can be used to import Java packages and +classes.

    +
    
    +
    +// importpackageclass.js
    +
    +// load compatibility script
    +load("nashorn:mozilla_compat.js");
    +// Import Java packages and classes 
    +// like import package.*; in Java
    +importPackage(java.awt);
    +// like import java.awt.Frame in Java
    +importClass(java.awt.Frame);
    +// Create Java Objects by "new ClassName"
    +var frame = new java.awt.Frame("hello");
    +// Call Java public methods from script
    +frame.setVisible(true);
    +// Access "JavaBean" properties like "fields"
    +print(frame.title);
    +
    +
    +

    The Packages global variable can +be used to access Java packages. Examples: +Packages.java.util.Vector, +Packages.javax.swing.JFrame. Please note that "java" +is a shortcut for "Packages.java". There are equivalent shortcuts +for javax, org, edu, com, net prefixes, so pratically all JDK +platform classes can be accessed without the "Packages" prefix.

    +

    Note that java.lang is not imported by default (unlike Java) +because that would result in conflicts with JavaScript's built-in +Object, Boolean, Math and so on.

    +

    importPackage and importClass +functions "pollute" the global variable scope of JavaScript. To +avoid that, you may use JavaImporter.

    +
    
    +
    +// javaimporter.js
    +
    +// create JavaImporter with specific packages and classes to import
    +
    +var SwingGui = new JavaImporter(javax.swing,
    +                            javax.swing.event,
    +                            javax.swing.border,
    +                            java.awt.event);
    +with (SwingGui) {
    +    // within this 'with' statement, we can access Swing and AWT
    +    // classes by unqualified (simple) names.
    +
    +    var mybutton = new JButton("test");
    +    var myframe = new JFrame("test");
    +}
    +
    +
    +
    +
    + +

    Creating, Converting and Using Java Arrays

    +

    While creating a Java object is the same as in Java, to create +Java arrays in JavaScript we can use Java reflection +explicitly. But once created the element access or length access is +the same as in Java. Also, a script array can be used when a Java +method expects a Java array (auto conversion). So in most cases we +don't have to create Java arrays explicitly.

    +
    
    +// javaarray.js
    +
    +// create Java String array of 5 elements
    +var a = java.lang.reflect.Array.newInstance(java.lang.String.class, 5);
    +
    +// Accessing elements and length access is by usual Java syntax
    +a[0] = "scripting is great!";
    +print(a.length);
    +print(a[0]);
    +
    +
    +

    +It is also possible to convert between JavaScript and Java arrays. +Given a JavaScript array and a Java type, Java.toJavaArray returns a Java array with the same initial contents, and with the specified component type. +

    +
    
    + var anArray = [1, "13", false]
    + var javaIntArray = Java.toJavaArray(anArray, "int")
    + print(javaIntArray[0]) // prints 1
    + print(javaIntArray[1]) // prints 13, as string "13" was converted to number 13 as per ECMAScript ToNumber conversion
    + print(javaIntArray[2]) // prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion
    +
    +

    +Given a Java array or Collection, Java.toJavaScriptArray returns a JavaScript array with a shallow copy of its contents. Note that in most cases, you can use Java arrays and lists natively in Nashorn; in cases where for some reason you need to have an actual JavaScript native array (e.g. to work with the array comprehensions functions), you will want to use this method.i +

    +
    
    +var File = Java.type("java.io.File");
    +var listCurDir = new File(".").listFiles();
    +var jsList = Java.toJavaScriptArray(listCurDir);
    +print(jsList);
    +
    +
    + +

    Implementing Java Interfaces

    +

    A Java interface can be implemented in JavaScript by using a +Java anonymous class-like syntax:

    +
    
    +// runnable.js
    +
    +var r  = new java.lang.Runnable() {
    +    run: function() {
    +        print("running...\n");
    +    }
    +};
    +
    +// "r" can be passed to Java methods that expect java.lang.Runnable
    +var th = new java.lang.Thread(r);
    +th.start();
    +th.join();
    +
    +
    +

    When an interface with a single method is expected, you can pass +a script function directly.(auto conversion)

    +
    
    +// samfunc.js
    +
    +function func() {
    +     print("I am func!");
    +}
    +
    +// pass script function for java.lang.Runnable argument
    +var th = new java.lang.Thread(func);
    +th.start();
    +th.join();
    +
    +
    +
    + +

    Extending Java classes

    +

    +If a Java class is abstract, you can instantiate an anonymous subclass of it using an argument list that is applicable to any of its public or protected constructors, but inserting a JavaScript object with functions properties that provide JavaScript implementations of the abstract methods. If method names are overloaded, the JavaScript function will provide implementation for all overloads. E.g.: +

    + +
    
    + var TimerTask =  Java.type("java.util.TimerTask")
    + var task = new TimerTask({ run: function() { print("Hello World!") } })
    +
    + +Nashorn supports a syntactic extension where a "new" expression followed by an argument is identical to invoking the constructor and passing the argument to it, so you can write the above example also as: + +
    
    + var task = new TimerTask {
    +     run: function() {
    +       print("Hello World!")
    +     }
    + }
    +
    + +which is very similar to Java anonymous inner class definition. On the other hand, if the type is an abstract type with a single abstract method (commonly referred to as a "SAM type") or all abstract methods it has share the same overloaded name), then instead of an object, you can just pass a function, so the above example can become even more simplified to: + +
    
    + var task = new TimerTask(function() { print("Hello World!") })
    +
    + +

    +Note that in every one of these cases if you are trying to instantiate an abstract class that has constructors that take some arguments, you can invoke those simply by specifying the arguments after the initial implementation object or function. +

    +

    +The use of functions can be taken even further; if you are invoking a Java method that takes a SAM type, you can just pass in a function object, and Nashorn will know what you meant: +

    +
    + Java.type("java.util.Timer")
    + timer.schedule(function() { print("Hello World!") })
    +
    + +Here, Timer.schedule() expects a TimerTask as its argument, so Nashorn creates an instance of a TimerTask subclass and uses the passed function to implement its only abstract method, run(). In this usage though, you can't use non-default constructors; the type must be either an interface, or must have a protected or public no-arg constructor. + +

    +To extend a concrete Java class, you have to use Java.extend function. +Java.extend returns a type object for a subclass of the specified Java class (or implementation of the specified interface) that acts as a script-to-Java adapter for it. +

    +
    
    +// javaextend.js
    +
    +var ArrayList = Java.type("java.util.ArrayList")
    +var ArrayListExtender = Java.extend(ArrayList)
    +var printSizeInvokedArrayList = new ArrayListExtender() {
    +    size: function() { print("size invoked!"); }
    +}
    +var printAddInvokedArrayList = new ArrayListExtender() {
    +    add: function(x, y) {
    +        if(typeof(y) === "undefined") {
    +            print("add(e) invoked!");
    +        } else {
    +            print("add(i, e) invoked!");
    +        }
    +    }
    +};
    +printSizeInvokedArrayList.size();
    +printAddInvokedArrayList.add(33, 33);
    +
    +
    + +

    Overload Resolution

    +

    Java methods can be overloaded by argument types. In Java, +overload resolution occurs at compile time (performed by javac). +When calling Java methods from a script, the script +interpreter/compiler needs to select the appropriate method. With +the JavaScript engine, you do not need to do anything special - the +correct Java method overload variant is selected based on the +argument types. But, sometimes you may want (or have) to explicitly +select a particular overload variant.

    +
    
    +// overload.js
    +
    +var out = java.lang.System.out;
    +
    +// select a particular print function 
    +out["println(java.lang.Object)"]("hello");
    +
    +
    +
    + +

    Implementing Your Own Script Engine

    +

    We will not cover implementation of JSR-223 compliant script +engines in detail. Minimally, you need to implement the +javax.script.ScriptEngine and +javax.script.ScriptEngineFactory interfaces. The +abstract class javax.script.AbstractScriptEngine +provides useful defaults for a few methods of the +ScriptEngine interface.

    +

    Before starting to implement a JSR-223 engine, you may want to +check http://java.net/projects/Scripting +project. This project maintains JSR-223 implementations for many +popular open source scripting languages.

    +
    + +

    References

    + + + + +

    + + + + + + + +
    Oracle and/or its affiliates
    + Java Technology
    +

    +Copyright © 2013, Oracle and/or its affiliates. All rights reserved. +

    +
    +

    Contact Us

    +
    +

    + + + + + + + + + + + + + + + diff --git a/nashorn/docs/source/EvalFile.java b/nashorn/docs/source/EvalFile.java new file mode 100644 index 00000000000..6bb4e38118c --- /dev/null +++ b/nashorn/docs/source/EvalFile.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010, 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. + */ + +import javax.script.*; + +public class EvalFile { + public static void main(String[] args) throws Exception { + // create a script engine manager + ScriptEngineManager factory = new ScriptEngineManager(); + // create JavaScript engine + ScriptEngine engine = factory.getEngineByName("nashorn"); + // evaluate JavaScript code from given file - specified by first argument + engine.eval(new java.io.FileReader(args[0])); + } +} + diff --git a/nashorn/docs/source/EvalScript.java b/nashorn/docs/source/EvalScript.java new file mode 100644 index 00000000000..7fcbe1cd879 --- /dev/null +++ b/nashorn/docs/source/EvalScript.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010, 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. + */ + +import javax.script.*; + +public class EvalScript { + public static void main(String[] args) throws Exception { + // create a script engine manager + ScriptEngineManager factory = new ScriptEngineManager(); + // create a JavaScript engine + ScriptEngine engine = factory.getEngineByName("nashorn"); + // evaluate JavaScript code from String + engine.eval("print('Hello, World')"); + } +} + diff --git a/nashorn/docs/source/InvokeScriptFunction.java b/nashorn/docs/source/InvokeScriptFunction.java new file mode 100644 index 00000000000..26de36c4e94 --- /dev/null +++ b/nashorn/docs/source/InvokeScriptFunction.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2010, 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. + */ + +import javax.script.*; + +public class InvokeScriptFunction { + public static void main(String[] args) throws Exception { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("nashorn"); + + // JavaScript code in a String + String script = "function hello(name) { print('Hello, ' + name); }"; + // evaluate script + engine.eval(script); + + // javax.script.Invocable is an optional interface. + // Check whether your script engine implements or not! + // Note that the JavaScript engine implements Invocable interface. + Invocable inv = (Invocable) engine; + + // invoke the global function named "hello" + inv.invokeFunction("hello", "Scripting!!" ); + } +} + + + diff --git a/nashorn/docs/source/InvokeScriptMethod.java b/nashorn/docs/source/InvokeScriptMethod.java new file mode 100644 index 00000000000..a3f5ece745f --- /dev/null +++ b/nashorn/docs/source/InvokeScriptMethod.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010, 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. + */ + +import javax.script.*; + +public class InvokeScriptMethod { + public static void main(String[] args) throws Exception { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("nashorn"); + + // JavaScript code in a String. This code defines a script object 'obj' + // with one method called 'hello'. + String script = "var obj = new Object(); obj.hello = function(name) { print('Hello, ' + name); }"; + // evaluate script + engine.eval(script); + + // javax.script.Invocable is an optional interface. + // Check whether your script engine implements or not! + // Note that the JavaScript engine implements Invocable interface. + Invocable inv = (Invocable) engine; + + // get script object on which we want to call the method + Object obj = engine.get("obj"); + + // invoke the method named "hello" on the script object "obj" + inv.invokeMethod(obj, "hello", "Script Method !!" ); + } +} diff --git a/nashorn/docs/source/MultiScopes.java b/nashorn/docs/source/MultiScopes.java new file mode 100644 index 00000000000..6c4fa2a27b6 --- /dev/null +++ b/nashorn/docs/source/MultiScopes.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2010, 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. + */ + +import javax.script.*; + +public class MultiScopes { + public static void main(String[] args) throws Exception { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("nashorn"); + + engine.put("x", "hello"); + // print global variable "x" + engine.eval("print(x);"); + // the above line prints "hello" + + // Now, pass a different script context + ScriptContext newContext = new SimpleScriptContext(); + newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); + Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE); + + // add new variable "x" to the new engineScope + engineScope.put("x", "world"); + + // execute the same script - but this time pass a different script context + engine.eval("print(x);", newContext); + // the above line prints "world" + } +} + + diff --git a/nashorn/docs/source/RunnableImpl.java b/nashorn/docs/source/RunnableImpl.java new file mode 100644 index 00000000000..1d858d40cd8 --- /dev/null +++ b/nashorn/docs/source/RunnableImpl.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010, 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. + */ + +import javax.script.*; + +public class RunnableImpl { + public static void main(String[] args) throws Exception { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("nashorn"); + + // JavaScript code in a String + String script = "function run() { print('run called'); }"; + + // evaluate script + engine.eval(script); + + Invocable inv = (Invocable) engine; + + // get Runnable interface object from engine. This interface methods + // are implemented by script functions with the matching name. + Runnable r = inv.getInterface(Runnable.class); + + // start a new thread that runs the script implemented + // runnable interface + Thread th = new Thread(r); + th.start(); + th.join(); + } +} diff --git a/nashorn/docs/source/RunnableImplObject.java b/nashorn/docs/source/RunnableImplObject.java new file mode 100644 index 00000000000..877f8c15e17 --- /dev/null +++ b/nashorn/docs/source/RunnableImplObject.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010, 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. + */ + +import javax.script.*; + +public class RunnableImplObject { + public static void main(String[] args) throws Exception { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("nashorn"); + + // JavaScript code in a String + String script = "var obj = new Object(); obj.run = function() { print('run method called'); }"; + + // evaluate script + engine.eval(script); + + // get script object on which we want to implement the interface with + Object obj = engine.get("obj"); + + Invocable inv = (Invocable) engine; + + // get Runnable interface object from engine. This interface methods + // are implemented by script methods of object 'obj' + Runnable r = inv.getInterface(obj, Runnable.class); + + // start a new thread that runs the script implemented + // runnable interface + Thread th = new Thread(r); + th.start(); + th.join(); + } +} diff --git a/nashorn/docs/source/ScriptVars.java b/nashorn/docs/source/ScriptVars.java new file mode 100644 index 00000000000..7e16cfca09e --- /dev/null +++ b/nashorn/docs/source/ScriptVars.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010, 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. + */ + +import javax.script.*; +import java.io.*; + +public class ScriptVars { + public static void main(String[] args) throws Exception { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("nashorn"); + + File f = new File("test.txt"); + // expose File object as variable to script + engine.put("file", f); + + // evaluate a script string. The script accesses "file" + // variable and calls method on it + engine.eval("print(file.getAbsolutePath())"); + } +} + + + diff --git a/nashorn/docs/source/importpackageclass.js b/nashorn/docs/source/importpackageclass.js new file mode 100644 index 00000000000..afc02a9bf37 --- /dev/null +++ b/nashorn/docs/source/importpackageclass.js @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2010, 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. + */ + +// load compatibility script +load("nashorn:mozilla_compat.js"); + +// Import Java packages and classes +// like import package.*; in Java +importPackage(java.awt); +// like import java.awt.Frame in Java +importClass(java.awt.Frame); +// Create Java Objects by "new ClassName" +var frame = new java.awt.Frame("hello"); +// Call Java public methods from script +frame.setVisible(true); +// Access "JavaBean" properties like "fields" +print(frame.title); diff --git a/nashorn/docs/source/javaarray.js b/nashorn/docs/source/javaarray.js new file mode 100644 index 00000000000..b9d93f0d42c --- /dev/null +++ b/nashorn/docs/source/javaarray.js @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010, 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. + */ + +// create Java String array of 5 elements +var a = java.lang.reflect.Array.newInstance(java.lang.String.class, 5); + +// Accessing elements and length access is by usual Java syntax +a[0] = "scripting is great!"; +print(a.length); +print(a[0]); + +// convert a script array to Java array +var anArray = [1, "13", false]; +var javaIntArray = Java.toJavaArray(anArray, "int"); +print(javaIntArray[0]);// prints 1 +print(javaIntArray[1]); // prints 13, as string "13" was converted to number 13 as per ECMAScript ToNumber conversion +print(javaIntArray[2]);// prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion + +// convert a Java array to a JavaScript array +var File = Java.type("java.io.File"); +var listCurDir = new File(".").listFiles(); +var jsList = Java.toJavaScriptArray(listCurDir); +print(jsList); diff --git a/nashorn/docs/source/javaextend.js b/nashorn/docs/source/javaextend.js new file mode 100644 index 00000000000..408da320a19 --- /dev/null +++ b/nashorn/docs/source/javaextend.js @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2010, 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. + */ + +var ArrayList = Java.type("java.util.ArrayList") +var ArrayListExtender = Java.extend(ArrayList) +var printSizeInvokedArrayList = new ArrayListExtender() { + size: function() { print("size invoked!"); } +} +var printAddInvokedArrayList = new ArrayListExtender() { + add: function(x, y) { + if(typeof(y) === "undefined") { + print("add(e) invoked!"); + } else { + print("add(i, e) invoked!"); + } + } +}; +printSizeInvokedArrayList.size(); +printAddInvokedArrayList.add(33, 33); diff --git a/nashorn/docs/source/javaimporter.js b/nashorn/docs/source/javaimporter.js new file mode 100644 index 00000000000..3bd07988d21 --- /dev/null +++ b/nashorn/docs/source/javaimporter.js @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010, 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. + */ + +// create JavaImporter with specific packages and classes to import + +var SwingGui = new JavaImporter(javax.swing, + javax.swing.event, + javax.swing.border, + java.awt.event); +with (SwingGui) { + // within this 'with' statement, we can access Swing and AWT + // classes by unqualified (simple) names. + + var mybutton = new JButton("test"); + print(mybutton); + var myframe = new JFrame("test"); + print(myframe); +} + + diff --git a/nashorn/docs/source/javatypes.js b/nashorn/docs/source/javatypes.js new file mode 100644 index 00000000000..e0b6f07b137 --- /dev/null +++ b/nashorn/docs/source/javatypes.js @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2010, 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. + */ + + +// accessing java types +var arrayListType = Java.type("java.util.ArrayList") +var intType = Java.type("int") +var stringArrayType = Java.type("java.lang.String[]") +var int2DArrayType = Java.type("int[][]") + +// Using java types +var ArrayList = Java.type("java.util.ArrayList") +var anArrayList = new ArrayList +var anArrayListWithSize = new ArrayList(16) + +// fully qualified name +var ftype = Java.type("java.awt.geom.Arc2D$Float") + +// inner class property +var arctype = Java.type("java.awt.geom.Arc2D") +var ftype = arctype.Float + diff --git a/nashorn/docs/source/overload.js b/nashorn/docs/source/overload.js new file mode 100644 index 00000000000..2407d0c5a5c --- /dev/null +++ b/nashorn/docs/source/overload.js @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2010, 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. + */ + +var out = java.lang.System.out; + +// select a particular print function +out["println(java.lang.Object)"]("hello"); + diff --git a/nashorn/docs/source/runnable.js b/nashorn/docs/source/runnable.js new file mode 100644 index 00000000000..67cd31c67cf --- /dev/null +++ b/nashorn/docs/source/runnable.js @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2010, 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. + */ + +var r = new java.lang.Runnable() { + run: function() { + print("running...\n"); + } +}; + +// "r" can be passed to Java methods that expect java.lang.Runnable +var th = new java.lang.Thread(r); +th.start(); +th.join(); diff --git a/nashorn/docs/source/samfunc.js b/nashorn/docs/source/samfunc.js new file mode 100644 index 00000000000..c870076e1fd --- /dev/null +++ b/nashorn/docs/source/samfunc.js @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2010, 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. + */ + +function func() { + print("I am func!"); +} + +// pass script function for java.lang.Runnable argument +var th = new java.lang.Thread(func); +th.start(); +th.join(); diff --git a/nashorn/docs/source/test.js b/nashorn/docs/source/test.js new file mode 100644 index 00000000000..6323c386479 --- /dev/null +++ b/nashorn/docs/source/test.js @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010, 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. + */ + +print("This is hello from test.js"); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java index 8f9ffd4ae06..2c68a417fd6 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java @@ -351,10 +351,10 @@ public class NativeJava { * var ArrayList = Java.type("java.util.ArrayList") * var ArrayListExtender = Java.extend(ArrayList) * var printSizeInvokedArrayList = new ArrayListExtender() { - * function size() { print("size invoked!"); } + * size: function() { print("size invoked!"); } * } * var printAddInvokedArrayList = new ArrayListExtender() { - * function add(x, y) { + * add: function(x, y) { * if(typeof(y) === "undefined") { * print("add(e) invoked!"); * } else { From be500502ec8445abead21e2b711cb9ebf2824b01 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Tue, 5 Feb 2013 18:44:54 +0530 Subject: [PATCH 113/311] 8007521: $ENV should be undefined when security manager is present Reviewed-by: hannesw, jlaskey --- .../jdk/nashorn/internal/objects/Global.java | 17 ++++- .../internal/runtime/ScriptingFunctions.java | 64 ++++++------------- .../JDK-8006191.js | 0 .../JDK-8006191.js.EXPECTED | 0 nashorn/test/script/sandbox/env.js | 36 +++++++++++ nashorn/test/script/sandbox/exec.js | 39 +++++++++++ 6 files changed, 108 insertions(+), 48 deletions(-) rename nashorn/test/script/{basic => currently-failing}/JDK-8006191.js (100%) rename nashorn/test/script/{basic => currently-failing}/JDK-8006191.js.EXPECTED (100%) create mode 100644 nashorn/test/script/sandbox/env.js create mode 100644 nashorn/test/script/sandbox/exec.js diff --git a/nashorn/src/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk/nashorn/internal/objects/Global.java index 380566e2d14..ed4557c045c 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java @@ -34,6 +34,7 @@ import java.io.PrintWriter; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.ref.SoftReference; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -1464,8 +1465,20 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, value); // Nashorn extension: global.$ENV (scripting-mode-only) - value = ScriptingFunctions.getENVValues(newEmptyInstance(), this.isStrictContext()); - addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, value); + if (System.getSecurityManager() == null) { + // do not fill $ENV if we have a security manager around + // Retrieve current state of ENV variables. + final ScriptObject env = newEmptyInstance(); + env.putAll(System.getenv()); + addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env); + } else { + addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); + } + + // add other special properties for exec support + addOwnProperty(ScriptingFunctions.OUT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); + addOwnProperty(ScriptingFunctions.ERR_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); + addOwnProperty(ScriptingFunctions.EXIT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); } private void initTypedArray() { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java index fe9b97f6985..d3ac11e420a 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java @@ -61,9 +61,9 @@ public class ScriptingFunctions { /** Names of special properties used by $EXEC API. */ public static final String EXEC_NAME = "$EXEC"; - private static final String OUT_NAME = "$OUT"; - private static final String ERR_NAME = "$ERR"; - private static final String EXIT_NAME = "$EXIT"; + public static final String OUT_NAME = "$OUT"; + public static final String ERR_NAME = "$ERR"; + public static final String EXIT_NAME = "$EXIT"; /** Names of special properties used by $ENV API. */ public static final String ENV_NAME = "$ENV"; @@ -139,14 +139,6 @@ public class ScriptingFunctions { // Current global is need to fetch additional inputs and for additional results. final ScriptObject global = Context.getGlobal(); - // Current ENV property state. - final Object env = global.get(ENV_NAME); - // Make sure ENV is a valid script object. - if (!(env instanceof ScriptObject)) { - typeError("env.not.object"); - } - final ScriptObject envProperties = (ScriptObject)env; - // Break exec string into tokens. final StringTokenizer tokenizer = new StringTokenizer(JSType.toString(string)); final String[] cmdArray = new String[tokenizer.countTokens()]; @@ -157,18 +149,23 @@ public class ScriptingFunctions { // Set up initial process. final ProcessBuilder processBuilder = new ProcessBuilder(cmdArray); - // If a working directory is present, use it. - final Object pwd = envProperties.get(PWD_NAME); - if (pwd != UNDEFINED) { - processBuilder.directory(new File(JSType.toString(pwd))); - } + // Current ENV property state. + final Object env = global.get(ENV_NAME); + if (env instanceof ScriptObject) { + final ScriptObject envProperties = (ScriptObject)env; - // Set up ENV variables. - final Map environment = processBuilder.environment(); - environment.clear(); - for (Map.Entry entry : envProperties.entrySet()) { + // If a working directory is present, use it. + final Object pwd = envProperties.get(PWD_NAME); + if (pwd != UNDEFINED) { + processBuilder.directory(new File(JSType.toString(pwd))); + } - environment.put(JSType.toString(entry.getKey()), JSType.toString(entry.getValue())); + // Set up ENV variables. + final Map environment = processBuilder.environment(); + environment.clear(); + for (Map.Entry entry : envProperties.entrySet()) { + environment.put(JSType.toString(entry.getKey()), JSType.toString(entry.getValue())); + } } // Start the process. @@ -214,31 +211,6 @@ public class ScriptingFunctions { return out; } - /** - * Return an object containing properties mapping to ENV variables. - * - * @param envProperties object to receive properties - * @param isStrict global's strict state - * - * @return Script object with properties mapping to ENV variables. - */ - public static ScriptObject getENVValues(final ScriptObject envProperties, final boolean isStrict) { - // Retrieve current state of ENV variables. - Map envVars; - try { - envVars = System.getenv(); - } catch(SecurityException ex) { - envVars = new HashMap<>(); - } - - // Map ENV variables. - for (Map.Entry entry : envVars.entrySet()) { - envProperties.set(entry.getKey(), entry.getValue(), isStrict); - } - - return envProperties; - } - private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { return MH.findStatic(MethodHandles.lookup(), ScriptingFunctions.class, name, MH.type(rtype, types)); } diff --git a/nashorn/test/script/basic/JDK-8006191.js b/nashorn/test/script/currently-failing/JDK-8006191.js similarity index 100% rename from nashorn/test/script/basic/JDK-8006191.js rename to nashorn/test/script/currently-failing/JDK-8006191.js diff --git a/nashorn/test/script/basic/JDK-8006191.js.EXPECTED b/nashorn/test/script/currently-failing/JDK-8006191.js.EXPECTED similarity index 100% rename from nashorn/test/script/basic/JDK-8006191.js.EXPECTED rename to nashorn/test/script/currently-failing/JDK-8006191.js.EXPECTED diff --git a/nashorn/test/script/sandbox/env.js b/nashorn/test/script/sandbox/env.js new file mode 100644 index 00000000000..df80e6fb589 --- /dev/null +++ b/nashorn/test/script/sandbox/env.js @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/** + * Try to get env object + * + * @test + * @security + * @option -scripting + */ + +var env = $ENV; +// should be empty!! +for (i in env) { + print("FAILED: can get: " + i + " = " + env[i]); +} diff --git a/nashorn/test/script/sandbox/exec.js b/nashorn/test/script/sandbox/exec.js new file mode 100644 index 00000000000..86d70b3640c --- /dev/null +++ b/nashorn/test/script/sandbox/exec.js @@ -0,0 +1,39 @@ +/* + * 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. + */ + +/** + * Try to get exec + * + * @test + * @security + * @option -scripting + */ + +try { + var ans = `java -version`; + fail("should have thrown exception!"); +} catch (e) { + if (! (e instanceof java.lang.SecurityException)) { + fail("SecurityException expected, got " + e); + } +} From ac9ca521adb6dd429cefe466b1e48075b7138d73 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Tue, 5 Feb 2013 21:00:04 +0530 Subject: [PATCH 114/311] 8007522: IllegalStateException thrown from String.prototype.search function Reviewed-by: jlaskey --- .../jdk/nashorn/internal/objects/NativeRegExp.java | 2 +- nashorn/test/script/basic/JDK-8007522.js | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 nashorn/test/script/basic/JDK-8007522.js diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java index 487feafaccd..9d5bf104130 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java @@ -675,7 +675,7 @@ public final class NativeRegExp extends ScriptObject { start = matcher.find(start) ? matcher.start() : -1; if (global) { - setLastIndex(matcher.end()); + setLastIndex(start == -1? -1 : matcher.end()); } return start; diff --git a/nashorn/test/script/basic/JDK-8007522.js b/nashorn/test/script/basic/JDK-8007522.js new file mode 100644 index 00000000000..7a52e922c0a --- /dev/null +++ b/nashorn/test/script/basic/JDK-8007522.js @@ -0,0 +1,13 @@ +/** + * JDK-8007522: IllegalStateException thrown from String.prototype.search function + * + * @test + * @run + */ + +var str = "hello"; +// search used to result in IllegalStateException +if (str.search(/foo/g) != -1) { + fail("String.prototype.search failed"); +} + From 292a819b5322e29ea8f0abb4e30cdfc8c5fd83e8 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Tue, 5 Feb 2013 22:07:04 +0530 Subject: [PATCH 115/311] 8007523: VerifyError on script that uses regular expression literals with ternary operator Reviewed-by: lagergren --- .../jdk/nashorn/internal/ir/LiteralNode.java | 5 +++ nashorn/test/script/basic/JDK-8007522.js | 23 ++++++++++++ nashorn/test/script/basic/JDK-8007523.js | 36 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 nashorn/test/script/basic/JDK-8007523.js diff --git a/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java b/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java index 51317acad32..f1bf1b80c64 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java +++ b/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java @@ -493,6 +493,11 @@ public abstract class LiteralNode extends Node implements PropertyKey { return new LexerTokenLiteralNode(this); } + @Override + public Type getType() { + return Type.OBJECT; + } + @Override public void toString(final StringBuilder sb) { sb.append(value.toString()); diff --git a/nashorn/test/script/basic/JDK-8007522.js b/nashorn/test/script/basic/JDK-8007522.js index 7a52e922c0a..855d7d198cc 100644 --- a/nashorn/test/script/basic/JDK-8007522.js +++ b/nashorn/test/script/basic/JDK-8007522.js @@ -1,3 +1,26 @@ +/* + * 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. + */ + /** * JDK-8007522: IllegalStateException thrown from String.prototype.search function * diff --git a/nashorn/test/script/basic/JDK-8007523.js b/nashorn/test/script/basic/JDK-8007523.js new file mode 100644 index 00000000000..2a97ce28683 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8007523.js @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/** + * JDK-8007523: VerifyError on script that uses regular expression literals with ternary operator + * + * @test + * @run + */ + +var flag = true; + +// used to throw VerifyError because of the following ternary operator +if (String(flag? /bar1/ : /bar2/) != '/bar1/') { + fail("ternary operator failed to pass right value"); +} From e84e88f4c9b8375be1764a2d59e2cf2556b3c0a2 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Tue, 5 Feb 2013 22:56:47 -0800 Subject: [PATCH 116/311] 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 4eee363f14aa377a530acdf1cd51ab1e6130c655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 6 Feb 2013 10:31:58 +0100 Subject: [PATCH 117/311] 8007273: Creation of ScriptFunctions can be refactored Reviewed-by: lagergren, attila --- .../objects/FunctionObjectCreator.java | 49 +- .../codegen/objects/ObjectCreator.java | 9 +- .../jdk/nashorn/internal/objects/Global.java | 3 +- .../internal/objects/ScriptFunctionImpl.java | 126 ++--- .../nashorn/internal/runtime/PropertyMap.java | 1 + .../internal/runtime/ScriptFunction.java | 404 ++++------------ .../internal/runtime/ScriptFunctionData.java | 442 ++++++++++++++++++ 7 files changed, 582 insertions(+), 452 deletions(-) create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java diff --git a/nashorn/src/jdk/nashorn/internal/codegen/objects/FunctionObjectCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/objects/FunctionObjectCreator.java index fc916486b1f..72ed43b1710 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/objects/FunctionObjectCreator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/objects/FunctionObjectCreator.java @@ -28,7 +28,6 @@ package jdk.nashorn.internal.codegen.objects; import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.HANDLE_STATIC; import static jdk.nashorn.internal.codegen.Compiler.SCRIPTFUNCTION_IMPL_OBJECT; import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE; -import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE; import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; @@ -40,14 +39,10 @@ import jdk.nashorn.internal.codegen.CodeGenerator; import jdk.nashorn.internal.codegen.FunctionSignature; import jdk.nashorn.internal.codegen.MethodEmitter; import jdk.nashorn.internal.ir.FunctionNode; -import jdk.nashorn.internal.ir.IdentNode; import jdk.nashorn.internal.ir.Symbol; -import jdk.nashorn.internal.parser.Token; -import jdk.nashorn.internal.parser.TokenType; import jdk.nashorn.internal.runtime.PropertyMap; -import jdk.nashorn.internal.runtime.ScriptFunction; +import jdk.nashorn.internal.runtime.ScriptFunctionData; import jdk.nashorn.internal.runtime.ScriptObject; -import jdk.nashorn.internal.runtime.Source; /** * Analyze a function object's characteristics for appropriate code @@ -79,58 +74,28 @@ public class FunctionObjectCreator extends ObjectCreator { */ @Override public void makeObject(final MethodEmitter method) { - makeMap(); - final IdentNode identNode = functionNode.getIdent(); - final String signature = new FunctionSignature(true, functionNode.needsCallee(), functionNode.getReturnType(), functionNode.isVarArg() ? null : functionNode.getParameters()).toString(); - final long firstToken = functionNode.getFirstToken(); - final long lastToken = functionNode.getLastToken(); - final int position = Token.descPosition(firstToken); - final int length = Token.descPosition(lastToken) - position + Token.descLength(lastToken); - final long token = Token.toDesc(TokenType.FUNCTION, position, length); + final PropertyMap map = makeMap(); + final String signature = new FunctionSignature(true, functionNode.needsCallee(), functionNode.getReturnType(), functionNode.isVarArg() ? null : functionNode.getParameters()).toString(); + final ScriptFunctionData scriptFunctionData = new ScriptFunctionData(functionNode, map); /* - * Instantiate the function object, must be referred to by name as - * class is not available at compile time + * Instantiate the function object */ method._new(SCRIPTFUNCTION_IMPL_OBJECT).dup(); - method.load(functionNode.isAnonymous() ? "" : identNode.getName()); + codegen.loadConstant(scriptFunctionData); loadHandle(method, signature); if(functionNode.needsParentScope()) { method.loadScope(); } else { method.loadNull(); } - method.getStatic(compileUnit.getUnitClassName(), SOURCE.tag(), SOURCE.descriptor()); - method.load(token); method.loadHandle(getClassName(), ALLOCATE.tag(), methodDescriptor(ScriptObject.class, PropertyMap.class), EnumSet.of(HANDLE_STATIC)); - /* - * Emit code for the correct property map for the object - */ - loadMap(method); - /* * Invoke the constructor */ - method.load(functionNode.needsCallee()); - method.load(functionNode.isStrictMode()); - method.invoke(constructorNoLookup(SCRIPTFUNCTION_IMPL_OBJECT, - String.class, - MethodHandle.class, - ScriptObject.class, - Source.class, - long.class, - MethodHandle.class, - PropertyMap.class, - boolean.class, - boolean.class)); + method.invoke(constructorNoLookup(SCRIPTFUNCTION_IMPL_OBJECT, ScriptFunctionData.class, MethodHandle.class, ScriptObject.class, MethodHandle.class)); - - if (functionNode.isVarArg()) { - method.dup(); - method.load(functionNode.getParameters().size()); - method.invoke(ScriptFunction.SET_ARITY); - } } } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectCreator.java index 6a6e9dc1649..1b02aa06d2f 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectCreator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectCreator.java @@ -127,14 +127,15 @@ public abstract class ObjectCreator { /** * Construct the property map appropriate for the object. + * @return the newly created property map */ - protected void makeMap() { + protected PropertyMap makeMap() { if (keys.isEmpty()) { //empty map propertyMap = PropertyMap.newMap(fieldObjectClass); - return; + } else { + propertyMap = newMapCreator(fieldObjectClass).makeMap(isVarArg()); } - - propertyMap = newMapCreator(fieldObjectClass).makeMap(isVarArg()); + return propertyMap; } /** diff --git a/nashorn/src/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk/nashorn/internal/objects/Global.java index ed4557c045c..c71ba27266a 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java @@ -34,7 +34,6 @@ import java.io.PrintWriter; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.ref.SoftReference; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -394,7 +393,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { @Override public ScriptFunction newScriptFunction(final String name, final MethodHandle handle, final ScriptObject scope, final boolean strict) { - return new ScriptFunctionImpl(name, handle, scope, strict, null); + return new ScriptFunctionImpl(name, handle, scope, null, strict, false); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java index 94490a27d9a..a3a6b33fd52 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java +++ b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java @@ -30,6 +30,8 @@ import static jdk.nashorn.internal.runtime.linker.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; + +import jdk.nashorn.internal.runtime.ScriptFunctionData; import jdk.nashorn.internal.codegen.objects.FunctionObjectCreator; import jdk.nashorn.internal.runtime.GlobalFunctions; import jdk.nashorn.internal.runtime.Property; @@ -37,7 +39,6 @@ import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; -import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.linker.Lookup; import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; @@ -46,109 +47,68 @@ import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; * function objects -- to expose properties like "prototype", "length" etc. */ public class ScriptFunctionImpl extends ScriptFunction { - // per-function object flags - private static final int IS_STRICT = 0b0000_0001; - private static final int IS_BUILTIN = 0b0000_0010; - private static final int HAS_CALLEE = 0b0000_0100; - - // set this function to be a builtin function - private void setIsBuiltin() { - flags |= IS_BUILTIN; - } - - // set this function to be a ECMAScript strict function - private void setIsStrict() { - flags |= IS_STRICT; - } private static final MethodHandle BOUND_FUNCTION = findOwnMH("boundFunction", Object.class, ScriptFunction.class, Object.class, Object[].class, Object.class, Object[].class); private static final MethodHandle BOUND_CONSTRUCTOR = findOwnMH("boundConstructor", Object.class, ScriptFunction.class, Object[].class, Object.class, Object[].class); private static final PropertyMap nasgenmap$; - private int flags; - /** - * Constructor - * - * Called by Nasgen generated code, no membercount, use the default map - * Creates builtin functions only + * Constructor called by Nasgen generated code, no membercount, use the default map. + * Creates builtin functions only. * * @param name name of function * @param invokeHandle handle for invocation * @param specs specialized versions of this method, if available, null otherwise */ ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final MethodHandle[] specs) { - this(name, invokeHandle, nasgenmap$, specs); + super(name, invokeHandle, nasgenmap$, null, specs, false, true); + init(); } /** - * Constructor - * - * Called by Nasgen generated code, no membercount, use the default map - * Creates builtin functions only + * Constructor called by Nasgen generated code, no membercount, use the map passed as argument. + * Creates builtin functions only. * * @param name name of function - * @param methodHandle handle for invocation + * @param invokeHandle handle for invocation * @param map initial property map * @param specs specialized versions of this method, if available, null otherwise */ - ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final PropertyMap map, final MethodHandle[] specs) { - super(name, methodHandle, (nasgenmap$ == map) ? nasgenmap$ : map.addAll(nasgenmap$), null, null, 0, false, specs); - this.setIsBuiltin(); + ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final MethodHandle[] specs) { + super(name, invokeHandle, map.addAll(nasgenmap$), null, specs, false, true); init(); } /** - * Constructor - * - * Called by Global.newScriptFunction (runtime) + * Constructor called by Global.newScriptFunction (runtime). * * @param name name of function * @param methodHandle handle for invocation * @param scope scope object - * @param strict are we in strict mode * @param specs specialized versions of this method, if available, null otherwise + * @param strict are we in strict mode + * @param builtin is this a built-in function */ - ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final boolean strict, final MethodHandle[] specs) { - super(name, methodHandle, getMap(strict), scope, specs); - if (strict) { - this.setIsStrict(); - } + ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean strict, final boolean builtin) { + super(name, methodHandle, getMap(strict), scope, specs, strict, builtin); init(); } /** - * Constructor + * Constructor called by (compiler) generated code for {@link ScriptObject}s. + * Code is generated by {@link FunctionObjectCreator} * - * Called by (compiler) generated code for {@link ScriptObject}s. Code is - * generated by {@link FunctionObjectCreator} - * - * TODO this is a horrible constructor - can we do it with fewer args? - * - * @param name name of function + * @param data static function data * @param methodHandle handle for invocation * @param scope scope object - * @param source source - * @param token token * @param allocator instance constructor for function - * @param allocatorMap initial map that constructor will keep reference to for future instantiations - * @param needCallee does the function use the {@code callee} variable - * @param strict are we in strict mode */ - public ScriptFunctionImpl( - final String name, - final MethodHandle methodHandle, - final ScriptObject scope, - final Source source, - final long token, - final MethodHandle allocator, - final PropertyMap allocatorMap, - final boolean needCallee, - final boolean strict) { - super(name, methodHandle, getMap(strict), scope, source, token, allocator, allocatorMap, needCallee, null); - if (strict) { - this.setIsStrict(); + public ScriptFunctionImpl(final ScriptFunctionData data, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle allocator) { + super(data, getMap(data.isStrict()), scope); + // Set method handles in script data + if (data.getInvoker() == null) { + data.setMethodHandles(methodHandle, allocator); } init(); } @@ -167,11 +127,11 @@ public class ScriptFunctionImpl extends ScriptFunction { static synchronized ScriptFunction getTypeErrorThrower() { if (typeErrorThrower == null) { //name handle - final ScriptFunctionImpl func = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_SETTER, null, false, null); + final ScriptFunctionImpl func = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_SETTER, null, null, false, false); // clear constructor handle... - func.constructHandle = null; - func.prototype = UNDEFINED; - typeErrorThrower = func; + func.setConstructHandle(null); + func.setPrototype(UNDEFINED); + typeErrorThrower = func; } return typeErrorThrower; @@ -216,28 +176,8 @@ public class ScriptFunctionImpl extends ScriptFunction { return new AnonymousFunction(); } - @Override - public final boolean isStrict() { - return (flags & IS_STRICT) != 0; - } - - @Override - public final boolean hasCalleeParameter() { - return (flags & HAS_CALLEE) != 0; - } - - @Override - protected void setHasCalleeParameter() { - flags |= HAS_CALLEE; - } - - @Override - public final boolean isBuiltin() { - return (flags & IS_BUILTIN) != 0; - } - /** - * Factory method for non-constructor functions + * Factory method for non-constructor built-in functions * * @param name function name * @param methodHandle handle for invocation @@ -246,9 +186,7 @@ public class ScriptFunctionImpl extends ScriptFunction { * @return new ScriptFunction */ public static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict) { - final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, strict, specs); - - func.setIsBuiltin(); + final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, strict, true); func.setConstructHandle(null); func.setPrototype(UNDEFINED); @@ -256,7 +194,7 @@ public class ScriptFunctionImpl extends ScriptFunction { } /** - * Factory method for non-constructor functions + * Factory method for non-constructor built-in functions * * @param name function name * @param methodHandle handle for invocation @@ -268,7 +206,7 @@ public class ScriptFunctionImpl extends ScriptFunction { } /** - * Factory method for non-constructor functions + * Factory method for non-constructor built-in functions * * @param name function name * @param methodHandle handle for invocation diff --git a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java index 399e2e94b61..0864b1c40c4 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java @@ -383,6 +383,7 @@ public final class PropertyMap implements Iterable, PropertyListener { * @return New {@link PropertyMap} with added properties. */ public PropertyMap addAll(final PropertyMap other) { + assert this != other : "adding property map to itself"; final Property[] otherProperties = other.properties.getProperties(); final PropertyHashMap newProperties = properties.immutableAdd(otherProperties); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java index c0b89be9e7e..2fbe3ee0cf5 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java @@ -37,7 +37,6 @@ import jdk.nashorn.internal.codegen.CompilerConstants.Call; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.objects.annotations.SpecializedConstructor; import jdk.nashorn.internal.objects.annotations.SpecializedFunction; -import jdk.nashorn.internal.parser.Token; import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; import jdk.nashorn.internal.runtime.linker.NashornGuards; @@ -70,144 +69,53 @@ public abstract class ScriptFunction extends ScriptObject { private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", Object.class, Object.class); - /** method handle to arity setter for this ScriptFunction */ - public static final Call SET_ARITY = virtualCallNoLookup(ScriptFunction.class, "setArity", void.class, int.class); /** method handle to scope getter for this ScriptFunction */ public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class); /** Should specialized function and specialized constructors for the builtin be used if available? */ private static final boolean DISABLE_SPECIALIZATION = Options.getBooleanProperty("nashorn.scriptfunction.specialization.disable"); - /** Name of function or null. */ - private final String name; - - /** Source of function. */ - private final Source source; - - /** Start position and length in source. */ - private final long token; - - /** Reference to code for this method. */ - private final MethodHandle invokeHandle; - - /** Reference to code for this method when called to create "new" object */ - protected MethodHandle constructHandle; + private final ScriptFunctionData data; /** Reference to constructor prototype. */ protected Object prototype; - /** Constructor to create a new instance. */ - private MethodHandle allocator; - - /** Map for new instance constructor. */ - private PropertyMap allocatorMap; - /** The parent scope. */ private final ScriptObject scope; - /** Specializations - see @SpecializedFunction */ - private MethodHandle[] invokeSpecializations; + /** + * Constructor + * + * @param name function name + * @param methodHandle method handle to function (if specializations are present, assumed to be most generic) + * @param map property map + * @param scope scope + * @param specs specialized version of this function - other method handles + * + */ + protected ScriptFunction( + final String name, + final MethodHandle methodHandle, + final PropertyMap map, + final ScriptObject scope, + final MethodHandle[] specs, + final boolean strict, + final boolean builtin) { - /** Specializations - see @SpecializedFunction */ - private MethodHandle[] constructSpecializations; - - /** This field is either computed in constructor or set explicitly by calling setArity method. */ - private int arity; + this (new ScriptFunctionData(name, methodHandle, specs, strict, builtin), map, scope); + } /** * Constructor * - * @param name function name - * @param methodHandle method handle to function (if specializations are present, assumed to be most generic) + * @param data static function data * @param map property map * @param scope scope - * @param specs specialized version of this function - other method handles */ protected ScriptFunction( - final String name, - final MethodHandle methodHandle, + final ScriptFunctionData data, final PropertyMap map, - final ScriptObject scope, - final MethodHandle[] specs) { - this(name, methodHandle, map, scope, null, 0, needsCallee(methodHandle), specs); - } - - /** - * Heuristic to figure out if the method handle has a callee argument. If it's type is either - * {@code (boolean, Object, ScriptFunction, ...)} or {@code (Object, ScriptFunction, ...)}, then we'll assume it has - * a callee argument. We need this as the constructor above is not passed this information, and can't just blindly - * assume it's false (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore - * they also always receive a callee. - * @param methodHandle the examined method handle - * @return true if the method handle expects a callee, false otherwise - */ - private static boolean needsCallee(MethodHandle methodHandle) { - final MethodType type = methodHandle.type(); - final int len = type.parameterCount(); - if(len == 0) { - return false; - } - if(type.parameterType(0) == boolean.class) { - return len > 2 && type.parameterType(2) == ScriptFunction.class; - } - return len > 1 && type.parameterType(1) == ScriptFunction.class; - } - - /** - * Constructor - * - * @param name function name - * @param methodHandle method handle to function (if specializations are present, assumed to be most generic) - * @param map property map - * @param scope scope - * @param source the source - * @param token token - * @param allocator method handle to this function's allocator - see JO$ classes - * @param allocatorMap property map to be used for all constructors - * @param needsCallee does this method use the {@code callee} variable - * @param specs specialized version of this function - other method handles - */ - protected ScriptFunction( - final String name, - final MethodHandle methodHandle, - final PropertyMap map, - final ScriptObject scope, - final Source source, - final long token, - final MethodHandle allocator, - final PropertyMap allocatorMap, - final boolean needsCallee, - final MethodHandle[] specs) { - - this(name, methodHandle, map, scope, source, token, needsCallee, specs); - - //this is the internal constructor - - this.allocator = allocator; - this.allocatorMap = allocatorMap; - } - - /** - * Constructor - * - * @param name function name - * @param methodHandle method handle to function (if specializations are present, assumed to be most generic) - * @param map property map - * @param scope scope - * @param source the source - * @param token token - * @param needsCallee does this method use the {@code callee} variable - * @param specs specialized version of this function - other method handles - */ - protected ScriptFunction( - final String name, - final MethodHandle methodHandle, - final PropertyMap map, - final ScriptObject scope, - final Source source, - final long token, - final boolean needsCallee, - final MethodHandle[] specs) { + final ScriptObject scope) { super(map); @@ -215,89 +123,8 @@ public abstract class ScriptFunction extends ScriptObject { constructorCount++; } - this.name = name; - this.source = source; - this.token = token; + this.data = data; this.scope = scope; - if(needsCallee) { - setHasCalleeParameter(); - } - - final MethodType type = methodHandle.type(); - final int paramCount = type.parameterCount(); - final boolean isVarArg = type.parameterType(paramCount - 1).isArray(); - - final MethodHandle mh = MH.asType(methodHandle, adaptType(type, needsCallee, isVarArg)); - - this.arity = isVarArg ? -1 : paramCount - 1; //drop the self param for arity - - if (needsCallee && !isVarArg) { - this.arity--; - } - - if (scope != null) { - this.invokeHandle = mh; - this.constructHandle = mh; - } else if (isConstructor(mh)) { - if (!isVarArg) { - this.arity--; // drop the boolean flag for arity - } - /* - * We insert a boolean argument to tell if the method was invoked as - * constructor or not if the method handle's first argument is boolean. - */ - this.invokeHandle = MH.insertArguments(mh, 0, false); - this.constructHandle = MH.insertArguments(mh, 0, true); - - if (specs != null) { - this.invokeSpecializations = new MethodHandle[specs.length]; - this.constructSpecializations = new MethodHandle[specs.length]; - for (int i = 0; i < specs.length; i++) { - this.invokeSpecializations[i] = MH.insertArguments(specs[i], 0, false); - this.constructSpecializations[i] = MH.insertArguments(specs[i], 0, true); - } - } - } else { - this.invokeHandle = mh; - this.constructHandle = mh; - this.invokeSpecializations = specs; - this.constructSpecializations = specs; - } - } - - /** - * Takes a method type, and returns a (potentially different method type) that the method handles used by - * ScriptFunction must conform to in order to be usable in {@link #invoke(Object, Object...)} and - * {@link #construct(Object, Object...)}. The returned method type will be sure to return {@code Object}, and will - * have all its parameters turned into {@code Object} as well, except for the following ones: - *
      - *
    • an optional first {@code boolean} parameter, used for some functions to distinguish method and constructor - * invocation,
    • - *
    • a last parameter of type {@code Object[]} which is used for vararg functions,
    • - *
    • the second (or, in presence of boolean parameter, third) argument, which is forced to be - * {@link ScriptFunction}, in case the function receives itself (callee) as an argument
    • - * @param type the original type - * @param hasCallee true if the function uses the callee argument - * @param isVarArg if the function is a vararg - * @return the new type, conforming to the rules above. - */ - private static MethodType adaptType(final MethodType type, final boolean hasCallee, final boolean isVarArg) { - // Generify broadly - MethodType newType = type.generic().changeReturnType(Object.class); - if(isVarArg) { - // Change back to vararg if we over-generified it - newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class); - } - final boolean hasBoolean = type.parameterType(0) == boolean.class; - if(hasBoolean) { - // Restore the initial boolean argument - newType = newType.changeParameterType(0, boolean.class); - } - if(hasCallee) { - // Restore the ScriptFunction argument - newType = newType.changeParameterType(hasBoolean ? 2 : 1, ScriptFunction.class); - } - return newType; } @Override @@ -329,7 +156,7 @@ public abstract class ScriptFunction extends ScriptObject { * @return arity */ public final int getArity() { - return arity; + return data.getArity(); } /** @@ -337,27 +164,32 @@ public abstract class ScriptFunction extends ScriptObject { * @param arity arity */ public final void setArity(final int arity) { - this.arity = arity; + data.setArity(arity); } /** * Is this a ECMAScript 'use strict' function? * @return true if function is in strict mode */ - public abstract boolean isStrict(); + public boolean isStrict() { + return data.isStrict(); + } /** * Is this a ECMAScript built-in function (like parseInt, Array.isArray) ? * @return true if built-in */ - public abstract boolean isBuiltin(); + public boolean isBuiltin() { + return data.isBuiltin(); + } /** - * Is this a non-strict and not-built-in script function? - * @return true if neither strict nor built-in + * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument + * according to ECMA 10.4.3. + * @return true if this argument must be an object */ - public boolean isNonStrictFunction() { - return !isStrict() && !isBuiltin(); + public boolean needsWrappedThis() { + return data.needsWrappedThis(); } /** @@ -372,43 +204,44 @@ public abstract class ScriptFunction extends ScriptObject { invokes++; } + final MethodHandle invoker = data.getGenericInvoker(); final Object selfObj = convertThisObject(self); final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; - if (isVarArg(invokeHandle)) { - if (hasCalleeParameter()) { - return invokeHandle.invokeExact(selfObj, this, args); + if (data.isVarArg()) { + if (data.needsCallee()) { + return invoker.invokeExact(selfObj, this, args); } - return invokeHandle.invokeExact(selfObj, args); + return invoker.invokeExact(selfObj, args); } - final int paramCount = invokeHandle.type().parameterCount(); - if (hasCalleeParameter()) { + final int paramCount = invoker.type().parameterCount(); + if (data.needsCallee()) { switch (paramCount) { case 2: - return invokeHandle.invokeExact(selfObj, this); + return invoker.invokeExact(selfObj, this); case 3: - return invokeHandle.invokeExact(selfObj, this, getArg(args, 0)); + return invoker.invokeExact(selfObj, this, getArg(args, 0)); case 4: - return invokeHandle.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1)); + return invoker.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1)); case 5: - return invokeHandle.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + return invoker.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1), getArg(args, 2)); default: - return invokeHandle.invokeWithArguments(withArguments(selfObj, this, paramCount, args)); + return invoker.invokeWithArguments(withArguments(selfObj, this, paramCount, args)); } } switch (paramCount) { case 1: - return invokeHandle.invokeExact(selfObj); + return invoker.invokeExact(selfObj); case 2: - return invokeHandle.invokeExact(selfObj, getArg(args, 0)); + return invoker.invokeExact(selfObj, getArg(args, 0)); case 3: - return invokeHandle.invokeExact(selfObj, getArg(args, 0), getArg(args, 1)); + return invoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1)); case 4: - return invokeHandle.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + return invoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); default: - return invokeHandle.invokeWithArguments(withArguments(selfObj, null, paramCount, args)); + return invoker.invokeWithArguments(withArguments(selfObj, null, paramCount, args)); } } @@ -424,44 +257,45 @@ public abstract class ScriptFunction extends ScriptObject { * @throws Throwable if there is an exception/error with the constructor invocation or thrown from it */ public Object construct(final Object self, final Object... args) throws Throwable { - if (constructHandle == null) { + if (data.getConstructor() == null) { typeError("not.a.constructor", ScriptRuntime.safeToString(this)); } - if (isVarArg(constructHandle)) { - if (hasCalleeParameter()) { - return constructHandle.invokeExact(self, this, args); + final MethodHandle constructor = data.getGenericConstructor(); + if (data.isVarArg()) { + if (data.needsCallee()) { + return constructor.invokeExact(self, this, args); } - return constructHandle.invokeExact(self, args); + return constructor.invokeExact(self, args); } - final int paramCount = constructHandle.type().parameterCount(); - if (hasCalleeParameter()) { + final int paramCount = constructor.type().parameterCount(); + if (data.needsCallee()) { switch (paramCount) { case 2: - return constructHandle.invokeExact(self, this); + return constructor.invokeExact(self, this); case 3: - return constructHandle.invokeExact(self, this, getArg(args, 0)); + return constructor.invokeExact(self, this, getArg(args, 0)); case 4: - return constructHandle.invokeExact(self, this, getArg(args, 0), getArg(args, 1)); + return constructor.invokeExact(self, this, getArg(args, 0), getArg(args, 1)); case 5: - return constructHandle.invokeExact(self, this, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + return constructor.invokeExact(self, this, getArg(args, 0), getArg(args, 1), getArg(args, 2)); default: - return constructHandle.invokeWithArguments(withArguments(self, this, args)); + return constructor.invokeWithArguments(withArguments(self, this, args)); } } switch(paramCount) { case 1: - return constructHandle.invokeExact(self); + return constructor.invokeExact(self); case 2: - return constructHandle.invokeExact(self, getArg(args, 0)); + return constructor.invokeExact(self, getArg(args, 0)); case 3: - return constructHandle.invokeExact(self, getArg(args, 0), getArg(args, 1)); + return constructor.invokeExact(self, getArg(args, 0), getArg(args, 1)); case 4: - return constructHandle.invokeExact(self, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + return constructor.invokeExact(self, getArg(args, 0), getArg(args, 1), getArg(args, 2)); default: - return constructHandle.invokeWithArguments(withArguments(self, null, args)); + return constructor.invokeWithArguments(withArguments(self, null, args)); } } @@ -509,9 +343,9 @@ public abstract class ScriptFunction extends ScriptObject { ScriptObject object = null; - if (allocator != null) { + if (data.getAllocator() != null) { try { - object = (ScriptObject)allocator.invokeExact(allocatorMap); + object = (ScriptObject)data.getAllocator().invokeExact(data.getAllocatorMap()); } catch (final RuntimeException | Error e) { throw e; } catch (final Throwable t) { @@ -546,25 +380,6 @@ public abstract class ScriptFunction extends ScriptObject { */ public abstract ScriptFunction makeBoundFunction(Object self, Object[] args); - /** - * Test if a methodHandle refers to a constructor. - * @param methodHandle MethodHandle to test. - * @return True if method is a constructor. - */ - private static boolean isConstructor(final MethodHandle methodHandle) { - return methodHandle.type().parameterCount() >= 1 && methodHandle.type().parameterType(0) == boolean.class; - } - - /** - * Test if a methodHandle refers to a variable argument method. - * @param methodHandle MethodHandle to test. - * @return True if variable arguments. - */ - public boolean isVarArg(final MethodHandle methodHandle) { - return hasCalleeParameter() - ? methodHandle.type().parameterCount() == 3 && methodHandle.type().parameterType(2).isArray() - : methodHandle.type().parameterCount() == 2 && methodHandle.type().parameterType(1).isArray(); - } @Override public final String safeToString() { @@ -573,23 +388,7 @@ public abstract class ScriptFunction extends ScriptObject { @Override public String toString() { - final StringBuilder sb = new StringBuilder(); - - sb.append(super.toString()) - .append(" [ ") - .append(invokeHandle) - .append(", ") - .append((name == null || name.isEmpty()) ? "" : name); - - if (source != null) { - sb.append(" @ ") - .append(source.getName()) - .append(':') - .append(source.getLine(Token.descPosition(token))); - } - sb.append(" ]"); - - return sb.toString(); + return data.toString(); } /** @@ -598,11 +397,7 @@ public abstract class ScriptFunction extends ScriptObject { * @return string representation of this function's source */ public final String toSource() { - if (source != null && token != 0) { - return source.getString(Token.descPosition(token), Token.descLength(token)); - } - - return "function " + (name == null ? "" : name) + "() { [native code] }"; + return data.toSource(); } /** @@ -696,7 +491,7 @@ public abstract class ScriptFunction extends ScriptObject { * @return invoke method handle */ public final MethodHandle getBestSpecializedInvokeHandle(final MethodType type) { - return candidateWithLowestWeight(type, getInvokeHandle(), invokeSpecializations); + return candidateWithLowestWeight(type, getInvokeHandle(), data.getInvokeSpecializations()); } /** @@ -706,7 +501,7 @@ public abstract class ScriptFunction extends ScriptObject { * @return invokeHandle */ public final MethodHandle getInvokeHandle() { - return invokeHandle; + return data.getInvoker(); } /** @@ -718,19 +513,9 @@ public abstract class ScriptFunction extends ScriptObject { */ public final MethodHandle getBoundInvokeHandle(final ScriptObject self) { final MethodHandle bound = MH.bindTo(getInvokeHandle(), self); - return hasCalleeParameter() ? MH.bindTo(bound, this) : bound; + return data.needsCallee() ? MH.bindTo(bound, this) : bound; } - /** - * Check whether the ScriptFunction has callee parameter - * @return true if callee parameter - */ - protected abstract boolean hasCalleeParameter(); - - /** - * Flag ScriptFunction as needing a callee parameter - */ - protected abstract void setHasCalleeParameter(); /** * Get the construct handle - the most generic (and if no specializations are in place, only) constructor @@ -740,7 +525,7 @@ public abstract class ScriptFunction extends ScriptObject { * @return construct handle */ public final MethodHandle getConstructHandle(final MethodType type) { - return candidateWithLowestWeight(type, getConstructHandle(), constructSpecializations); + return candidateWithLowestWeight(type, getConstructHandle(), data.getConstructSpecializations()); } /** @@ -748,7 +533,7 @@ public abstract class ScriptFunction extends ScriptObject { * @return constructor handle */ public final MethodHandle getConstructHandle() { - return constructHandle; + return data.getConstructor(); } /** @@ -756,8 +541,7 @@ public abstract class ScriptFunction extends ScriptObject { * @param constructHandle constructor handle */ public final void setConstructHandle(final MethodHandle constructHandle) { - this.constructHandle = constructHandle; - this.constructSpecializations = null; + data.setConstructor(constructHandle); } /** @@ -765,7 +549,7 @@ public abstract class ScriptFunction extends ScriptObject { * @return the name */ public final String getName() { - return name; + return data.getName(); } /** @@ -775,7 +559,7 @@ public abstract class ScriptFunction extends ScriptObject { * @return true if this needs compilation */ public final boolean needsCompilation() { - return invokeHandle == null; + return data.getInvoker() == null; } /** @@ -783,7 +567,7 @@ public abstract class ScriptFunction extends ScriptObject { * @return token */ public final long getToken() { - return token; + return data.getToken(); } /** @@ -907,7 +691,7 @@ public abstract class ScriptFunction extends ScriptObject { final Class[] ctorArgs = ctorType.dropParameterTypes(0, 1).parameterArray(); // drop self MethodHandle handle = MH.foldArguments(MH.dropArguments(NEWFILTER, 2, ctorArgs), constructor); - if (hasCalleeParameter()) { + if (data.needsCallee()) { handle = MH.foldArguments(handle, ALLOCATE); } else { handle = MH.filterArguments(handle, 0, ALLOCATE); @@ -958,12 +742,12 @@ public abstract class ScriptFunction extends ScriptObject { MethodHandle boundHandle; MethodHandle guard = null; - if (hasCalleeParameter()) { + if (data.needsCallee()) { final MethodHandle callHandle = getBestSpecializedInvokeHandle(type); if(NashornCallSiteDescriptor.isScope(desc)) { // (this, callee, args...) => (callee, args...) => (callee, [this], args...) - boundHandle = MH.bindTo(callHandle, isNonStrictFunction() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED); + boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED); boundHandle = MH.dropArguments(boundHandle, 1, Object.class); } else { // (this, callee, args...) permute => (callee, this, args...) which is what we get in @@ -980,7 +764,7 @@ public abstract class ScriptFunction extends ScriptObject { // For non-strict functions, check whether this-object is primitive type. // If so add a to-object-wrapper argument filter. // Else install a guard that will trigger a relink when the argument becomes primitive. - if (isNonStrictFunction()) { + if (needsWrappedThis()) { if (isPrimitiveThis(request.getArguments()[1])) { boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER); } else { @@ -992,7 +776,7 @@ public abstract class ScriptFunction extends ScriptObject { final MethodHandle callHandle = getBestSpecializedInvokeHandle(type.dropParameterTypes(0, 1)); if(NashornCallSiteDescriptor.isScope(desc)) { - boundHandle = MH.bindTo(callHandle, isNonStrictFunction() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED); + boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED); boundHandle = MH.dropArguments(boundHandle, 0, Object.class, Object.class); } else { boundHandle = MH.dropArguments(callHandle, 0, Object.class); @@ -1012,13 +796,13 @@ public abstract class ScriptFunction extends ScriptObject { MethodHandle methodHandle = getBestSpecializedInvokeHandle(type); if (bindName != null) { - if (hasCalleeParameter()) { + if (data.needsCallee()) { methodHandle = MH.insertArguments(methodHandle, 1, this, bindName); } else { methodHandle = MH.insertArguments(methodHandle, 1, bindName); } } else { - if (hasCalleeParameter()) { + if (data.needsCallee()) { methodHandle = MH.insertArguments(methodHandle, 1, this); } } @@ -1034,7 +818,7 @@ public abstract class ScriptFunction extends ScriptObject { * @return the converted this object */ protected Object convertThisObject(final Object thiz) { - if (!(thiz instanceof ScriptObject) && isNonStrictFunction()) { + if (!(thiz instanceof ScriptObject) && needsWrappedThis()) { if (JSType.nullOrUndefined(thiz)) { return Context.getGlobalTrusted(); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java new file mode 100644 index 00000000000..65dbd6375b5 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java @@ -0,0 +1,442 @@ +/* + * 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 jdk.nashorn.internal.runtime; + +import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.parser.Token; +import jdk.nashorn.internal.parser.TokenType; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; + +import static jdk.nashorn.internal.runtime.linker.Lookup.MH; + +/** + * A container for data needed to instantiate a specific {@link ScriptFunction} at runtime. + * Instances of this class are created during codegen and stored in script classes' + * constants array to reduce function instantiation overhead during runtime. + */ +public class ScriptFunctionData { + + // per-function object flags + private static final int IS_STRICT = 0b0000_0001; + private static final int IS_BUILTIN = 0b0000_0010; + private static final int HAS_CALLEE = 0b0000_0100; + private static final int IS_VARARGS = 0b0000_1000; + + /** Name of the function or "" */ + private final String name; + /** Source of this function, or null */ + private final Source source; + /** Map for new instance constructor */ + private PropertyMap allocatorMap; + /** Start position and length in source */ + private final long token; + /** Number of expected arguments, either taken from FunctionNode or calculated from method handle signature*/ + private int arity; + /** Does this function need a callee argument? */ + private final int flags; + + /** Reference to code for this method. */ + private MethodHandle invoker; + /** Reference to code for this method when called to create "new" object */ + private MethodHandle constructor; + /** Constructor to create a new instance. */ + private MethodHandle allocator; + /** Generic invoker to used in {@link ScriptFunction#invoke(Object, Object...)}. */ + private MethodHandle genericInvoker; + /** Generic constructor used in {@link ScriptFunction#construct(Object, Object...)}. */ + private MethodHandle genericConstructor; + /** Specializations - see @SpecializedFunction */ + private MethodHandle[] invokeSpecializations; + /** Specializations - see @SpecializedFunction */ + private MethodHandle[] constructSpecializations; + + /** + * Constructor + * @param fn the function node + * @param allocatorMap the allocator property map + */ + public ScriptFunctionData(final FunctionNode fn, final PropertyMap allocatorMap) { + + final long firstToken = fn.getFirstToken(); + final long lastToken = fn.getLastToken(); + final int position = Token.descPosition(firstToken); + final int length = Token.descPosition(lastToken) - position + Token.descLength(lastToken); + + this.name = fn.isAnonymous() ? "" : fn.getIdent().getName(); + this.source = fn.getSource(); + this.allocatorMap = allocatorMap; + this.token = Token.toDesc(TokenType.FUNCTION, position, length); + this.arity = fn.getParameters().size(); + this.flags = makeFlags(fn.needsCallee(), fn.isVarArg(), fn.isStrictMode(), false); + } + + /** + * Constructor + * @param name the function name + * @param methodHandle the method handle + * @param specs array of specialized method handles + * @param strict strict flag + * @param builtin builtin flag + */ + public ScriptFunctionData(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict, final boolean builtin) { + this.name = name; + this.source = null; + this.token = 0; + + final MethodType type = methodHandle.type(); + final int paramCount = type.parameterCount(); + final boolean isVarArg = type.parameterType(paramCount - 1).isArray(); + final boolean needsCallee = needsCallee(methodHandle); + + this.flags = makeFlags(needsCallee, isVarArg, strict, builtin); + this.arity = isVarArg ? -1 : paramCount - 1; //drop the self param for arity + + if (needsCallee && !isVarArg) { + this.arity--; + } + + if (isConstructor(methodHandle)) { + if (!isVarArg) { + this.arity--; // drop the boolean flag for arity + } + /* + * We insert a boolean argument to tell if the method was invoked as + * constructor or not if the method handle's first argument is boolean. + */ + this.invoker = MH.insertArguments(methodHandle, 0, false); + this.constructor = MH.insertArguments(methodHandle, 0, true); + + if (specs != null) { + this.invokeSpecializations = new MethodHandle[specs.length]; + this.constructSpecializations = new MethodHandle[specs.length]; + for (int i = 0; i < specs.length; i++) { + this.invokeSpecializations[i] = MH.insertArguments(specs[i], 0, false); + this.constructSpecializations[i] = MH.insertArguments(specs[i], 0, true); + } + } + } else { + this.invoker = methodHandle; + this.constructor = methodHandle; + this.invokeSpecializations = specs; + this.constructSpecializations = specs; + } + } + + /** + * Get the arity of the function. + * @return the arity + */ + public int getArity() { + return arity; + } + + /** + * Set the arity of the function. + * @param arity the arity + */ + public void setArity(int arity) { + this.arity = arity; + } + + /** + * Get the function name. + * @return function name + */ + public String getName() { + return name; + } + + /** + * Get the source of the function. + * @return the source + */ + public Source getSource() { + return source; + } + + /** + * Get this function as a String containing its source code. If no source code + * exists in this ScriptFunction, its contents will be displayed as {@code [native code]} + * @return string representation of this function's source + */ + public String toSource() { + if (source != null && token != 0) { + return source.getString(Token.descPosition(token), Token.descLength(token)); + } + + return "function " + (name == null ? "" : name) + "() { [native code] }"; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + + sb.append(super.toString()) + .append(" [ ") + .append(invoker) + .append(", ") + .append((name == null || name.isEmpty()) ? "" : name); + + if (source != null) { + sb.append(" @ ") + .append(source.getName()) + .append(':') + .append(source.getLine(Token.descPosition(token))); + } + sb.append(" ]"); + + return sb.toString(); + } + + /** + * Get the allocator property map. + * @return the allocator map + */ + public PropertyMap getAllocatorMap() { + return allocatorMap; + } + + /** + * Get the function's parse token. + * @return the token + */ + public long getToken() { + return token; + } + + /** + * Returns true if the function needs a callee argument. + * @return the needsCallee flag + */ + public boolean needsCallee() { + return (flags & HAS_CALLEE) != 0; + } + + /** + * Returns true if this is a strict-mode function. + * @return the strict flag + */ + public boolean isStrict() { + return (flags & IS_STRICT) != 0; + } + + /** + * Returns true if this is a built-in function. + * @return the built-in flag + */ + public boolean isBuiltin() { + return (flags & IS_BUILTIN) != 0; + } + + /** + * Returns true if this is a var-arg function. + * @return the var-arg flag + */ + public boolean isVarArg() { + return (flags & IS_VARARGS) != 0; + } + + /** + * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument + * according to ECMA 10.4.3. + * @return true if this argument must be an object + */ + public boolean needsWrappedThis() { + return (flags & (IS_STRICT | IS_BUILTIN)) == 0; + } + + /** + * Get the method handle used to invoke this function. + * @return the invoke handle + */ + public MethodHandle getInvoker() { + return invoker; + } + + /** + * Get the method handle used to invoke this function as a constructor. + * @return the constructor handle + */ + public MethodHandle getConstructor() { + return constructor; + } + + /** + * Set the constructor method handle. + * @param constructor the constructor handle + */ + public void setConstructor(MethodHandle constructor) { + this.constructor = constructor; + this.constructSpecializations = null; + } + + /** + * Get the method handle used to allocate a new object for this constructor. + * @return the allocator handle + */ + public MethodHandle getAllocator() { + return allocator; + } + + /** + * Get an adapted version of the invoker handle that only uses {@code Object} as parameter and return types. + * @return the generic invoke handle + */ + public MethodHandle getGenericInvoker() { + if (genericInvoker == null) { + assert invoker != null : "invoker is null"; + genericInvoker = adaptMethodType(invoker); + } + return genericInvoker; + } + + /** + * Get an adapted version of the constructor handle that only uses {@code Object} as parameter and return types. + * @return the generic constructor handle + */ + public MethodHandle getGenericConstructor() { + if (genericConstructor == null) { + assert constructor != null : "constructor is null"; + genericConstructor = adaptMethodType(constructor); + } + return genericConstructor; + } + + /** + * Get the specialized invoke handles for this function. + * @return array of specialized invoke handles + */ + public MethodHandle[] getInvokeSpecializations() { + return invokeSpecializations; + } + + /** + * Get the specialized construct handles for this function. + * @return array of specialized construct handles + */ + public MethodHandle[] getConstructSpecializations() { + return constructSpecializations; + } + + /** + * Set the method handles for this function. + * @param invoker the invoker handle + * @param allocator the allocator handle + */ + public void setMethodHandles(MethodHandle invoker, MethodHandle allocator) { + // We can't make method handle fields final because they're not available during codegen + // and they're set when first called, so we enforce set-once here. + if (this.invoker == null) { + this.invoker = invoker; + this.constructor = invoker; + this.allocator = allocator; + } + } + + /** + * Convert boolean flags to int. + * @param needsCallee needs-callee flag + * @param isVarArg var-arg flag + * @param isStrict strict flag + * @param isBuiltin builtin flag + * @return int flags + */ + private static int makeFlags(final boolean needsCallee, final boolean isVarArg, final boolean isStrict, final boolean isBuiltin) { + int flags = 0; + if (needsCallee) { + flags |= HAS_CALLEE; + } + if (isVarArg) { + flags |= IS_VARARGS; + } + if (isStrict) { + flags |= IS_STRICT; + } + if (isBuiltin) { + flags |= IS_BUILTIN; + } + return flags; + } + + /** + * Test if a methodHandle refers to a constructor. + * @param methodHandle MethodHandle to test. + * @return True if method is a constructor. + */ + private static boolean isConstructor(final MethodHandle methodHandle) { + return methodHandle.type().parameterCount() >= 1 && methodHandle.type().parameterType(0) == boolean.class; + } + + /** + * Heuristic to figure out if the method handle has a callee argument. If it's type is either + * {@code (boolean, Object, ScriptFunction, ...)} or {@code (Object, ScriptFunction, ...)}, then we'll assume it has + * a callee argument. We need this as the constructor above is not passed this information, and can't just blindly + * assume it's false (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore + * they also always receive a callee. + * @param methodHandle the examined method handle + * @return true if the method handle expects a callee, false otherwise + */ + private static boolean needsCallee(MethodHandle methodHandle) { + final MethodType type = methodHandle.type(); + final int len = type.parameterCount(); + if(len == 0) { + return false; + } + if(type.parameterType(0) == boolean.class) { + return len > 2 && type.parameterType(2) == ScriptFunction.class; + } + return len > 1 && type.parameterType(1) == ScriptFunction.class; + } + + /** + * Takes a method handle, and returns a potentially different method handle that can be used in + * {@link ScriptFunction#invoke(Object, Object...)} or {@link ScriptFunction#construct(Object, Object...)}. + * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into + * {@code Object} as well, except for the following ones: + *
        + *
      • a last parameter of type {@code Object[]} which is used for vararg functions,
      • + *
      • the second argument, which is forced to be {@link ScriptFunction}, in case the function receives itself + * (callee) as an argument
      • + *
      + * + * @param handle the original method handle + * @return the new handle, conforming to the rules above. + */ + private MethodHandle adaptMethodType(final MethodHandle handle) { + final MethodType type = handle.type(); + MethodType newType = type.generic(); + if (isVarArg()) { + newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class); + } + if (needsCallee()) { + newType = newType.changeParameterType(1, ScriptFunction.class); + } + return type.equals(newType) ? handle : handle.asType(newType); + } + +} From c95d492268e3007dd2ddce69348f0097aefa5797 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Wed, 6 Feb 2013 17:56:12 +0530 Subject: [PATCH 118/311] 8007619: Add support for deprecated properties of RegExp constructor Reviewed-by: lagergren, hannesw --- .../jdk/nashorn/internal/objects/Global.java | 7 ++ .../internal/objects/NativeRegExp.java | 110 +++++++++++++++--- .../internal/runtime/ScriptObject.java | 4 +- nashorn/test/script/basic/JDK-8007619.js | 49 ++++++++ .../test/script/basic/JDK-8007619.js.EXPECTED | 14 +++ 5 files changed, 167 insertions(+), 17 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8007619.js create mode 100644 nashorn/test/script/basic/JDK-8007619.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk/nashorn/internal/objects/Global.java index c71ba27266a..cf640b865cb 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java @@ -1351,6 +1351,13 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { final ScriptObject regExpProto = getRegExpPrototype(); regExpProto.addBoundProperties(DEFAULT_REGEXP); + // add hook to support "deprecated" "static" properties of RegExp constructor object + final ScriptFunction handler = ScriptFunctionImpl.makeFunction(NO_SUCH_METHOD_NAME, NativeRegExp.REGEXP_STATICS_HANDLER); + builtinRegExp.addOwnProperty(NO_SUCH_PROPERTY_NAME, Attribute.NOT_ENUMERABLE, handler); + + // add initial undefined "last successful match" property RegExp + builtinRegExp.addOwnProperty(NativeRegExp.LAST_REGEXP_MATCH, Attribute.NOT_ENUMERABLE, UNDEFINED); + // Error stuff initErrorObjects(); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java index 9d5bf104130..e44b929819c 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java @@ -27,7 +27,10 @@ package jdk.nashorn.internal.objects; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; +import static jdk.nashorn.internal.runtime.linker.Lookup.MH; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -54,6 +57,8 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; */ @ScriptClass("RegExp") public final class NativeRegExp extends ScriptObject { + static final MethodHandle REGEXP_STATICS_HANDLER = findOwnMH("regExpStaticsHandler", Object.class, Object.class, Object.class); + /** ECMA 15.10.7.5 lastIndex property */ @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) public Object lastIndex; @@ -75,6 +80,9 @@ public final class NativeRegExp extends ScriptObject { private BitVector groupsInNegativeLookahead; + // RegExp constructor object. Needed to support RegExp "static" properties, + private Object constructor; + /* public NativeRegExp() { init(); @@ -420,10 +428,81 @@ public final class NativeRegExp extends ScriptObject { final RegExpMatch m = execInner(string); // the input string if (m == null) { - return null; + return setLastRegExpMatch(null); } - return new NativeRegExpExecResult(m); + return setLastRegExpMatch(new NativeRegExpExecResult(m)); + } + + // Name of the "last successful match" property of the RegExp constructor + static final String LAST_REGEXP_MATCH = "__last_regexp_match__"; + + /** + * Handles "static" properties of RegExp constructor. These are "deprecated" + * properties of RegExp constructor. + * + * @param self self object passed to this method + * @param name name of the property being searched + * + * @return value of the specified property or undefined if not found + */ + public static Object regExpStaticsHandler(final Object self, final Object name) { + final String propName = JSType.toString(name); + if (self instanceof ScriptObject) { + final ScriptObject sobj = (ScriptObject)self; + final Object value = sobj.get(LAST_REGEXP_MATCH); + if (! (value instanceof NativeRegExpExecResult)) { + return UNDEFINED; + } + + // get the last match object + final NativeRegExpExecResult lastMatch = (NativeRegExpExecResult)value; + + // look for $1... $9 + if (propName.length() > 0 && propName.charAt(0) == '$') { + int index = 0; + try { + index = Integer.parseInt(propName.substring(1)); + } catch (final Exception ignored) { + return UNDEFINED; + } + + // index out of range + if (index < 1 && index > 9) { + return UNDEFINED; + } + + // retrieve indexed value from last match object. + return lastMatch.get(index); + } + + // misc. "static" properties supported + switch (propName) { + case "input": { + return lastMatch.input; + } + + case "lastMatch": { + return lastMatch.get(0); + } + + case "lastParen": { + final int len = ((Number)NativeRegExpExecResult.length(lastMatch)).intValue(); + return (len > 0)? lastMatch.get(len - 1) : UNDEFINED; + } + } + } + + return UNDEFINED; + } + + // Support for RegExp static properties. We set last successful match + // to the RegExp constructor object. + private Object setLastRegExpMatch(final Object match) { + if (constructor instanceof ScriptObject) { + ((ScriptObject)constructor).set(LAST_REGEXP_MATCH, match, isStrictContext()); + } + return match; } /** @@ -665,20 +744,15 @@ public final class NativeRegExp extends ScriptObject { * @return Index of match. */ Object search(final String string) { - final Matcher matcher = pattern.matcher(string); - - int start = 0; - if (global) { - start = getLastIndex(); + final RegExpMatch m = execInner(string); + // the input string + if (m == null) { + setLastRegExpMatch(null); + return -1; } - start = matcher.find(start) ? matcher.start() : -1; - - if (global) { - setLastIndex(start == -1? -1 : matcher.end()); - } - - return start; + setLastRegExpMatch(new NativeRegExpExecResult(m)); + return m.getIndex(); } /** @@ -706,7 +780,10 @@ public final class NativeRegExp extends ScriptObject { } private void init() { - this.setProto(Global.instance().getRegExpPrototype()); + final ScriptObject proto = Global.instance().getRegExpPrototype(); + this.setProto(proto); + // retrieve constructor to support "static" properties of RegExp + this.constructor = PrototypeObject.getConstructor(proto); } private static NativeRegExp checkRegExp(final Object self) { @@ -769,4 +846,7 @@ public final class NativeRegExp extends ScriptObject { this.groupsInNegativeLookahead = groupsInNegativeLookahead; } + private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { + return MH.findStatic(MethodHandles.publicLookup(), NativeRegExp.class, name, MH.type(rtype, types)); + } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java index 8c1076285f6..07106d84179 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -89,10 +89,10 @@ import org.dynalang.dynalink.support.CallSiteDescriptorFactory; public abstract class ScriptObject extends PropertyListenerManager implements PropertyAccess { /** Search fall back routine name for "no such method" */ - static final String NO_SUCH_METHOD_NAME = "__noSuchMethod__"; + public static final String NO_SUCH_METHOD_NAME = "__noSuchMethod__"; /** Search fall back routine name for "no such property" */ - static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__"; + public static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__"; /** Per ScriptObject flag - is this a scope object? */ public static final int IS_SCOPE = 0b0000_0001; diff --git a/nashorn/test/script/basic/JDK-8007619.js b/nashorn/test/script/basic/JDK-8007619.js new file mode 100644 index 00000000000..2c91f9cf661 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8007619.js @@ -0,0 +1,49 @@ +/* + * 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. + */ + +/** + * JDK-8007619: Add support for deprecated properties of RegExp constructor + * + * @test + * @run + */ + + +var emailPattern = /(\w+)@(\w+)\.(\w+)/g; +var input= "Please send mail to foo@acme.com and bar@gov.in ASAP!"; + +var match = emailPattern.exec(input); + +while (match != null) { + print("Match = " + match); + print("RegExp.lastMatch = " + RegExp.lastMatch); + + print("RegExp.$1 = " + RegExp.$1); + print("RegExp.$2 = " + RegExp.$2); + print("RegExp.$3 = " + RegExp.$3); + + print("RegExp.lastParen = " + RegExp.lastParen) + print("RegExp.input = " + RegExp.input); + + match = emailPattern.exec(input); +} diff --git a/nashorn/test/script/basic/JDK-8007619.js.EXPECTED b/nashorn/test/script/basic/JDK-8007619.js.EXPECTED new file mode 100644 index 00000000000..a440f1df4d0 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8007619.js.EXPECTED @@ -0,0 +1,14 @@ +Match = foo@acme.com,foo,acme,com +RegExp.lastMatch = foo@acme.com +RegExp.$1 = foo +RegExp.$2 = acme +RegExp.$3 = com +RegExp.lastParen = com +RegExp.input = Please send mail to foo@acme.com and bar@gov.in ASAP! +Match = bar@gov.in,bar,gov,in +RegExp.lastMatch = bar@gov.in +RegExp.$1 = bar +RegExp.$2 = gov +RegExp.$3 = in +RegExp.lastParen = in +RegExp.input = Please send mail to foo@acme.com and bar@gov.in ASAP! From 5900e641b044eaca0f1f8f613156763b95484dd2 Mon Sep 17 00:00:00 2001 From: James Laskey Date: Wed, 6 Feb 2013 08:42:19 -0400 Subject: [PATCH 119/311] 8007545: jjs input evalinput need to be NOT_ENUMERABLE Reviewed-by: sundar, lagergren --- .../src/jdk/nashorn/tools/resources/shell.js | 96 ++++++++++++------- 1 file changed, 61 insertions(+), 35 deletions(-) diff --git a/nashorn/src/jdk/nashorn/tools/resources/shell.js b/nashorn/src/jdk/nashorn/tools/resources/shell.js index bb78c72a112..87c40fd5c22 100644 --- a/nashorn/src/jdk/nashorn/tools/resources/shell.js +++ b/nashorn/src/jdk/nashorn/tools/resources/shell.js @@ -1,21 +1,21 @@ /* * 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. @@ -27,46 +27,72 @@ /** * Reads zero or more lines from standard input and returns concatenated string - * + * * @param endMarker marker string that signals end of input * @param prompt prompt printed for each line */ -function input(endMarker, prompt) { - if (!endMarker) { - endMarker = ""; - } - - if (!prompt) { - prompt = " >> "; - } - - var imports = new JavaImporter(java.io, java.lang); - var str = ""; - with (imports) { - var reader = new BufferedReader(new InputStreamReader(System['in'])); - var line; - while (true) { - System.out.print(prompt); - line = reader.readLine(); - if (line == null || line == endMarker) { - break; - } - str += line + "\n"; +Object.defineProperty(this, "input", { + value: function input(endMarker, prompt) { + if (!endMarker) { + endMarker = ""; } - } - - return str; -} + + if (!prompt) { + prompt = " >> "; + } + + var imports = new JavaImporter(java.io, java.lang); + var str = ""; + with (imports) { + var reader = new BufferedReader(new InputStreamReader(System['in'])); + var line; + while (true) { + System.out.print(prompt); + line = reader.readLine(); + if (line == null || line == endMarker) { + break; + } + str += line + "\n"; + } + } + + return str; + }, + enumerable: false, + writable: true, + configurable: true +}); + /** * Reads zero or more lines from standard input and evaluates the concatenated * string as code - * + * * @param endMarker marker string that signals end of input * @param prompt prompt printed for each line */ -function evalinput(endMarker, prompt) { - var code = input(endMarker, prompt); - // make sure everything is evaluated in global scope! - return this.eval(code); +Object.defineProperty(this, "evalinput", { + value: function evalinput(endMarker, prompt) { + var code = input(endMarker, prompt); + // make sure everything is evaluated in global scope! + return this.eval(code); + }, + enumerable: false, + writable: true, + configurable: true +}); + + +/** + * Elegantly exits the current session + */ +if (!quit) { +Object.defineProperty(this, "quit", { + value: function quit() { + java.lang.System.exit(0); + }, + enumerable: false, + writable: true, + configurable: true +}); } From 574016d0d3e85183261df1092de07628e339c4d6 Mon Sep 17 00:00:00 2001 From: James Laskey Date: Wed, 6 Feb 2013 11:57:51 -0400 Subject: [PATCH 120/311] 8007629: Remove extraneous quit from shell.js Reviewed-by: sundar, hannesw --- .../nashorn/api/scripting/resources/init.js | 23 +--------------- .../jdk/nashorn/internal/objects/Global.java | 27 ++++++++++++++++--- .../internal/runtime/ScriptingFunctions.java | 18 +------------ .../src/jdk/nashorn/tools/resources/shell.js | 15 ----------- 4 files changed, 26 insertions(+), 57 deletions(-) diff --git a/nashorn/src/jdk/nashorn/api/scripting/resources/init.js b/nashorn/src/jdk/nashorn/api/scripting/resources/init.js index 26a81e9c62b..18cde929451 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/resources/init.js +++ b/nashorn/src/jdk/nashorn/api/scripting/resources/init.js @@ -119,7 +119,7 @@ function jmap(map) { }, toString: function() { return map.toString(); - } + } }); } @@ -705,27 +705,6 @@ function exec(cmd) { $exit = process.exitValue(); } -/** - * Exit the shell program. - * - * @param exitCode integer code returned to OS shell. - * optional, defaults to 0 - */ -function exit(code) { - if (code) { - java.lang.System.exit(code + 0); - } else { - java.lang.System.exit(0); - } -} - -/** - * synonym for exit - */ -function quit(code) { - exit(code); -} - // XML utilities /** diff --git a/nashorn/src/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk/nashorn/internal/objects/Global.java index cf640b865cb..aa7361a7625 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java @@ -115,6 +115,14 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { @Property(attributes = Attribute.NOT_ENUMERABLE) public Object load; + /** Nashorn extension: global.exit */ + @Property(attributes = Attribute.NOT_ENUMERABLE) + public Object exit; + + /** Nashorn extension: global.quit */ + @Property(attributes = Attribute.NOT_ENUMERABLE) + public Object quit; + /** Value property NaN of the Global Object - ECMA 15.1.1.1 NaN */ @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT) public final Object NaN = Double.NaN; @@ -333,6 +341,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { private static final MethodHandle PRINT = findOwnMH("print", Object.class, Object.class, Object[].class); private static final MethodHandle PRINTLN = findOwnMH("println", Object.class, Object.class, Object[].class); private static final MethodHandle LOAD = findOwnMH("load", Object.class, Object.class, Object.class); + private static final MethodHandle EXIT = findOwnMH("exit", Object.class, Object.class, Object.class); /** * Constructor @@ -688,6 +697,19 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { return global.getContext().load(scope, source); } + /** + * Global exit and quit implementation - Nashorn extension: perform a {@code System.exit} call from the script + * + * @param self self reference + * @param code exit code + * + * @return undefined (will never be reacheD) + */ + public static Object exit(final Object self, final Object code) { + System.exit(JSType.toInt32(code)); + return UNDEFINED; + } + ScriptObject getFunctionPrototype() { return ScriptFunction.getPrototype(builtinFunction); } @@ -1320,6 +1342,8 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { this.unescape = ScriptFunctionImpl.makeFunction("unescape", GlobalFunctions.UNESCAPE); this.print = ScriptFunctionImpl.makeFunction("print", getContext()._print_no_newline ? PRINT : PRINTLN); this.load = ScriptFunctionImpl.makeFunction("load", LOAD); + this.exit = ScriptFunctionImpl.makeFunction("exit", EXIT); + this.quit = ScriptFunctionImpl.makeFunction("quit", EXIT); // built-in constructors this.builtinArray = (ScriptFunction)initConstructor("Array"); @@ -1454,9 +1478,6 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { value = ScriptFunctionImpl.makeFunction("readFully", ScriptingFunctions.READFULLY); addOwnProperty("readFully", Attribute.NOT_ENUMERABLE, value); - value = ScriptFunctionImpl.makeFunction("quit", ScriptingFunctions.QUIT); - addOwnProperty("quit", Attribute.NOT_ENUMERABLE, value); - final String execName = ScriptingFunctions.EXEC_NAME; value = ScriptFunctionImpl.makeFunction(execName, ScriptingFunctions.EXEC); addOwnProperty(execName, Attribute.NOT_ENUMERABLE, value); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java index d3ac11e420a..71011395b46 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java @@ -53,10 +53,7 @@ public class ScriptingFunctions { /** Handle to implementation of {@link ScriptingFunctions#readFully} - Nashorn extension */ public static final MethodHandle READFULLY = findOwnMH("readFully", Object.class, Object.class, Object.class); - /** Handle to implementation of {@link ScriptingFunctions#quit} - Nashorn extension */ - public static final MethodHandle QUIT = findOwnMH("quit", Object.class, Object.class, Object.class); - - /** Handle to implementation of {@link ScriptingFunctions#quit} - Nashorn extension */ + /** Handle to implementation of {@link ScriptingFunctions#exec} - Nashorn extension */ public static final MethodHandle EXEC = findOwnMH("exec", Object.class, Object.class, Object.class, Object.class); /** Names of special properties used by $EXEC API. */ @@ -114,19 +111,6 @@ public class ScriptingFunctions { return new String(Source.readFully(f)); } - /** - * Nashorn extension: perform a {@code System.exit} call from the script - * - * @param self self reference - * @param code exit code - * - * @return undefined (will never be reacheD) - */ - public static Object quit(final Object self, final Object code) { - System.exit(JSType.toInt32(code)); - return UNDEFINED; - } - /** * Nashorn extension: exec a string in a separate process. * diff --git a/nashorn/src/jdk/nashorn/tools/resources/shell.js b/nashorn/src/jdk/nashorn/tools/resources/shell.js index 87c40fd5c22..fdfde7ad78a 100644 --- a/nashorn/src/jdk/nashorn/tools/resources/shell.js +++ b/nashorn/src/jdk/nashorn/tools/resources/shell.js @@ -81,18 +81,3 @@ Object.defineProperty(this, "evalinput", { writable: true, configurable: true }); - - -/** - * Elegantly exits the current session - */ -if (!quit) { -Object.defineProperty(this, "quit", { - value: function quit() { - java.lang.System.exit(0); - }, - enumerable: false, - writable: true, - configurable: true -}); -} From 57ef7ce075b598cc416cb7e2274e8353aa971c06 Mon Sep 17 00:00:00 2001 From: James Laskey Date: Wed, 6 Feb 2013 12:51:09 -0400 Subject: [PATCH 121/311] 8007643: Add testing for quit and exit Reviewed-by: sundar --- nashorn/test/script/sandbox/exit.js | 16 +++++++++++++++- nashorn/test/script/sandbox/exit.js.EXPECTED | 2 ++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/nashorn/test/script/sandbox/exit.js b/nashorn/test/script/sandbox/exit.js index d7737f53b4f..d77744fe7a8 100644 --- a/nashorn/test/script/sandbox/exit.js +++ b/nashorn/test/script/sandbox/exit.js @@ -22,7 +22,7 @@ */ /** - * Try to call System.exit. + * Try to call System.exit, quit and exit. * * @test * @security @@ -43,4 +43,18 @@ try { check(e); } +try { + quit(); + // will not reach here regardless of outcome.. +} catch (e) { + check(e); +} + +try { + exit(0); + // will not reach here regardless of outcome.. +} catch (e) { + check(e); +} + print("Success, didn't exit!"); diff --git a/nashorn/test/script/sandbox/exit.js.EXPECTED b/nashorn/test/script/sandbox/exit.js.EXPECTED index ef927afcfd4..c1411eb89d7 100644 --- a/nashorn/test/script/sandbox/exit.js.EXPECTED +++ b/nashorn/test/script/sandbox/exit.js.EXPECTED @@ -1,2 +1,4 @@ java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "exitVM.0") +java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "exitVM.0") +java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "exitVM.0") Success, didn't exit! From b247ddfcc390dc47c954c0cfb1bb062c0dfdcff7 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Thu, 7 Feb 2013 17:17:29 +0530 Subject: [PATCH 122/311] 8007715: Make sure that not all tests run with AllPermission Reviewed-by: lagergren, attila --- nashorn/make/build.xml | 36 +++++--- nashorn/make/project.properties | 11 ++- .../jdk/nashorn/internal/runtime/Context.java | 28 ++++-- .../runtime/linker/JavaAdapterFactory.java | 4 +- nashorn/test/script/README | 26 ++++++ nashorn/test/script/basic/NASHORN-758.js | 12 +-- nashorn/test/script/basic/javaexceptions.js | 2 +- nashorn/test/script/basic/newexpr.js | 2 +- nashorn/test/script/sandbox/interfaceimpl.js | 63 ++++++++++++++ nashorn/test/script/sandbox/loadcompat.js | 50 +++++++++++ .../script/{basic => trusted}/JDK-8006424.js | 0 .../script/{basic => trusted}/JDK-8006529.js | 0 .../script/{basic => trusted}/NASHORN-638.js | 0 .../NASHORN-638.js.EXPECTED | 0 .../script/{basic => trusted}/NASHORN-653.js | 0 nashorn/test/script/trusted/README | 4 + .../test/script/{basic => trusted}/getenv.js | 0 .../{basic => trusted}/getenv.js.EXPECTED | 0 .../api/scripting/ScriptEngineTest.java | 74 ---------------- .../nashorn/internal/runtime/ContextTest.java | 86 +++++++++++++++++++ 20 files changed, 294 insertions(+), 104 deletions(-) create mode 100644 nashorn/test/script/README create mode 100644 nashorn/test/script/sandbox/interfaceimpl.js create mode 100644 nashorn/test/script/sandbox/loadcompat.js rename nashorn/test/script/{basic => trusted}/JDK-8006424.js (100%) rename nashorn/test/script/{basic => trusted}/JDK-8006529.js (100%) rename nashorn/test/script/{basic => trusted}/NASHORN-638.js (100%) rename nashorn/test/script/{basic => trusted}/NASHORN-638.js.EXPECTED (100%) rename nashorn/test/script/{basic => trusted}/NASHORN-653.js (100%) create mode 100644 nashorn/test/script/trusted/README rename nashorn/test/script/{basic => trusted}/getenv.js (100%) rename nashorn/test/script/{basic => trusted}/getenv.js.EXPECTED (100%) diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml index 8ef6b50e551..04766c17387 100644 --- a/nashorn/make/build.xml +++ b/nashorn/make/build.xml @@ -198,25 +198,40 @@ debug="${javac.debug}" encoding="${javac.encoding}" includeantruntime="false"/> + + + + + + + + + + + - + + + - + - - + + + - + + @@ -225,14 +240,11 @@ - + + - - - - - - + + diff --git a/nashorn/make/project.properties b/nashorn/make/project.properties index 682cdb686a5..70107f4caed 100644 --- a/nashorn/make/project.properties +++ b/nashorn/make/project.properties @@ -53,6 +53,10 @@ parallel.test.runner=jdk.nashorn.internal.test.framework.ParallelTestRunner # test classes directory build.test.classes.dir=${build.dir}/test/classes +# nashorn test jar - internal tests jar and api tests jar +nashorn.internal.tests.jar=${build.dir}/nashorn-internal-tests.jar +nashorn.api.tests.jar=${build.dir}/nashorn-api-tests.jar + # test results directory build.test.results.dir=${build.dir}/test/reports @@ -116,12 +120,13 @@ test.script.dir=test/script test.basic.dir=test/script/basic test.error.dir=test/script/error test.sandbox.dir=test/script/sandbox +test.trusted.dir=test/script/trusted test.external.dir=test/script/external test262.dir=${test.external.dir}/test262 test262.suite.dir=${test262.dir}/test/suite test-sys-prop.test.dir=${test.dir} -test-sys-prop.test.js.roots=${test.basic.dir} ${test.error.dir} ${test.sandbox.dir} +test-sys-prop.test.js.roots=${test.basic.dir} ${test.error.dir} ${test.sandbox.dir} ${test.trusted.dir} test-sys-prop.test262.suite.dir=${test262.suite.dir} test-sys-prop.es5conform.testcases.dir=${test.external.dir}/ES5Conform/TestCases test-sys-prop.test.basic.dir=${test.basic.dir} @@ -205,7 +210,9 @@ test262-test-sys-prop.test.js.framework=\ run.test.classpath=\ ${file.reference.testng.jar}:\ - ${build.test.classes.dir} + ${nashorn.internal.tests.jar}:\ + ${nashorn.api.tests.jar} + src.dir=src test.src.dir=test/src diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index c7137fd3050..6e04247b18d 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -607,24 +607,38 @@ public final class Context { if (src instanceof String) { srcName = (String)src; final File file = new File((String)src); - if (file.isFile()) { - url = file.toURI().toURL(); - } else if (srcName.indexOf(':') != -1) { + if (srcName.indexOf(':') != -1) { try { url = new URL((String)src); } catch (final MalformedURLException e) { // fallback URL - nashorn:foo.js - check under jdk/nashorn/internal/runtime/resources - String str = (String)src; + final String str = (String)src; if (str.startsWith("nashorn:")) { - str = "resources/" + str.substring("nashorn:".length()); - url = Context.class.getResource(str); - if (url == null) { + final String resource = "resources/" + str.substring("nashorn:".length()); + // NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme + // These scripts are always available and are loaded from nashorn.jar's resources. + final Source code = AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public Source run() { + try { + final URL resURL = Context.class.getResource(resource); + return (resURL != null)? new Source(str, resURL) : null; + } catch (final IOException exp) { + return null; + } + } + }); + if (code == null) { throw e; } + return evaluateSource(code, scope, scope); } else { throw e; } } + } else if (file.isFile()) { + url = file.toURI().toURL(); } src = url; } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java index f4b4ad2054d..685f141e8ae 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java @@ -456,6 +456,8 @@ public final class JavaAdapterFactory { private static ClassLoader createClassLoader(final ClassLoader parentLoader, final String className, final byte[] classBytes, final String privilegedActionClassName) { return new AdapterLoader(parentLoader) { + private final ProtectionDomain myProtectionDomain = getClass().getProtectionDomain(); + @Override protected Class findClass(final String name) throws ClassNotFoundException { if(name.equals(className)) { @@ -463,7 +465,7 @@ public final class JavaAdapterFactory { return defineClass(name, bytes, 0, bytes.length, GENERATED_PROTECTION_DOMAIN); } else if(name.equals(privilegedActionClassName)) { final byte[] bytes = generatePrivilegedActionClassBytes(privilegedActionClassName.replace('.', '/')); - return defineClass(name, bytes, 0, bytes.length, getClass().getProtectionDomain()); + return defineClass(name, bytes, 0, bytes.length, myProtectionDomain); } else { throw new ClassNotFoundException(name); } diff --git a/nashorn/test/script/README b/nashorn/test/script/README new file mode 100644 index 00000000000..3cca31eb95e --- /dev/null +++ b/nashorn/test/script/README @@ -0,0 +1,26 @@ +basic: + +"basic" language and library tests. These need run only with File read +permission to read files under "test/script" or subdirs and property read +permission to read properties named "nashorn.test.*" + +error: + +scripts that should result in compile-time error. The expected files check +for the error message format etc. + +currently-failing: + +Tests that fail currently - but should pass eventually. +These are excluded for now. + +sandbox: + +Tests to check that sandbox scripts cannot access security sensitive resources. +Scripts under this directory run with no special permissions other than +what is given to all "sandbox" scripts. + +trusted: + +These tests run under AllPermission. Put only those scripts that really need +AllPermission - say for eg. creating class loader, full reflective access. diff --git a/nashorn/test/script/basic/NASHORN-758.js b/nashorn/test/script/basic/NASHORN-758.js index 7a92a4c3e6a..f57eaf1913f 100644 --- a/nashorn/test/script/basic/NASHORN-758.js +++ b/nashorn/test/script/basic/NASHORN-758.js @@ -25,16 +25,16 @@ * NASHORN-758 : nashorn shell command line options improvements * * @test - * @option -Dfoo=bar - * @option -Dhello=world + * @option -Dnashorn.test.foo=bar + * @option -Dnashorn.test.hello=world * @run */ -if (java.lang.System.getProperty("foo") != "bar") { - fail("System property 'foo' != 'bar'"); +if (java.lang.System.getProperty("nashorn.test.foo") != "bar") { + fail("System property 'nashorn.test.foo' != 'bar'"); } -if (java.lang.System.getProperty("hello") != "world") { - fail("System property 'hello' != 'world'"); +if (java.lang.System.getProperty("nashorn.test.hello") != "world") { + fail("System property 'nashorn.test.hello' != 'world'"); } diff --git a/nashorn/test/script/basic/javaexceptions.js b/nashorn/test/script/basic/javaexceptions.js index 3db97e621f6..3f81f697245 100644 --- a/nashorn/test/script/basic/javaexceptions.js +++ b/nashorn/test/script/basic/javaexceptions.js @@ -31,7 +31,7 @@ try { new java.io.FileInputStream("non_existent_file"); } catch (e) { - print(e instanceof java.io.FileNotFoundException); + print(e instanceof java.io.FileNotFoundException || e instanceof java.lang.SecurityException); } try { diff --git a/nashorn/test/script/basic/newexpr.js b/nashorn/test/script/basic/newexpr.js index 78711a13965..d8d1b48cdcf 100644 --- a/nashorn/test/script/basic/newexpr.js +++ b/nashorn/test/script/basic/newexpr.js @@ -29,7 +29,7 @@ */ var File = java.io.File; -print(new File(".").isDirectory()); +print(! new File(".").toString().isEmpty()); var obj = { foo : function (x) { diff --git a/nashorn/test/script/sandbox/interfaceimpl.js b/nashorn/test/script/sandbox/interfaceimpl.js new file mode 100644 index 00000000000..b2ee86b5f0b --- /dev/null +++ b/nashorn/test/script/sandbox/interfaceimpl.js @@ -0,0 +1,63 @@ +/* + * 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. + */ + +/** + * Check that user defined interface can be implemented. + * + * @test + * @run + * @security + */ + +var Window = Java.type("jdk.nashorn.api.scripting.Window"); +var WindowEventHandler = Java.type("jdk.nashorn.api.scripting.WindowEventHandler"); + +var w = new Window(); + +var loadedFuncReached = false; +// try function to SAM converter +w.onload = function() { + loadedFuncReached = true; + return true; +} + +w.onload.loaded(); +if (! loadedFuncReached) { + fail("Interface method impl. not called"); +} + +// reset +loadedFuncReached = false; + +// try direct interface implementation +w.onload = new WindowEventHandler() { + loaded: function() { + loadedFuncReached = true; + return true; + } +}; + +w.onload.loaded(); +if (! loadedFuncReached) { + fail("Interface method impl. not called"); +} diff --git a/nashorn/test/script/sandbox/loadcompat.js b/nashorn/test/script/sandbox/loadcompat.js new file mode 100644 index 00000000000..e99f67f2116 --- /dev/null +++ b/nashorn/test/script/sandbox/loadcompat.js @@ -0,0 +1,50 @@ +/* + * 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. + */ + +/** + * Check that nashorn mozilla compatibility script can be loaded in sandbox. + * + * @test + * @run + * @security + */ + +load("nashorn:mozilla_compat.js"); + +var obj = {}; +if (obj.__proto__ !== Object.prototype) { + fail("__proto__ does not work as expected"); +} + +var array = []; +if (array.__proto__ !== Array.prototype) { + fail("__proto__ does not work as expected"); +} + +if (typeof JavaAdapter != 'function') { + fail("JavaAdapter constructor is missing in compatibility script"); +} + +if (typeof importPackage != 'function') { + fail("importPackage function is missing in compatibility script"); +} diff --git a/nashorn/test/script/basic/JDK-8006424.js b/nashorn/test/script/trusted/JDK-8006424.js similarity index 100% rename from nashorn/test/script/basic/JDK-8006424.js rename to nashorn/test/script/trusted/JDK-8006424.js diff --git a/nashorn/test/script/basic/JDK-8006529.js b/nashorn/test/script/trusted/JDK-8006529.js similarity index 100% rename from nashorn/test/script/basic/JDK-8006529.js rename to nashorn/test/script/trusted/JDK-8006529.js diff --git a/nashorn/test/script/basic/NASHORN-638.js b/nashorn/test/script/trusted/NASHORN-638.js similarity index 100% rename from nashorn/test/script/basic/NASHORN-638.js rename to nashorn/test/script/trusted/NASHORN-638.js diff --git a/nashorn/test/script/basic/NASHORN-638.js.EXPECTED b/nashorn/test/script/trusted/NASHORN-638.js.EXPECTED similarity index 100% rename from nashorn/test/script/basic/NASHORN-638.js.EXPECTED rename to nashorn/test/script/trusted/NASHORN-638.js.EXPECTED diff --git a/nashorn/test/script/basic/NASHORN-653.js b/nashorn/test/script/trusted/NASHORN-653.js similarity index 100% rename from nashorn/test/script/basic/NASHORN-653.js rename to nashorn/test/script/trusted/NASHORN-653.js diff --git a/nashorn/test/script/trusted/README b/nashorn/test/script/trusted/README new file mode 100644 index 00000000000..60260ed7525 --- /dev/null +++ b/nashorn/test/script/trusted/README @@ -0,0 +1,4 @@ +This directory contains tests that need AllPermission to run. + +Scripts that need to create classloaders, need to reflectively access +declared members of other classes etc. should go here. diff --git a/nashorn/test/script/basic/getenv.js b/nashorn/test/script/trusted/getenv.js similarity index 100% rename from nashorn/test/script/basic/getenv.js rename to nashorn/test/script/trusted/getenv.js diff --git a/nashorn/test/script/basic/getenv.js.EXPECTED b/nashorn/test/script/trusted/getenv.js.EXPECTED similarity index 100% rename from nashorn/test/script/basic/getenv.js.EXPECTED rename to nashorn/test/script/trusted/getenv.js.EXPECTED diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java index 6b043f6af14..169ebf9d653 100644 --- a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java +++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java @@ -972,46 +972,6 @@ public class ScriptEngineTest { } } - private static class MyClassLoader extends ClassLoader { - // to check if script engine uses the specified class loader - private final boolean[] reached = new boolean[1]; - - @Override - protected Class findClass(final String name) throws ClassNotFoundException { - // flag that it reached here - reached[0] = true; - return super.findClass(name); - } - - public boolean reached() { - return reached[0]; - } - }; - - @Test - public void factoryClassLoaderTest() { - final ScriptEngineManager sm = new ScriptEngineManager(); - for (ScriptEngineFactory fac : sm.getEngineFactories()) { - if (fac instanceof NashornScriptEngineFactory) { - final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac; - final MyClassLoader loader = new MyClassLoader(); - // set the classloader as app class loader - final ScriptEngine e = nfac.getScriptEngine(loader); - try { - e.eval("Packages.foo"); - // check that the class loader was attempted - assertTrue(loader.reached(), "did not reach class loader!"); - } catch (final ScriptException se) { - se.printStackTrace(); - fail(se.getMessage()); - } - return; - } - } - - fail("Cannot find nashorn factory!"); - } - @Test public void factoryOptionsTest() { final ScriptEngineManager sm = new ScriptEngineManager(); @@ -1033,38 +993,4 @@ public class ScriptEngineTest { fail("Cannot find nashorn factory!"); } - - @Test - public void factoryClassLoaderAndOptionsTest() { - final ScriptEngineManager sm = new ScriptEngineManager(); - for (ScriptEngineFactory fac : sm.getEngineFactories()) { - if (fac instanceof NashornScriptEngineFactory) { - final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac; - final String[] options = new String[] { "-strict" }; - final MyClassLoader loader = new MyClassLoader(); - // set the classloader as app class loader - final ScriptEngine e = nfac.getScriptEngine(options, loader); - try { - e.eval("Packages.foo"); - // check that the class loader was attempted - assertTrue(loader.reached(), "did not reach class loader!"); - } catch (final ScriptException se) { - se.printStackTrace(); - fail(se.getMessage()); - } - - try { - // strict mode - delete of a var should throw SyntaxError - e.eval("var d = 2; delete d;"); - } catch (final ScriptException se) { - // check that the error message contains "SyntaxError" - assertTrue(se.getMessage().contains("SyntaxError")); - } - - return; - } - } - - fail("Cannot find nashorn factory!"); - } } diff --git a/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java b/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java index f7e6857d32c..396847661af 100644 --- a/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java @@ -27,8 +27,15 @@ package jdk.nashorn.internal.runtime; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; import java.util.Map; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import jdk.nashorn.api.scripting.NashornScriptEngineFactory; +import jdk.nashorn.api.scripting.ScriptEngineTest; import jdk.nashorn.internal.runtime.options.Options; import org.testng.annotations.Test; @@ -107,4 +114,83 @@ public class ContextTest { final ScriptFunction func = cx.compileScript(source, global, cx._strict); return func != null ? ScriptRuntime.apply(func, global) : null; } + + // Tests for trusted client usage of nashorn script engine factory extension API + + private static class MyClassLoader extends ClassLoader { + // to check if script engine uses the specified class loader + private final boolean[] reached = new boolean[1]; + + @Override + protected Class findClass(final String name) throws ClassNotFoundException { + // flag that it reached here + reached[0] = true; + return super.findClass(name); + } + + public boolean reached() { + return reached[0]; + } + }; + + // These are for "private" extension API of NashornScriptEngineFactory that + // accepts a ClassLoader and/or command line options. + + @Test + public void factoryClassLoaderTest() { + final ScriptEngineManager sm = new ScriptEngineManager(); + for (ScriptEngineFactory fac : sm.getEngineFactories()) { + if (fac instanceof NashornScriptEngineFactory) { + final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac; + final MyClassLoader loader = new MyClassLoader(); + // set the classloader as app class loader + final ScriptEngine e = nfac.getScriptEngine(loader); + try { + e.eval("Packages.foo"); + // check that the class loader was attempted + assertTrue(loader.reached(), "did not reach class loader!"); + } catch (final ScriptException se) { + se.printStackTrace(); + fail(se.getMessage()); + } + return; + } + } + + fail("Cannot find nashorn factory!"); + } + + @Test + public void factoryClassLoaderAndOptionsTest() { + final ScriptEngineManager sm = new ScriptEngineManager(); + for (ScriptEngineFactory fac : sm.getEngineFactories()) { + if (fac instanceof NashornScriptEngineFactory) { + final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac; + final String[] options = new String[] { "-strict" }; + final MyClassLoader loader = new MyClassLoader(); + // set the classloader as app class loader + final ScriptEngine e = nfac.getScriptEngine(options, loader); + try { + e.eval("Packages.foo"); + // check that the class loader was attempted + assertTrue(loader.reached(), "did not reach class loader!"); + } catch (final ScriptException se) { + se.printStackTrace(); + fail(se.getMessage()); + } + + try { + // strict mode - delete of a var should throw SyntaxError + e.eval("var d = 2; delete d;"); + } catch (final ScriptException se) { + // check that the error message contains "SyntaxError" + assertTrue(se.getMessage().contains("SyntaxError")); + } + + return; + } + } + + fail("Cannot find nashorn factory!"); + } } From 37905fb387d85c619c012f9f9d9828834bd4e5bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Thu, 7 Feb 2013 14:58:41 +0100 Subject: [PATCH 123/311] 8007627: Support @Getter annotation on constructor Reviewed-by: attila, lagergren --- .../jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java | 2 +- .../jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java index 6da3562dc4c..836cb8930c0 100644 --- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java @@ -135,7 +135,7 @@ public class ConstructorGenerator extends ClassGenerator { linkerAddGetterSetter(mi, className, memInfo); } else if (memInfo.isConstructorGetter()) { final MemberInfo setter = scriptClassInfo.findSetter(memInfo); - linkerAddGetterSetter(mi, className, memInfo, setter); + linkerAddGetterSetter(mi, scriptClassInfo.getJavaName(), memInfo, setter); } } emitStaticInitSuffix(mi, className); diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java index 9aeaf8f7eaa..17750cd1bbf 100644 --- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java @@ -112,7 +112,7 @@ public class PrototypeGenerator extends ClassGenerator { linkerAddGetterSetter(mi, className, memInfo); } else if (memInfo.isPrototypeGetter()) { final MemberInfo setter = scriptClassInfo.findSetter(memInfo); - linkerAddGetterSetter(mi, className, memInfo, setter); + linkerAddGetterSetter(mi, scriptClassInfo.getJavaName(), memInfo, setter); } } emitStaticInitSuffix(mi, className); From f2dc010c1610c008b8513588b0e89faffb21e954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Thu, 7 Feb 2013 15:33:17 +0100 Subject: [PATCH 124/311] 8007718: Make static RegExp properties fully compatible to other engines Reviewed-by: lagergren, sundar --- .../jdk/nashorn/internal/objects/Global.java | 20 +- .../internal/objects/NativeRegExp.java | 287 ++++++++++++------ .../nashorn/internal/runtime/RegExpMatch.java | 18 ++ .../internal/runtime/ScriptObject.java | 4 +- nashorn/test/script/basic/JDK-8007718.js | 55 ++++ .../test/script/basic/JDK-8007718.js.EXPECTED | 105 +++++++ 6 files changed, 379 insertions(+), 110 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8007718.js create mode 100644 nashorn/test/script/basic/JDK-8007718.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk/nashorn/internal/objects/Global.java index aa7361a7625..4ea7fd0979e 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java @@ -48,6 +48,7 @@ import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.NativeJavaPackage; import jdk.nashorn.internal.runtime.OptionsObject; import jdk.nashorn.internal.runtime.PropertyDescriptor; +import jdk.nashorn.internal.runtime.RegExpMatch; import jdk.nashorn.internal.runtime.Scope; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; @@ -337,6 +338,9 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { // class cache private ClassCache classCache; + // Used to store the last RegExp result to support deprecated RegExp constructor properties + private RegExpMatch lastRegExpMatch; + private static final MethodHandle EVAL = findOwnMH("eval", Object.class, Object.class, Object.class); private static final MethodHandle PRINT = findOwnMH("print", Object.class, Object.class, Object[].class); private static final MethodHandle PRINTLN = findOwnMH("println", Object.class, Object.class, Object[].class); @@ -1375,13 +1379,6 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { final ScriptObject regExpProto = getRegExpPrototype(); regExpProto.addBoundProperties(DEFAULT_REGEXP); - // add hook to support "deprecated" "static" properties of RegExp constructor object - final ScriptFunction handler = ScriptFunctionImpl.makeFunction(NO_SUCH_METHOD_NAME, NativeRegExp.REGEXP_STATICS_HANDLER); - builtinRegExp.addOwnProperty(NO_SUCH_PROPERTY_NAME, Attribute.NOT_ENUMERABLE, handler); - - // add initial undefined "last successful match" property RegExp - builtinRegExp.addOwnProperty(NativeRegExp.LAST_REGEXP_MATCH, Attribute.NOT_ENUMERABLE, UNDEFINED); - // Error stuff initErrorObjects(); @@ -1703,4 +1700,13 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { return MH.findStatic(MethodHandles.publicLookup(), Global.class, name, MH.type(rtype, types)); } + + RegExpMatch getLastRegExpMatch() { + return lastRegExpMatch; + } + + void setLastRegExpMatch(RegExpMatch regExpMatch) { + this.lastRegExpMatch = regExpMatch; + } + } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java index e44b929819c..781d2333b35 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java @@ -27,10 +27,7 @@ package jdk.nashorn.internal.objects; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; -import static jdk.nashorn.internal.runtime.linker.Lookup.MH; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -43,6 +40,7 @@ import jdk.nashorn.internal.objects.annotations.Getter; import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.objects.annotations.SpecializedConstructor; +import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.parser.RegExp; import jdk.nashorn.internal.runtime.BitVector; import jdk.nashorn.internal.runtime.JSType; @@ -57,8 +55,6 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; */ @ScriptClass("RegExp") public final class NativeRegExp extends ScriptObject { - static final MethodHandle REGEXP_STATICS_HANDLER = findOwnMH("regExpStaticsHandler", Object.class, Object.class, Object.class); - /** ECMA 15.10.7.5 lastIndex property */ @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) public Object lastIndex; @@ -80,8 +76,8 @@ public final class NativeRegExp extends ScriptObject { private BitVector groupsInNegativeLookahead; - // RegExp constructor object. Needed to support RegExp "static" properties, - private Object constructor; + // Reference to global object needed to support static RegExp properties + private Global globalObject; /* public NativeRegExp() { @@ -329,7 +325,7 @@ public final class NativeRegExp extends ScriptObject { * @param self self reference * @return the input string for the regexp */ - @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE | Attribute.NOT_WRITABLE) + @Getter(attributes = Attribute.NON_ENUMERABLE_CONSTANT) public static Object source(final Object self) { return checkRegExp(self).input; } @@ -340,7 +336,7 @@ public final class NativeRegExp extends ScriptObject { * @param self self reference * @return true if this regexp is flagged global, false otherwise */ - @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE | Attribute.NOT_WRITABLE) + @Getter(attributes = Attribute.NON_ENUMERABLE_CONSTANT) public static Object global(final Object self) { return checkRegExp(self).global; } @@ -351,7 +347,7 @@ public final class NativeRegExp extends ScriptObject { * @param self self reference * @return true if this regexp if flagged to ignore case, false otherwise */ - @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE | Attribute.NOT_WRITABLE) + @Getter(attributes = Attribute.NON_ENUMERABLE_CONSTANT) public static Object ignoreCase(final Object self) { return checkRegExp(self).ignoreCase; } @@ -362,11 +358,175 @@ public final class NativeRegExp extends ScriptObject { * @param self self reference * @return true if this regexp is flagged to be multiline, false otherwise */ - @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE | Attribute.NOT_WRITABLE) + @Getter(attributes = Attribute.NON_ENUMERABLE_CONSTANT) public static Object multiline(final Object self) { return checkRegExp(self).multiline; } + /** + * Getter for non-standard RegExp.input property. + * @param self self object + * @return last regexp input + */ + @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "input") + public static Object getLastInput(Object self) { + final RegExpMatch match = Global.instance().getLastRegExpMatch(); + return match == null ? "" : match.getInput(); + } + + /** + * Getter for non-standard RegExp.multiline property. + * @param self self object + * @return last regexp input + */ + @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "multiline") + public static Object getLastMultiline(Object self) { + return false; // doesn't ever seem to become true and isn't documented anyhwere + } + + /** + * Getter for non-standard RegExp.lastMatch property. + * @param self self object + * @return last regexp input + */ + @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "lastMatch") + public static Object getLastMatch(Object self) { + final RegExpMatch match = Global.instance().getLastRegExpMatch(); + return match == null ? "" : match.getGroup(0); + } + + /** + * Getter for non-standard RegExp.lastParen property. + * @param self self object + * @return last regexp input + */ + @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "lastParen") + public static Object getLastParen(Object self) { + final RegExpMatch match = Global.instance().getLastRegExpMatch(); + return match == null ? "" : match.getLastParen(); + } + + /** + * Getter for non-standard RegExp.leftContext property. + * @param self self object + * @return last regexp input + */ + @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "leftContext") + public static Object getLeftContext(Object self) { + final RegExpMatch match = Global.instance().getLastRegExpMatch(); + return match == null ? "" : match.getInput().substring(0, match.getIndex()); + } + + /** + * Getter for non-standard RegExp.rightContext property. + * @param self self object + * @return last regexp input + */ + @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "rightContext") + public static Object getRightContext(Object self) { + final RegExpMatch match = Global.instance().getLastRegExpMatch(); + return match == null ? "" : match.getInput().substring(match.getIndex() + match.length()); + } + + /** + * Getter for non-standard RegExp.$1 property. + * @param self self object + * @return last regexp input + */ + @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$1") + public static Object getGroup1(Object self) { + final RegExpMatch match = Global.instance().getLastRegExpMatch(); + return match == null ? "" : match.getGroup(1); + } + + /** + * Getter for non-standard RegExp.$2 property. + * @param self self object + * @return last regexp input + */ + @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$2") + public static Object getGroup2(Object self) { + final RegExpMatch match = Global.instance().getLastRegExpMatch(); + return match == null ? "" : match.getGroup(2); + } + + /** + * Getter for non-standard RegExp.$3 property. + * @param self self object + * @return last regexp input + */ + @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$3") + public static Object getGroup3(Object self) { + final RegExpMatch match = Global.instance().getLastRegExpMatch(); + return match == null ? "" : match.getGroup(3); + } + + /** + * Getter for non-standard RegExp.$4 property. + * @param self self object + * @return last regexp input + */ + @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$4") + public static Object getGroup4(Object self) { + final RegExpMatch match = Global.instance().getLastRegExpMatch(); + return match == null ? "" : match.getGroup(4); + } + + /** + * Getter for non-standard RegExp.$5 property. + * @param self self object + * @return last regexp input + */ + @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$5") + public static Object getGroup5(Object self) { + final RegExpMatch match = Global.instance().getLastRegExpMatch(); + return match == null ? "" : match.getGroup(5); + } + + /** + * Getter for non-standard RegExp.$6 property. + * @param self self object + * @return last regexp input + */ + @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$6") + public static Object getGroup6(Object self) { + final RegExpMatch match = Global.instance().getLastRegExpMatch(); + return match == null ? "" : match.getGroup(6); + } + + /** + * Getter for non-standard RegExp.$7 property. + * @param self self object + * @return last regexp input + */ + @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$7") + public static Object getGroup7(Object self) { + final RegExpMatch match = Global.instance().getLastRegExpMatch(); + return match == null ? "" : match.getGroup(7); + } + + /** + * Getter for non-standard RegExp.$8 property. + * @param self self object + * @return last regexp input + */ + @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$8") + public static Object getGroup8(Object self) { + final RegExpMatch match = Global.instance().getLastRegExpMatch(); + return match == null ? "" : match.getGroup(8); + } + + /** + * Getter for non-standard RegExp.$9 property. + * @param self self object + * @return last regexp input + */ + @Getter(where = Where.CONSTRUCTOR, attributes = Attribute.CONSTANT, name = "$9") + public static Object getGroup9(Object self) { + final RegExpMatch match = Global.instance().getLastRegExpMatch(); + return match == null ? "" : match.getGroup(9); + } + private RegExpMatch execInner(final String string) { if (this.pattern == null) { return null; // never matches or similar, e.g. a[] @@ -389,7 +549,9 @@ public final class NativeRegExp extends ScriptObject { setLastIndex(matcher.end()); } - return new RegExpMatch(string, matcher.start(), groups(matcher)); + final RegExpMatch match = new RegExpMatch(string, matcher.start(), groups(matcher)); + globalObject.setLastRegExpMatch(match); + return match; } /** @@ -425,84 +587,13 @@ public final class NativeRegExp extends ScriptObject { * @return NativeArray of matches, string or null. */ public Object exec(final String string) { - final RegExpMatch m = execInner(string); - // the input string - if (m == null) { - return setLastRegExpMatch(null); + final RegExpMatch match = execInner(string); + + if (match == null) { + return null; } - return setLastRegExpMatch(new NativeRegExpExecResult(m)); - } - - // Name of the "last successful match" property of the RegExp constructor - static final String LAST_REGEXP_MATCH = "__last_regexp_match__"; - - /** - * Handles "static" properties of RegExp constructor. These are "deprecated" - * properties of RegExp constructor. - * - * @param self self object passed to this method - * @param name name of the property being searched - * - * @return value of the specified property or undefined if not found - */ - public static Object regExpStaticsHandler(final Object self, final Object name) { - final String propName = JSType.toString(name); - if (self instanceof ScriptObject) { - final ScriptObject sobj = (ScriptObject)self; - final Object value = sobj.get(LAST_REGEXP_MATCH); - if (! (value instanceof NativeRegExpExecResult)) { - return UNDEFINED; - } - - // get the last match object - final NativeRegExpExecResult lastMatch = (NativeRegExpExecResult)value; - - // look for $1... $9 - if (propName.length() > 0 && propName.charAt(0) == '$') { - int index = 0; - try { - index = Integer.parseInt(propName.substring(1)); - } catch (final Exception ignored) { - return UNDEFINED; - } - - // index out of range - if (index < 1 && index > 9) { - return UNDEFINED; - } - - // retrieve indexed value from last match object. - return lastMatch.get(index); - } - - // misc. "static" properties supported - switch (propName) { - case "input": { - return lastMatch.input; - } - - case "lastMatch": { - return lastMatch.get(0); - } - - case "lastParen": { - final int len = ((Number)NativeRegExpExecResult.length(lastMatch)).intValue(); - return (len > 0)? lastMatch.get(len - 1) : UNDEFINED; - } - } - } - - return UNDEFINED; - } - - // Support for RegExp static properties. We set last successful match - // to the RegExp constructor object. - private Object setLastRegExpMatch(final Object match) { - if (constructor instanceof ScriptObject) { - ((ScriptObject)constructor).set(LAST_REGEXP_MATCH, match, isStrictContext()); - } - return match; + return new NativeRegExpExecResult(match); } /** @@ -744,15 +835,13 @@ public final class NativeRegExp extends ScriptObject { * @return Index of match. */ Object search(final String string) { - final RegExpMatch m = execInner(string); - // the input string - if (m == null) { - setLastRegExpMatch(null); + final RegExpMatch match = execInner(string); + + if (match == null) { return -1; } - setLastRegExpMatch(new NativeRegExpExecResult(m)); - return m.getIndex(); + return match.getIndex(); } /** @@ -780,10 +869,9 @@ public final class NativeRegExp extends ScriptObject { } private void init() { - final ScriptObject proto = Global.instance().getRegExpPrototype(); - this.setProto(proto); - // retrieve constructor to support "static" properties of RegExp - this.constructor = PrototypeObject.getConstructor(proto); + // Keep reference to global object to support "static" properties of RegExp + this.globalObject = Global.instance(); + this.setProto(globalObject.getRegExpPrototype()); } private static NativeRegExp checkRegExp(final Object self) { @@ -846,7 +934,4 @@ public final class NativeRegExp extends ScriptObject { this.groupsInNegativeLookahead = groupsInNegativeLookahead; } - private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { - return MH.findStatic(MethodHandles.publicLookup(), NativeRegExp.class, name, MH.type(rtype, types)); - } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/RegExpMatch.java b/nashorn/src/jdk/nashorn/internal/runtime/RegExpMatch.java index 81ab1db3a99..80b6f06d385 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/RegExpMatch.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/RegExpMatch.java @@ -77,4 +77,22 @@ public final class RegExpMatch { public int length() { return ((String)groups[0]).length(); } + + /** + * Get the group with the given index or the empty string if group index is not valid. + * @param index the group index + * @return the group or "" + */ + public Object getGroup(int index) { + return index >= 0 && index < groups.length ? groups[index] : ""; + } + + /** + * Get the last parenthesis group, or the empty string if none exists. + * @return the last group or "" + */ + public Object getLastParen() { + return groups.length > 1 ? groups[groups.length - 1] : ""; + } + } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java index 07106d84179..8c1076285f6 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -89,10 +89,10 @@ import org.dynalang.dynalink.support.CallSiteDescriptorFactory; public abstract class ScriptObject extends PropertyListenerManager implements PropertyAccess { /** Search fall back routine name for "no such method" */ - public static final String NO_SUCH_METHOD_NAME = "__noSuchMethod__"; + static final String NO_SUCH_METHOD_NAME = "__noSuchMethod__"; /** Search fall back routine name for "no such property" */ - public static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__"; + static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__"; /** Per ScriptObject flag - is this a scope object? */ public static final int IS_SCOPE = 0b0000_0001; diff --git a/nashorn/test/script/basic/JDK-8007718.js b/nashorn/test/script/basic/JDK-8007718.js new file mode 100644 index 00000000000..fce5d8c8a7e --- /dev/null +++ b/nashorn/test/script/basic/JDK-8007718.js @@ -0,0 +1,55 @@ +/* + * 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. + */ + +/** + * JDK-8007718: Make static RegExp properties fully compatible to other engines + * + * @test + * @run + */ + +function dumpRegExpProperties() { + for (var p in RegExp) { + print(p, RegExp[p], typeof RegExp[p]); + } +} + +dumpRegExpProperties(); + +/abc/.exec("xyz"); +dumpRegExpProperties(); + +/(b)(a)(r)/gmi.exec("FOOBARfoo"); +dumpRegExpProperties(); + +"abcdefghijklmnopq".match(/(\w)(\w)(\w)(\w)(\w)(\w)(\w)(\w)(\w)(\w)(\w)/); +dumpRegExpProperties(); + +"abcabcabcABCabcABC".split(/(b)/i); +dumpRegExpProperties(); + +"foobarfoo".search(/bar/); +dumpRegExpProperties(); + +/abc/.exec("xyz"); +dumpRegExpProperties(); diff --git a/nashorn/test/script/basic/JDK-8007718.js.EXPECTED b/nashorn/test/script/basic/JDK-8007718.js.EXPECTED new file mode 100644 index 00000000000..9ffbd3cc839 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8007718.js.EXPECTED @@ -0,0 +1,105 @@ +input string +multiline false boolean +lastMatch string +lastParen string +leftContext string +rightContext string +$1 string +$2 string +$3 string +$4 string +$5 string +$6 string +$7 string +$8 string +$9 string +input string +multiline false boolean +lastMatch string +lastParen string +leftContext string +rightContext string +$1 string +$2 string +$3 string +$4 string +$5 string +$6 string +$7 string +$8 string +$9 string +input FOOBARfoo string +multiline false boolean +lastMatch BAR string +lastParen R string +leftContext FOO string +rightContext foo string +$1 B string +$2 A string +$3 R string +$4 string +$5 string +$6 string +$7 string +$8 string +$9 string +input abcdefghijklmnopq string +multiline false boolean +lastMatch abcdefghijk string +lastParen k string +leftContext string +rightContext lmnopq string +$1 a string +$2 b string +$3 c string +$4 d string +$5 e string +$6 f string +$7 g string +$8 h string +$9 i string +input abcabcabcABCabcABC string +multiline false boolean +lastMatch B string +lastParen B string +leftContext abcabcabcABCabcA string +rightContext C string +$1 B string +$2 string +$3 string +$4 string +$5 string +$6 string +$7 string +$8 string +$9 string +input foobarfoo string +multiline false boolean +lastMatch bar string +lastParen string +leftContext foo string +rightContext foo string +$1 string +$2 string +$3 string +$4 string +$5 string +$6 string +$7 string +$8 string +$9 string +input foobarfoo string +multiline false boolean +lastMatch bar string +lastParen string +leftContext foo string +rightContext foo string +$1 string +$2 string +$3 string +$4 string +$5 string +$6 string +$7 string +$8 string +$9 string From 3479e4412ab65b5c582060e502348c7d81a69b0a Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Thu, 7 Feb 2013 09:41:47 -0800 Subject: [PATCH 125/311] 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 126/311] 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 127/311] 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 32d71c7cb9536531d967d00980b6992d268b688f Mon Sep 17 00:00:00 2001 From: James Laskey Date: Fri, 8 Feb 2013 09:19:38 -0400 Subject: [PATCH 128/311] 8006222: Move slot from SpillProperty to Property Reviewed-by: hannesw, lagergren --- .../codegen/objects/FieldObjectCreator.java | 4 +- .../internal/codegen/objects/MapCreator.java | 64 ++------- .../codegen/objects/ObjectCreator.java | 28 ++-- .../internal/objects/ScriptFunctionImpl.java | 2 +- .../internal/runtime/AccessorProperty.java | 110 +++++++++------ .../internal/runtime/FindProperty.java | 128 ++++-------------- .../nashorn/internal/runtime/Property.java | 53 ++++++-- .../nashorn/internal/runtime/PropertyMap.java | 5 +- .../internal/runtime/ScriptObject.java | 27 ++-- .../internal/runtime/SpillProperty.java | 35 +---- .../runtime/UserAccessorProperty.java | 18 +-- .../internal/runtime/linker/Lookup.java | 2 +- 12 files changed, 187 insertions(+), 289 deletions(-) diff --git a/nashorn/src/jdk/nashorn/internal/codegen/objects/FieldObjectCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/objects/FieldObjectCreator.java index f6e1c262b87..46219f05cd2 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/objects/FieldObjectCreator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/objects/FieldObjectCreator.java @@ -75,7 +75,7 @@ public abstract class FieldObjectCreator extends ObjectCreator { * @param symbols symbols for fields in object * @param values values (or null where no value) to be written to the fields * @param isScope is this a scope object - * @param hasArguments does the created object have an "arguments" object + * @param hasArguments does the created object have an "arguments" property */ public FieldObjectCreator(final CodeGenerator codegen, final List keys, final List symbols, final List values, final boolean isScope, final boolean hasArguments) { super(codegen, keys, symbols, isScope, hasArguments); @@ -106,7 +106,7 @@ public abstract class FieldObjectCreator extends ObjectCreator { if (isScope()) { loadScope(method); - if (isVarArg()) { + if (hasArguments()) { method.loadArguments(); method.invoke(constructorNoLookup(getClassName(), PropertyMap.class, ScriptObject.class, ARGUMENTS.type())); } else { diff --git a/nashorn/src/jdk/nashorn/internal/codegen/objects/MapCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/objects/MapCreator.java index da3a47fc4b2..1696597b862 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/objects/MapCreator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/objects/MapCreator.java @@ -25,20 +25,12 @@ package jdk.nashorn.internal.codegen.objects; -import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.OBJECT_FIELDS_ONLY; -import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.PRIMITIVE_TYPE; -import static jdk.nashorn.internal.runtime.linker.Lookup.MH; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.List; -import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.runtime.AccessorProperty; import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.PropertyMap; -import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.arrays.ArrayIndex; /** @@ -72,11 +64,11 @@ public class MapCreator { /** * Constructs a property map based on a set of fields. * - * @param isVarArg is this a vararg object map + * @param hasArguments does the created object have an "arguments" property * * @return New map populated with accessor properties. */ - public PropertyMap makeMap(final boolean isVarArg) { + public PropertyMap makeMap(final boolean hasArguments) { final List properties = new ArrayList<>(); assert keys != null; @@ -86,63 +78,31 @@ public class MapCreator { final Symbol symbol = symbols[i]; if (symbol != null && !ArrayIndex.isIndexKey(key)) { - final Property property = initHandle(key, symbol.getFieldIndex(), symbol, isVarArg); - properties.add(property); + properties.add(new AccessorProperty(key, getPropertyFlags(symbol, hasArguments), structure, symbol.getFieldIndex())); } } return PropertyMap.newMap(structure, properties); } - private Property initHandle(final String key, final int fieldIndex, final Symbol symbol, final boolean isVarArg) { - assert symbol != null; - final boolean isParam = symbol.isParam(); - - final String fieldNameObject = ObjectClassGenerator.getFieldName(fieldIndex, Type.OBJECT); - final String fieldNamePrimitive = ObjectClassGenerator.getFieldName(fieldIndex, ObjectClassGenerator.PRIMITIVE_TYPE); - - MethodHandle primitiveGetter = null; - MethodHandle primitiveSetter = null; - MethodHandle objectGetter; - MethodHandle objectSetter; - - final MethodHandles.Lookup lookup = MethodHandles.lookup(); - - if (isParam && isVarArg) { - final MethodHandle arguments = MH.getter(MethodHandles.lookup(), structure, "arguments", Object.class); - final MethodHandle argumentsSO = MH.asType(arguments, arguments.type().changeReturnType(ScriptObject.class)); - objectGetter = MH.insertArguments(MH.filterArguments(ScriptObject.GET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, fieldIndex); - objectSetter = MH.insertArguments(MH.filterArguments(ScriptObject.SET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, fieldIndex); - } else { - objectGetter = MH.getter(lookup, structure, fieldNameObject, Type.OBJECT.getTypeClass()); - objectSetter = MH.setter(lookup, structure, fieldNameObject, Type.OBJECT.getTypeClass()); - if (!OBJECT_FIELDS_ONLY) { - primitiveGetter = MH.getter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass()); - primitiveSetter = MH.setter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass()); - } - } - - return new AccessorProperty(key, getPropertyFlags(symbol, isVarArg), objectGetter, objectSetter, primitiveGetter, primitiveSetter); - } - /** * Compute property flags given local state of a field. Maybe be overridden and extended, * as is the case in {@link ObjectMapCreator} * - * @param symbol symbol to check - * @param isVarArg is this a vararg + * @param symbol symbol to check + * @param hasArguments does the created object have an "arguments" property * * @return flags to use for fields */ - protected int getPropertyFlags(final Symbol symbol, final boolean isVarArg) { - final boolean isParam = symbol.isParam(); + protected int getPropertyFlags(final Symbol symbol, final boolean hasArguments) { int flags = 0; - if (isParam || isVarArg) { - flags |= Property.IS_ALWAYS_OBJECT; - if (isParam) { - flags |= Property.IS_PARAMETER; - } + if (symbol.isParam()) { + flags |= Property.IS_ALWAYS_OBJECT | Property.IS_PARAMETER; + } + + if (hasArguments) { + flags |= Property.IS_ALWAYS_OBJECT | Property.HAS_ARGUMENTS; } if (symbol.isScope()) { diff --git a/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectCreator.java index 1b02aa06d2f..71c0b699da9 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectCreator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectCreator.java @@ -52,7 +52,7 @@ public abstract class ObjectCreator { protected final CodeGenerator codegen; private final boolean isScope; - private final boolean isVarArg; + private final boolean hasArguments; private int fieldCount; private int paramCount; private String fieldObjectClassName; @@ -62,19 +62,19 @@ public abstract class ObjectCreator { /** * Constructor * - * @param codegen the code generator - * @param keys the keys - * @param symbols the symbols corresponding to keys, same index - * @param isScope is this object scope - * @param isVarArg is this object var arg + * @param codegen the code generator + * @param keys the keys + * @param symbols the symbols corresponding to keys, same index + * @param isScope is this object scope + * @param hasArguments does the created object have an "arguments" property */ - protected ObjectCreator(final CodeGenerator codegen, final List keys, final List symbols, final boolean isScope, final boolean isVarArg) { + protected ObjectCreator(final CodeGenerator codegen, final List keys, final List symbols, final boolean isScope, final boolean hasArguments) { this.codegen = codegen; this.compileUnit = codegen.getCurrentCompileUnit(); this.keys = keys; this.symbols = symbols; this.isScope = isScope; - this.isVarArg = isVarArg; + this.hasArguments = hasArguments; countFields(); findClass(); @@ -86,7 +86,7 @@ public abstract class ObjectCreator { private void countFields() { for (final Symbol symbol : this.symbols) { if (symbol != null) { - if (isVarArg() && symbol.isParam()) { + if (hasArguments() && symbol.isParam()) { symbol.setFieldIndex(paramCount++); } else { symbol.setFieldIndex(fieldCount++); @@ -133,7 +133,7 @@ public abstract class ObjectCreator { if (keys.isEmpty()) { //empty map propertyMap = PropertyMap.newMap(fieldObjectClass); } else { - propertyMap = newMapCreator(fieldObjectClass).makeMap(isVarArg()); + propertyMap = newMapCreator(fieldObjectClass).makeMap(hasArguments()); } return propertyMap; } @@ -167,10 +167,10 @@ public abstract class ObjectCreator { } /** - * Is this a vararg object - * @return true if vararg + * Does the created object have an "arguments" property + * @return true if has an "arguments" property */ - protected boolean isVarArg() { - return isVarArg; + protected boolean hasArguments() { + return hasArguments; } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java index a3a6b33fd52..c84d8deab61 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java +++ b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java @@ -139,7 +139,7 @@ public class ScriptFunctionImpl extends ScriptFunction { // add a new property that throws TypeError on get as well as set static synchronized PropertyMap newThrowerProperty(final PropertyMap map, final String name, final int flags) { - return map.newProperty(name, flags, Lookup.TYPE_ERROR_THROWER_GETTER, Lookup.TYPE_ERROR_THROWER_SETTER); + return map.newProperty(name, flags, -1, Lookup.TYPE_ERROR_THROWER_GETTER, Lookup.TYPE_ERROR_THROWER_SETTER); } // property map for strict mode functions - lazily initialized diff --git a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java index dfa07dc2cd7..d10091ee4a7 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java @@ -29,6 +29,7 @@ import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.ACCESSOR import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.DEBUG_FIELDS; import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.LOG; import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.OBJECT_FIELDS_ONLY; +import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.PRIMITIVE_TYPE; import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.createGetter; import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.createGuardBoxedPrimitiveSetter; import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.createSetter; @@ -41,6 +42,7 @@ import static jdk.nashorn.internal.runtime.linker.MethodHandleFactory.stripName; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import jdk.nashorn.internal.codegen.objects.ObjectClassGenerator; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.runtime.linker.Lookup; import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; @@ -89,49 +91,6 @@ public class AccessorProperty extends Property { } } - /** - * Constructor - * - * primitiveGetter and setter are only used in dual fields mode. Setting them to null also - * works in dual field mode, it only means that the property never has a primitive - * representation - * - * @param key property key - * @param flags property flags - * @param objectGetter seed getter for object field - * @param objectSetter seed setter for object field - * @param primitiveGetter seed getter for primitive field (in dual field mode) - * @param primitiveSetter seed setter for primitive field (in dual field mode) - */ - public AccessorProperty(final String key, final int flags, final MethodHandle objectGetter, final MethodHandle objectSetter, final MethodHandle primitiveGetter, final MethodHandle primitiveSetter) { - super(key, flags); - - this.objectGetter = objectGetter; - this.objectSetter = objectSetter; - this.primitiveGetter = primitiveGetter; - this.primitiveSetter = primitiveSetter; - - Class initialType = null; - - if (OBJECT_FIELDS_ONLY || isAlwaysObject()) { - initialType = Object.class; - } else { - if (!canBePrimitive()) { - info(key + " cannot be primitive"); - initialType = Object.class; - } else { - info(key + " CAN be primitive"); - if (!canBeUndefined()) { - info(key + " is always defined"); - initialType = int.class; //double works too for less type invalidation, but this requires experimentation, e.g. var x = 17; x += 2 will turn it into double now because of lack of range analysis - } - } - } - - // is always object means "is never initialized to undefined, and always of object type - setCurrentType(initialType); - } - /** * Delegate constructor. This is used when adding properties to the Global scope, which * is necessary for outermost levels in a script (the ScriptObject is represented by @@ -161,11 +120,12 @@ public class AccessorProperty extends Property { * * @param key the property key * @param flags the property flags + * @param slot the property field number or spill slot * @param getter the property getter * @param setter the property setter or null if non writable, non configurable */ - public AccessorProperty(final String key, final int flags, final MethodHandle getter, final MethodHandle setter) { - super(key, flags); + public AccessorProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) { + super(key, flags, slot); // we don't need to prep the setters these will never be invalidated as this is a nasgen // or known type getter/setter. No invalidations will take place @@ -192,6 +152,66 @@ public class AccessorProperty extends Property { setCurrentType(getterType); } + /** + * Constructor for dual field AccessorPropertys. + * + * @param key property key + * @param flags property flags + * @param structure structure for objects associated with this property + * @param slot property field number or spill slot + */ + public AccessorProperty(final String key, final int flags, final Class structure, final int slot) { + super(key, flags, slot); + + /* + * + * primitiveGetter and primitiveSetter are only used in dual fields mode. Setting them to null also + * works in dual field mode, it only means that the property never has a primitive + * representation. + */ + primitiveGetter = null; + primitiveSetter = null; + + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + + if (isParameter() && hasArguments()) { + final MethodHandle arguments = MH.getter(MethodHandles.lookup(), structure, "arguments", Object.class); + final MethodHandle argumentsSO = MH.asType(arguments, arguments.type().changeReturnType(ScriptObject.class)); + + objectGetter = MH.insertArguments(MH.filterArguments(ScriptObject.GET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot); + objectSetter = MH.insertArguments(MH.filterArguments(ScriptObject.SET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot); + } else { + final String fieldNameObject = ObjectClassGenerator.getFieldName(slot, Type.OBJECT); + final String fieldNamePrimitive = ObjectClassGenerator.getFieldName(slot, ObjectClassGenerator.PRIMITIVE_TYPE); + + objectGetter = MH.getter(lookup, structure, fieldNameObject, Type.OBJECT.getTypeClass()); + objectSetter = MH.setter(lookup, structure, fieldNameObject, Type.OBJECT.getTypeClass()); + + if (!OBJECT_FIELDS_ONLY) { + primitiveGetter = MH.getter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass()); + primitiveSetter = MH.setter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass()); + } + } + + Class initialType = null; + + if (OBJECT_FIELDS_ONLY || isAlwaysObject()) { + initialType = Object.class; + } else if (!canBePrimitive()) { + info(key + " cannot be primitive"); + initialType = Object.class; + } else { + info(key + " CAN be primitive"); + if (!canBeUndefined()) { + info(key + " is always defined"); + initialType = int.class; //double works too for less type invalidation, but this requires experimentation, e.g. var x = 17; x += 2 will turn it into double now because of lack of range analysis + } + } + + // is always object means "is never initialized to undefined, and always of object type + setCurrentType(initialType); + } + /** * Copy constructor * diff --git a/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java index 87efd9f6c45..7089d1f6872 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java @@ -34,53 +34,26 @@ import jdk.nashorn.internal.codegen.objects.ObjectClassGenerator; * This class represents the result from a find property search. */ public final class FindProperty { + /** Object where search began. */ private final ScriptObject self; + ; + /** Object where search finish. */ private final ScriptObject prototype; - private final PropertyMap map; + + /** Found property. */ private final Property property; - private final int depth; - private final boolean isScope; /** * Constructor * - * @param self script object where property was found + * @param self script object where search began * @param prototype prototype where property was found, may be {@code self} if not inherited - * @param map property map for script object * @param property property that was search result - * @param depth depth walked in property chain to find result */ - public FindProperty(final ScriptObject self, final ScriptObject prototype, final PropertyMap map, final Property property, final int depth) { + public FindProperty(final ScriptObject self, final ScriptObject prototype, final Property property) { this.self = self; this.prototype = prototype; - this.map = map; this.property = property; - this.depth = depth; - this.isScope = prototype.isScope(); - } - - /** - * Get ScriptObject for search - * @return script object - */ - public ScriptObject getSelf() { - return self; - } - - /** - * Get search depth - * @return depth - */ - public int getDepth() { - return depth; - } - - /** - * Get flags for property that was found - * @return property flags for property returned in {@link FindProperty#getProperty()} - */ - public int getFlags() { - return property.getFlags(); } /** @@ -102,20 +75,33 @@ public final class FindProperty { } /** - * In certain properties, such as {@link UserAccessorProperty}, getter and setter functions - * are present. This function gets the getter function as a {@code ScriptFunction} - * @return getter function, or null if not present + * Ask for a setter that sets the given type. The type has nothing to do with the + * internal representation of the property. It may be an Object (boxing primitives) or + * a primitive (primitive fields with -Dnashorn.fields.dual=true) + * @see ObjectClassGenerator + * + * @param type type of setter, e.g. int.class if we want a function with {@code set(I)V} signature + * @param strict are we in strict mode + * + * @return method handle for the getter */ - public ScriptFunction getGetterFunction() { - return property.getGetterFunction(getOwner()); + public MethodHandle getSetter(final Class type, final boolean strict) { + MethodHandle setter = property.getSetter(type, getOwner().getMap()); + if (property instanceof UserAccessorProperty) { + final UserAccessorProperty uc = (UserAccessorProperty) property; + setter = MH.insertArguments(setter, 0, (isInherited() ? getOwner() : null), + uc.getSetterSlot(), strict? property.getKey() : null); + } + + return setter; } /** - * Return the property map where the property was found - * @return property map + * Return the {@code ScriptObject} owning of the property: this means the prototype. + * @return owner of property */ - public PropertyMap getMap() { - return map; + public ScriptObject getOwner() { + return prototype; } /** @@ -148,62 +134,8 @@ public final class FindProperty { * @return true if on scope */ public boolean isScope() { - return isScope; + return prototype.isScope(); } - /** - * Return the {@code ScriptObject} owning of the property: this means the prototype. - * @return owner of property - */ - public ScriptObject getOwner() { - return prototype; - } - - /** - * Ask for a setter that sets the given type. The type has nothing to do with the - * internal representation of the property. It may be an Object (boxing primitives) or - * a primitive (primitive fields with -Dnashorn.fields.dual=true) - * @see ObjectClassGenerator - * - * @param type type of setter, e.g. int.class if we want a function with {@code set(I)V} signature - * @param strict are we in strict mode - * - * @return method handle for the getter - */ - public MethodHandle getSetter(final Class type, final boolean strict) { - MethodHandle setter = property.getSetter(type, getOwner().getMap()); - if (property instanceof UserAccessorProperty) { - final UserAccessorProperty uc = (UserAccessorProperty) property; - setter = MH.insertArguments(setter, 0, (isInherited() ? getOwner() : null), - uc.getSetterSlot(), strict? property.getKey() : null); - } - - return setter; - } - - /** - * In certain properties, such as {@link UserAccessorProperty}, getter and setter functions - * are present. This function gets the setter function as a {@code ScriptFunction} - * @return setter function, or null if not present - */ - public ScriptFunction getSetterFunction() { - return property.getSetterFunction(getOwner()); - } - - /** - * Check if the property found is configurable - * @return true if configurable - */ - public boolean isConfigurable() { - return property.isConfigurable(); - } - - /** - * Check if the property found is writable - * @return true if writable - */ - public boolean isWritable() { - return property.isWritable(); - } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Property.java b/nashorn/src/jdk/nashorn/internal/runtime/Property.java index ae46c7a720f..0c5cf3f1f37 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Property.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Property.java @@ -67,17 +67,20 @@ public abstract class Property { /** Is this a spill property? See {@link SpillProperty} */ public static final int IS_SPILL = 0b0000_0001_0000; - /** Is this a function parameter ? */ + /** Is this a function parameter? */ public static final int IS_PARAMETER = 0b0000_0010_0000; + /** Is parameter accessed thru arguments? */ + public static final int HAS_ARGUMENTS = 0b0000_0100_0000; + /** Is this property always represented as an Object? See {@link ObjectClassGenerator} and dual fields flag. */ - public static final int IS_ALWAYS_OBJECT = 0b0000_0100_0000; + public static final int IS_ALWAYS_OBJECT = 0b0000_1000_0000; /** Can this property be primitive? */ - public static final int CAN_BE_PRIMITIVE = 0b0000_1000_0000; + public static final int CAN_BE_PRIMITIVE = 0b0001_0000_0000; /** Can this property be undefined? */ - public static final int CAN_BE_UNDEFINED = 0b0001_0000_0000; + public static final int CAN_BE_UNDEFINED = 0b0010_0000_0000; /** Property key. */ private final String key; @@ -85,15 +88,21 @@ public abstract class Property { /** Property flags. */ protected int flags; + /** Property field number or spill slot */ + private final int slot; + /** * Constructor * * @param key property key * @param flags property flags + * @param slot property field number or spill slot */ - public Property(final String key, final int flags) { + public Property(final String key, final int flags, final int slot) { + assert key != null; this.key = key; this.flags = flags; + this.slot = slot; } /** @@ -104,6 +113,7 @@ public abstract class Property { protected Property(final Property property) { this.key = property.key; this.flags = property.flags; + this.slot = property.slot; } /** @@ -214,6 +224,14 @@ public abstract class Property { return (flags & IS_PARAMETER) == IS_PARAMETER; } + /** + * Check whether this property is in an object with arguments field + * @return true if has arguments + */ + public boolean hasArguments() { + return (flags & HAS_ARGUMENTS) == HAS_ARGUMENTS; + } + /** * Check whether this is a spill property, i.e. one that will not * be stored in a specially generated field in the property class. @@ -371,17 +389,17 @@ public abstract class Property { } /** - * Get the spill slot as described in {@link Property#getSpillCount()}. - * @return spill slot, -1 if none exists + * Get the field number or spill slot + * @return number/slot, -1 if none exists */ public int getSlot() { - return -1; + return slot; } @Override public int hashCode() { final Class type = getCurrentType(); - return Objects.hashCode(this.key) ^ flags ^ (type == null ? 0 : type.hashCode()); + return Objects.hashCode(this.key) ^ flags ^ getSlot() ^ (type == null ? 0 : type.hashCode()); } @Override @@ -390,17 +408,16 @@ public abstract class Property { return true; } - if (!(other instanceof Property)) { + if (other == null || this.getClass() != other.getClass()) { return false; } final Property otherProperty = (Property)other; - final Object otherKey = otherProperty.key; - final Class otherType = otherProperty.getCurrentType(); - return flags == otherProperty.flags && - (key == null ? otherKey == null : key.equals(otherKey)) && - (getCurrentType() == otherType); + return getFlags() == otherProperty.getFlags() && + getSlot() == otherProperty.getSlot() && + getCurrentType() == otherProperty.getCurrentType() && + getKey().equals(otherProperty.getKey()); } @Override @@ -417,6 +434,12 @@ public abstract class Property { append(type == null ? "UNDEFINED" : Type.typeFor(type).getDescriptor()). append('}'); + if (slot != -1) { + sb.append('['); + sb.append(slot); + sb.append(']'); + } + return sb.toString(); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java index 0864b1c40c4..9a99c74d08b 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java @@ -271,13 +271,14 @@ public final class PropertyMap implements Iterable, PropertyListener { * * @param key {@link Property} key. * @param propertyFlags {@link Property} flags. + * @param slot {@link Property} slot. * @param getter {@link Property} get accessor method. * @param setter {@link Property} set accessor method. * * @return New {@link PropertyMap} with {@link AccessorProperty} added. */ - public PropertyMap newProperty(final String key, final int propertyFlags, final MethodHandle getter, final MethodHandle setter) { - return newProperty(new AccessorProperty(key, propertyFlags, getter, setter)); + public PropertyMap newProperty(final String key, final int propertyFlags, final int slot, final MethodHandle getter, final MethodHandle setter) { + return newProperty(new AccessorProperty(key, propertyFlags, slot, getter, setter)); } /** diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java index 8c1076285f6..c12ec723a39 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -650,24 +650,23 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr * @return FindPropertyData or null if not found. */ public final FindProperty findProperty(final String key, final boolean deep, final boolean stopOnNonScope) { - int depth = 0; - for (ScriptObject self = this; self != null; self = self.getProto()) { // if doing deep search, stop search on the first non-scope object if asked to do so - if (stopOnNonScope && depth != 0 && !self.isScope()) { - break; + if (stopOnNonScope && self != this && !self.isScope()) { + return null; } + final PropertyMap selfMap = self.getMap(); final Property property = selfMap.findProperty(key); if (property != null) { - return new FindProperty(this, self, selfMap, property, depth); - } else if (!deep) { - return null; + return new FindProperty(this, self, property); } - depth++; - } + if (!deep) { + return null; + } + } return null; } @@ -999,7 +998,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr * @return Value of property. */ public final Object getWithProperty(final Property property) { - return getObjectValue(new FindProperty(this, this, getMap(), property, 0)); + return getObjectValue(new FindProperty(this, this, property)); } /** @@ -1793,7 +1792,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr // If it's not a scope search, then we don't want any inherited properties except those with user defined accessors. if (!scope && find != null && find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) { // We should still check if inherited data property is not writable - if (isExtensible() && !find.isWritable()) { + if (isExtensible() && !find.getProperty().isWritable()) { return createEmptySetMethod(desc, "property.not.writable", false); } // Otherwise, forget the found property @@ -1801,7 +1800,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } if (find != null) { - if(!find.isWritable()) { + if(!find.getProperty().isWritable()) { // Existing, non-writable property return createEmptySetMethod(desc, "property.not.writable", true); } @@ -2617,7 +2616,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr MethodHandle setter; if (f != null) { - if (!f.isWritable()) { + if (!f.getProperty().isWritable()) { if (strict) { typeError("property.not.writable", key, ScriptRuntime.safeToString(this)); } @@ -3120,7 +3119,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return true; } - if (!find.isConfigurable()) { + if (!find.getProperty().isConfigurable()) { if (strict) { typeError("cant.delete.property", propName, ScriptRuntime.safeToString(this)); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/SpillProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/SpillProperty.java index 98e04de0067..90f5f8bfc1f 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/SpillProperty.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/SpillProperty.java @@ -42,9 +42,6 @@ import jdk.nashorn.internal.runtime.linker.Lookup; public final class SpillProperty extends AccessorProperty { private static final MethodHandle SPILLGETTER = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class), Lookup.GET_OBJECT_TYPE); - /** Property slot in spill */ - private final int slot; - /** * Constructor * @@ -55,14 +52,11 @@ public final class SpillProperty extends AccessorProperty { * @param setter setter for property, or null if not configurable and writable */ public SpillProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) { - super(key, flags, getter, setter); - this.slot = slot; + super(key, flags, slot, getter, setter); } private SpillProperty(final SpillProperty property) { super(property); - - this.slot = property.slot; } @Override @@ -88,31 +82,4 @@ public final class SpillProperty extends AccessorProperty { return super.getSetter(type, currentMap); } - @Override - public int getSlot() { - return slot; - } - - @Override - public String toString() { - return super.toString() + '[' + slot + ']'; - } - - @Override - public int hashCode() { - return super.hashCode() ^ slot; - } - - @Override - public boolean equals(final Object other) { - if (this == other) { - return true; - } - - if (other instanceof SpillProperty) { - return super.equals(other) && slot == ((SpillProperty) other).slot; - } - - return false; - } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java index 6bb053a1036..c4c6f60e511 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java @@ -60,7 +60,7 @@ public final class UserAccessorProperty extends Property { * @param setterSlot setter slot, starting at first embed */ public UserAccessorProperty(final String key, final int flags, final int getterSlot, final int setterSlot) { - super(key, flags); + super(key, flags, -1); this.getterSlot = getterSlot; this.setterSlot = setterSlot; } @@ -95,17 +95,13 @@ public final class UserAccessorProperty extends Property { @Override public boolean equals(final Object other) { - if (this == other) { - return true; + if (!super.equals(other)) { + return false; } - if (other instanceof UserAccessorProperty) { - final UserAccessorProperty uc = (UserAccessorProperty) other; - return super.equals(other) && getterSlot == uc.getterSlot && setterSlot == uc.setterSlot; - } - - return false; - } + final UserAccessorProperty uc = (UserAccessorProperty) other; + return getterSlot == uc.getterSlot && setterSlot == uc.setterSlot; + } @Override public int hashCode() { @@ -158,6 +154,6 @@ public final class UserAccessorProperty extends Property { public ScriptFunction getSetterFunction(final ScriptObject obj) { final Object value = obj.getEmbedOrSpill(setterSlot); return (value instanceof ScriptFunction) ? (ScriptFunction) value : null; - } + } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/Lookup.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/Lookup.java index 44f195ad2d0..c47a0f7984c 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/Lookup.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/Lookup.java @@ -160,7 +160,7 @@ public final class Lookup { throw new IllegalArgumentException("getter/setter has wrong arguments"); } - return map.newProperty(key, flags, getter, setter); + return map.newProperty(key, flags, -1, getter, setter); } /** From 710f06674d267cb32a1321532a58b8f68e0eff26 Mon Sep 17 00:00:00 2001 From: Attila Szegedi Date: Sat, 9 Feb 2013 16:58:48 +0100 Subject: [PATCH 129/311] 8006943: Fix order of function method arguments to be (callee, thisObject) Reviewed-by: jlaskey, lagergren --- .../jdk/nashorn/internal/codegen/Attr.java | 2 +- .../internal/codegen/CodeGenerator.java | 14 +- .../internal/codegen/CompilerConstants.java | 13 +- .../internal/codegen/FunctionSignature.java | 34 ++-- .../internal/codegen/MethodEmitter.java | 23 ++- .../codegen/objects/ObjectClassGenerator.java | 12 +- .../internal/codegen/types/ObjectType.java | 5 - .../internal/objects/ScriptFunctionImpl.java | 3 +- .../jdk/nashorn/internal/runtime/Context.java | 4 +- .../internal/runtime/ScriptFunction.java | 175 +++++++++++------- .../internal/runtime/ScriptFunctionData.java | 43 +++-- 11 files changed, 196 insertions(+), 132 deletions(-) diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java index 9c2c6fb34f6..bb0f3a2e95a 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java @@ -237,8 +237,8 @@ final class Attr extends NodeOperatorVisitor { functionNode.setFrame(functionNode.pushFrame()); - initThis(functionNode); initCallee(functionNode); + initThis(functionNode); if (functionNode.isVarArg()) { initVarArg(functionNode); } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 1f3e9675516..c8742e67772 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -650,16 +650,16 @@ public final class CodeGenerator extends NodeOperatorVisitor { final String signature = new FunctionSignature(true, callee.needsCallee(), callee.getReturnType(), isVarArg ? null : callee.getParameters()).toString(); + if (callee.needsCallee()) { + new FunctionObjectCreator(CodeGenerator.this, callee).makeObject(method); + } + if (callee.isStrictMode()) { // self is undefined method.loadUndefined(Type.OBJECT); } else { // get global from scope (which is the self) globalInstance(); } - if (callee.needsCallee()) { // TODO: always true - new FunctionObjectCreator(CodeGenerator.this, callee).makeObject(method); // TODO: if callee not needed, function object is used only to pass scope (could be optimized). if neither the scope nor the function object is needed by the callee, we can pass null instead. - } - loadArgs(args, signature, isVarArg, argCount); method.invokeStatic(callee.getCompileUnit().getUnitClassName(), callee.getName(), signature); assert method.peekType().equals(callee.getReturnType()) : method.peekType() + " != " + callee.getReturnType(); @@ -1646,8 +1646,8 @@ public final class CodeGenerator extends NodeOperatorVisitor { final Class rtype = fn.getReturnType().getTypeClass(); final boolean needsArguments = fn.needsArguments(); final Class[] ptypes = needsArguments ? - new Class[] {Object.class, ScriptFunction.class, ScriptObject.class, Object.class} : - new Class[] {Object.class, ScriptFunction.class, ScriptObject.class}; + new Class[] {ScriptFunction.class, Object.class, ScriptObject.class, Object.class} : + new Class[] {ScriptFunction.class, Object.class, ScriptObject.class}; setCurrentCompileUnit(splitCompileUnit); splitNode.setCompileUnit(splitCompileUnit); @@ -1669,12 +1669,12 @@ public final class CodeGenerator extends NodeOperatorVisitor { splitNode.setMethodEmitter(method); final MethodEmitter caller = splitNode.getCaller(); - caller.loadThis(); if(fn.needsCallee()) { caller.loadCallee(); } else { caller.loadNull(); } + caller.loadThis(); caller.loadScope(); if (needsArguments) { caller.loadArguments(); diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java index a77bd0b53f5..68bafc20704 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java @@ -82,8 +82,12 @@ public enum CompilerConstants { /** method name for Java method that is script entry point */ RUN_SCRIPT("runScript"), - /** this name and slot */ - THIS("this", 0), + /** + * "this" name symbol for a parameter representing ECMAScript "this" in static methods that are compiled + * representations of ECMAScript functions. It is not assigned a slot, as its position in the method signature is + * dependent on other factors (most notably, callee can precede it). + */ + THIS("this"), /** this debugger symbol */ THIS_DEBUGGER("__this__"), @@ -95,7 +99,7 @@ public enum CompilerConstants { SCRIPT_RETURN("__return__"), /** the callee value variable when necessary */ - CALLEE("__callee__", ScriptFunction.class, 1), + CALLEE("__callee__", ScriptFunction.class), /** the varargs variable when necessary */ VARARGS("__varargs__"), @@ -127,6 +131,9 @@ public enum CompilerConstants { /** prefix for regexps */ REGEX_PREFIX("$regex"), + /** "this" used in non-static Java methods; always in slot 0 */ + JAVA_THIS("this", 0), + /** init scope */ INIT_SCOPE("$scope", 2), diff --git a/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java b/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java index 818c7129156..7bb7747e547 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java @@ -25,9 +25,6 @@ package jdk.nashorn.internal.codegen; -import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE; -import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; - import java.util.List; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.FunctionNode; @@ -99,34 +96,31 @@ public final class FunctionSignature { count = isVarArg ? 1 : argTypes.length; } - int first = 0; - - if (hasSelf) { - count++; - first++; - } if (hasCallee) { count++; - first++; + } + if (hasSelf) { + count++; } paramTypes = new Type[count]; - if (hasSelf) { - paramTypes[THIS.slot()] = Type.OBJECT; - } + int next = 0; if (hasCallee) { - paramTypes[CALLEE.slot()] = Type.typeFor(ScriptFunction.class); + paramTypes[next++] = Type.typeFor(ScriptFunction.class); + } + + if (hasSelf) { + paramTypes[next++] = Type.OBJECT; } if (isVarArg) { - paramTypes[first] = Type.OBJECT_ARRAY; + paramTypes[next] = Type.OBJECT_ARRAY; } else if (argTypes != null) { - for (int i = first, j = 0; i < count; i++, j++) { - paramTypes[i] = argTypes[j]; - if (paramTypes[i].isObject()) { - paramTypes[i] = Type.OBJECT; //TODO: for now, turn java/lang/String into java/lang/Object as we aren't as specific. - } + for (int j = 0; next < count;) { + final Type type = argTypes[j++]; + // TODO: for now, turn java/lang/String into java/lang/Object as we aren't as specific. + paramTypes[next++] = type.isObject() ? Type.OBJECT : type; } } else { assert false : "isVarArgs cannot be false when argTypes are null"; diff --git a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java index e87468bacc9..8553f9a9dd7 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java @@ -831,7 +831,8 @@ public class MethodEmitter implements Emitter { if (symbol.hasSlot()) { final int slot = symbol.getSlot(); debug("load symbol", symbol.getName(), " slot=", slot); - pushType(symbol.getSymbolType().load(method, slot)); + final Type type = symbol.getSymbolType().load(method, slot); + pushType(type == Type.OBJECT && symbol.isThis() ? Type.THIS : type); } else if (symbol.isParam()) { assert !symbol.isScope(); assert functionNode.isVarArg() : "Non-vararg functions have slotted parameters"; @@ -865,10 +866,21 @@ public class MethodEmitter implements Emitter { */ public MethodEmitter load(final Type type, final int slot) { debug("explicit load", type, slot); - pushType(type.load(method, slot)); + final Type loadType = type.load(method, slot); + pushType(loadType == Type.OBJECT && isThisSlot(slot) ? Type.THIS : loadType); return this; } + private boolean isThisSlot(final int slot) { + if(functionNode == null) { + return slot == CompilerConstants.JAVA_THIS.slot(); + } + final int thisSlot = functionNode.getThisNode().getSymbol().getSlot(); + assert !functionNode.needsCallee() || thisSlot == 1; // needsCallee -> thisSlot == 1 + assert functionNode.needsCallee() || thisSlot == 0; // !needsCallee -> thisSlot == 0 + return slot == thisSlot; + } + /** * Push the this object to the stack. * @@ -949,10 +961,11 @@ public class MethodEmitter implements Emitter { * @return the method emitter */ public MethodEmitter loadCallee() { - debug("load callee " + functionNode.getCalleeNode().getSymbol()); - assert functionNode.getCalleeNode().getSymbol().getSlot() != 0 : "callee has wrong slot " + functionNode.getCalleeNode().getSymbol().getSlot() + " in " + functionNode.getName(); + final Symbol calleeSymbol = functionNode.getCalleeNode().getSymbol(); + debug("load callee ", calleeSymbol); + assert calleeSymbol.getSlot() == 0 : "callee has wrong slot " + calleeSymbol.getSlot() + " in " + functionNode.getName(); - return load(functionNode.getCalleeNode().getSymbol()); + return load(calleeSymbol); } /** diff --git a/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectClassGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectClassGenerator.java index 813152b8ba7..3c69687ae4d 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectClassGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectClassGenerator.java @@ -29,9 +29,9 @@ import static jdk.nashorn.internal.codegen.Compiler.SCRIPTS_PACKAGE; import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE; import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_ARGUMENTS; import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_SCOPE; +import static jdk.nashorn.internal.codegen.CompilerConstants.JAVA_THIS; import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_PREFIX; import static jdk.nashorn.internal.codegen.CompilerConstants.MAP; -import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; import static jdk.nashorn.internal.codegen.CompilerConstants.className; import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; import static jdk.nashorn.internal.runtime.linker.Lookup.MH; @@ -251,7 +251,7 @@ public final class ObjectClassGenerator { // always initialize fields to undefined, even with --dual-fields. Then it's ok to // remember things like "widest set type" in properties, and if it's object, don't // add any special "return undefined" getters, saving an invalidation - init.load(Type.OBJECT, THIS.slot()); + init.load(Type.OBJECT, JAVA_THIS.slot()); init.loadUndefined(Type.OBJECT); final Iterator iter = fieldNames.iterator(); @@ -387,7 +387,7 @@ public final class ObjectClassGenerator { private static MethodEmitter newInitMethod(final ClassEmitter classEmitter) { final MethodEmitter init = classEmitter.init(PropertyMap.class); init.begin(); - init.load(Type.OBJECT, THIS.slot()); + init.load(Type.OBJECT, JAVA_THIS.slot()); init.load(Type.OBJECT, MAP.slot()); init.invoke(constructorNoLookup(ScriptObject.class, PropertyMap.class)); @@ -402,7 +402,7 @@ public final class ObjectClassGenerator { private static MethodEmitter newInitScopeMethod(final ClassEmitter classEmitter) { final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class); init.begin(); - init.load(Type.OBJECT, THIS.slot()); + init.load(Type.OBJECT, JAVA_THIS.slot()); init.load(Type.OBJECT, MAP.slot()); init.load(Type.OBJECT, INIT_SCOPE.slot()); init.invoke(constructorNoLookup(FunctionScope.class, PropertyMap.class, ScriptObject.class)); @@ -418,7 +418,7 @@ public final class ObjectClassGenerator { private static MethodEmitter newInitScopeWithArgumentsMethod(final ClassEmitter classEmitter) { final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class, Object.class); init.begin(); - init.load(Type.OBJECT, THIS.slot()); + init.load(Type.OBJECT, JAVA_THIS.slot()); init.load(Type.OBJECT, MAP.slot()); init.load(Type.OBJECT, INIT_SCOPE.slot()); init.load(Type.OBJECT, INIT_ARGUMENTS.slot()); @@ -436,7 +436,7 @@ public final class ObjectClassGenerator { private static void newEmptyInit(final ClassEmitter classEmitter, final String className) { final MethodEmitter emptyInit = classEmitter.init(); emptyInit.begin(); - emptyInit.load(Type.OBJECT, THIS.slot()); + emptyInit.load(Type.OBJECT, JAVA_THIS.slot()); emptyInit.loadNull(); emptyInit.invoke(constructorNoLookup(className, PropertyMap.class)); emptyInit.returnVoid(); diff --git a/nashorn/src/jdk/nashorn/internal/codegen/types/ObjectType.java b/nashorn/src/jdk/nashorn/internal/codegen/types/ObjectType.java index 05fd21f1e75..cb2f876bfc2 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/types/ObjectType.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/types/ObjectType.java @@ -74,11 +74,6 @@ class ObjectType extends Type { public Type load(final MethodVisitor method, final int slot) { assert slot != -1; method.visitVarInsn(ALOAD, slot); - - if (slot == CompilerConstants.THIS.slot()) { - return Type.THIS; - } - return Type.OBJECT; } diff --git a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java index c84d8deab61..f3b4a665908 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java +++ b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java @@ -30,13 +30,12 @@ import static jdk.nashorn.internal.runtime.linker.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; - -import jdk.nashorn.internal.runtime.ScriptFunctionData; import jdk.nashorn.internal.codegen.objects.FunctionObjectCreator; import jdk.nashorn.internal.runtime.GlobalFunctions; import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.ScriptFunction; +import jdk.nashorn.internal.runtime.ScriptFunctionData; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.linker.Lookup; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index 6e04247b18d..46a3a7b7197 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -886,8 +886,8 @@ public final class Context { RUN_SCRIPT.tag(), MH.type( Object.class, - Object.class, - ScriptFunction.class)); + ScriptFunction.class, + Object.class)); boolean strict; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java index 2fbe3ee0cf5..4542c8f7ebd 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java @@ -210,7 +210,7 @@ public abstract class ScriptFunction extends ScriptObject { if (data.isVarArg()) { if (data.needsCallee()) { - return invoker.invokeExact(selfObj, this, args); + return invoker.invokeExact(this, selfObj, args); } return invoker.invokeExact(selfObj, args); } @@ -219,15 +219,15 @@ public abstract class ScriptFunction extends ScriptObject { if (data.needsCallee()) { switch (paramCount) { case 2: - return invoker.invokeExact(selfObj, this); + return invoker.invokeExact(this, selfObj); case 3: - return invoker.invokeExact(selfObj, this, getArg(args, 0)); + return invoker.invokeExact(this, selfObj, getArg(args, 0)); case 4: - return invoker.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1)); + return invoker.invokeExact(this, selfObj, getArg(args, 0), getArg(args, 1)); case 5: - return invoker.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + return invoker.invokeExact(this, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); default: - return invoker.invokeWithArguments(withArguments(selfObj, this, paramCount, args)); + return invoker.invokeWithArguments(withArguments(selfObj, paramCount, args)); } } @@ -241,7 +241,7 @@ public abstract class ScriptFunction extends ScriptObject { case 4: return invoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); default: - return invoker.invokeWithArguments(withArguments(selfObj, null, paramCount, args)); + return invoker.invokeWithArguments(withArguments(selfObj, paramCount, args)); } } @@ -264,7 +264,7 @@ public abstract class ScriptFunction extends ScriptObject { final MethodHandle constructor = data.getGenericConstructor(); if (data.isVarArg()) { if (data.needsCallee()) { - return constructor.invokeExact(self, this, args); + return constructor.invokeExact(this, self, args); } return constructor.invokeExact(self, args); } @@ -273,15 +273,15 @@ public abstract class ScriptFunction extends ScriptObject { if (data.needsCallee()) { switch (paramCount) { case 2: - return constructor.invokeExact(self, this); + return constructor.invokeExact(this, self); case 3: - return constructor.invokeExact(self, this, getArg(args, 0)); + return constructor.invokeExact(this, self, getArg(args, 0)); case 4: - return constructor.invokeExact(self, this, getArg(args, 0), getArg(args, 1)); + return constructor.invokeExact(this, self, getArg(args, 0), getArg(args, 1)); case 5: - return constructor.invokeExact(self, this, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + return constructor.invokeExact(this, self, getArg(args, 0), getArg(args, 1), getArg(args, 2)); default: - return constructor.invokeWithArguments(withArguments(self, this, args)); + return constructor.invokeWithArguments(withArguments(self, args)); } } @@ -295,31 +295,30 @@ public abstract class ScriptFunction extends ScriptObject { case 4: return constructor.invokeExact(self, getArg(args, 0), getArg(args, 1), getArg(args, 2)); default: - return constructor.invokeWithArguments(withArguments(self, null, args)); + return constructor.invokeWithArguments(withArguments(self, args)); } } - private static Object[] withArguments(final Object self, final ScriptFunction function, final Object... args) { - return withArguments(self, function, args.length + (function == null ? 1 : 2), args); // + 2 to include self and function + private Object[] withArguments(final Object self, final Object[] args) { + return withArguments(self, args.length + (data.needsCallee() ? 2 : 1), args); } - private static Object[] withArguments(final Object self, final ScriptFunction function, final int paramCount, final Object... args) { - final Object[] finalArgs = new Object[paramCount]; + private Object[] withArguments(final Object self, final int argCount, final Object[] args) { + final Object[] finalArgs = new Object[argCount]; - finalArgs[0] = self; - int nextArg = 1; - if (function != null) { - finalArgs[nextArg++] = function; + int nextArg = 0; + if (data.needsCallee()) { + finalArgs[nextArg++] = this; } + finalArgs[nextArg++] = self; - //don't add more args that there is paramcount in the handle (including self) - final int maxArgs = Math.min(args.length, paramCount - (function == null ? 1 : 2)); - for (int i = 0; i < maxArgs;) { + // Don't add more args that there is argCount in the handle (including self and callee). + for (int i = 0; i < args.length && nextArg < argCount;) { finalArgs[nextArg++] = args[i++]; } - //if we have fewer params than paramcount, pad undefined - while (nextArg < paramCount) { + // If we have fewer args than argCount, pad with undefined. + while (nextArg < argCount) { finalArgs[nextArg++] = UNDEFINED; } @@ -512,10 +511,18 @@ public abstract class ScriptFunction extends ScriptObject { * @return bound invoke handle */ public final MethodHandle getBoundInvokeHandle(final ScriptObject self) { - final MethodHandle bound = MH.bindTo(getInvokeHandle(), self); - return data.needsCallee() ? MH.bindTo(bound, this) : bound; + return MH.bindTo(bindToCalleeIfNeeded(getInvokeHandle()), self); } + /** + * Bind the method handle to this {@code ScriptFunction} instance if it needs a callee parameter. If this function's + * method handles don't have a callee parameter, the handle is returned unchanged. + * @param methodHandle the method handle to potentially bind to this function instance. + * @return the potentially bound method handle + */ + private MethodHandle bindToCalleeIfNeeded(final MethodHandle methodHandle) { + return data.needsCallee() ? MH.bindTo(methodHandle, this) : methodHandle; + } /** * Get the construct handle - the most generic (and if no specializations are in place, only) constructor @@ -524,7 +531,7 @@ public abstract class ScriptFunction extends ScriptObject { * @param type type for wanted constructor * @return construct handle */ - public final MethodHandle getConstructHandle(final MethodType type) { + private final MethodHandle getConstructHandle(final MethodType type) { return candidateWithLowestWeight(type, getConstructHandle(), data.getConstructSpecializations()); } @@ -537,8 +544,8 @@ public abstract class ScriptFunction extends ScriptObject { } /** - * Set a method handle to the constructor for this function - * @param constructHandle constructor handle + * Set a method handle to the constructor for this function. + * @param constructHandle constructor handle. Can be null to prevent the function from being used as a constructor. */ public final void setConstructHandle(final MethodHandle constructHandle) { data.setConstructor(constructHandle); @@ -674,7 +681,11 @@ public abstract class ScriptFunction extends ScriptObject { @Override protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc) { + // Call site type is (callee, args...) - dyn:new doesn't specify a "this", it's our job to allocate it final MethodType type = desc.getMethodType(); + + // Constructor arguments are either (callee, this, args...) or (this, args...), depending on whether it needs a + // callee or not. MethodHandle constructor = getConstructHandle(type); if (constructor == null) { @@ -682,18 +693,30 @@ public abstract class ScriptFunction extends ScriptObject { return null; } + // If it was (callee, this, args...), permute it to (this, callee, args...). We're doing this because having + // "this" in the first argument position is what allows the elegant folded composition of + // (newFilter x constructor x allocator) further down below in the code. + constructor = swapCalleeAndThis(constructor); + final MethodType ctorType = constructor.type(); - - // guard against primitive constructor return types - constructor = MH.asType(constructor, constructor.type().changeReturnType(Object.class)); - - // apply new filter - final Class[] ctorArgs = ctorType.dropParameterTypes(0, 1).parameterArray(); // drop self + // Drop constructor "this", so it's also captured as "allocation" parameter of newFilter after we fold the + // constructor into newFilter. + // (this, [callee, ]args...) => ([callee, ]args...) + final Class[] ctorArgs = ctorType.dropParameterTypes(0, 1).parameterArray(); + // Fold constructor into newFilter that replaces the return value from the constructor with the originally + // allocated value when the originally allocated value is a primitive. + // (result, this, [callee, ]args...) x (this, [callee, ]args...) => (this, [callee, ]args...) MethodHandle handle = MH.foldArguments(MH.dropArguments(NEWFILTER, 2, ctorArgs), constructor); + // allocate() takes a ScriptFunction and returns a newly allocated ScriptObject... if (data.needsCallee()) { + // ...we either fold it into the previous composition, if we need both the ScriptFunction callee object and + // the newly allocated object in the arguments, so (this, callee, args...) x (callee) => (callee, args...), + // or... handle = MH.foldArguments(handle, ALLOCATE); } else { + // ...replace the ScriptFunction argument with the newly allocated object, if it doesn't need the callee + // (this, args...) filter (callee) => (callee, args...) handle = MH.filterArguments(handle, 0, ALLOCATE); } @@ -701,6 +724,30 @@ public abstract class ScriptFunction extends ScriptObject { return new GuardedInvocation(filterIn, null, NashornGuards.getFunctionGuard(this)); } + /** + * If this function's method handles need a callee parameter, swap the order of first two arguments for the passed + * method handle. If this function's method handles don't need a callee parameter, returns the original method + * handle unchanged. + * @param mh a method handle with order of arguments {@code (callee, this, args...)} + * @return a method handle with order of arguments {@code (this, callee, args...)} + */ + private MethodHandle swapCalleeAndThis(final MethodHandle mh) { + if (!data.needsCallee()) { + return mh; + } + final MethodType type = mh.type(); + assert type.parameterType(0) == ScriptFunction.class; + assert type.parameterType(1) == Object.class; + final MethodType newType = type.changeParameterType(0, Object.class).changeParameterType(1, ScriptFunction.class); + final int[] reorder = new int[type.parameterCount()]; + reorder[0] = 1; + assert reorder[1] == 0; + for (int i = 2; i < reorder.length; ++i) { + reorder[i] = i; + } + return MethodHandles.permuteArguments(mh, newType, reorder); + } + @SuppressWarnings("unused") private static Object newFilter(final Object result, final Object allocation) { return (result instanceof ScriptObject || !JSType.isPrimitive(result))? result : allocation; @@ -716,7 +763,7 @@ public abstract class ScriptFunction extends ScriptObject { /** * dyn:call call site signature: (callee, thiz, [args...]) - * generated method signature: (thiz, callee, [args...]) + * generated method signature: (callee, thiz, [args...]) * * cases: * (a) method has callee parameter @@ -735,8 +782,10 @@ public abstract class ScriptFunction extends ScriptObject { final MethodHandle collector = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class, type.parameterCount() - 2); - return new GuardedInvocation(collector, - desc.getMethodType().parameterType(0) == ScriptFunction.class ? null : NashornGuards.getScriptFunctionGuard()); + // If call site is statically typed to take a ScriptFunction, we don't need a guard, otherwise we need a + // generic "is this a ScriptFunction?" guard. + return new GuardedInvocation(collector, ScriptFunction.class.isAssignableFrom(desc.getMethodType().parameterType(0)) + ? null : NashornGuards.getScriptFunctionGuard()); } MethodHandle boundHandle; @@ -745,21 +794,15 @@ public abstract class ScriptFunction extends ScriptObject { if (data.needsCallee()) { final MethodHandle callHandle = getBestSpecializedInvokeHandle(type); - if(NashornCallSiteDescriptor.isScope(desc)) { - // (this, callee, args...) => (callee, args...) => (callee, [this], args...) - boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED); + if (NashornCallSiteDescriptor.isScope(desc)) { + // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined + // (callee, this, args...) => (callee, args...) + boundHandle = MH.insertArguments(callHandle, 1, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED); + // (callee, args...) => (callee, [this], args...) boundHandle = MH.dropArguments(boundHandle, 1, Object.class); } else { - // (this, callee, args...) permute => (callee, this, args...) which is what we get in - final MethodType oldType = callHandle.type(); - final int[] reorder = new int[oldType.parameterCount()]; - for (int i = 2; i < reorder.length; i++) { - reorder[i] = i; - } - reorder[0] = 1; - assert reorder[1] == 0; - final MethodType newType = oldType.changeParameterType(0, oldType.parameterType(1)).changeParameterType(1, oldType.parameterType(0)); - boundHandle = MethodHandles.permuteArguments(callHandle, newType, reorder); + // It's already (callee, this, args...), just what we need + boundHandle = callHandle; // For non-strict functions, check whether this-object is primitive type. // If so add a to-object-wrapper argument filter. @@ -775,10 +818,14 @@ public abstract class ScriptFunction extends ScriptObject { } else { final MethodHandle callHandle = getBestSpecializedInvokeHandle(type.dropParameterTypes(0, 1)); - if(NashornCallSiteDescriptor.isScope(desc)) { + if (NashornCallSiteDescriptor.isScope(desc)) { + // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined + // (this, args...) => (args...) boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED); + // (args...) => ([callee], [this], args...) boundHandle = MH.dropArguments(boundHandle, 0, Object.class, Object.class); } else { + // (this, args...) => ([callee], this, args...) boundHandle = MH.dropArguments(callHandle, 0, Object.class); } } @@ -793,21 +840,11 @@ public abstract class ScriptFunction extends ScriptObject { * These don't want a callee parameter, so bind that. Name binding is optional. */ MethodHandle getCallMethodHandle(final MethodType type, final String bindName) { - MethodHandle methodHandle = getBestSpecializedInvokeHandle(type); + return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(getBestSpecializedInvokeHandle(type)), bindName), type); + } - if (bindName != null) { - if (data.needsCallee()) { - methodHandle = MH.insertArguments(methodHandle, 1, this, bindName); - } else { - methodHandle = MH.insertArguments(methodHandle, 1, bindName); - } - } else { - if (data.needsCallee()) { - methodHandle = MH.insertArguments(methodHandle, 1, this); - } - } - - return pairArguments(methodHandle, type); + private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) { + return bindName == null ? methodHandle : MH.insertArguments(methodHandle, 1, bindName); } /** diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java index 65dbd6375b5..c72037c24a0 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java @@ -25,14 +25,13 @@ package jdk.nashorn.internal.runtime; -import jdk.nashorn.internal.ir.FunctionNode; -import jdk.nashorn.internal.parser.Token; -import jdk.nashorn.internal.parser.TokenType; +import static jdk.nashorn.internal.runtime.linker.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; - -import static jdk.nashorn.internal.runtime.linker.Lookup.MH; +import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.parser.Token; +import jdk.nashorn.internal.parser.TokenType; /** * A container for data needed to instantiate a specific {@link ScriptFunction} at runtime. @@ -129,19 +128,19 @@ public class ScriptFunctionData { * constructor or not if the method handle's first argument is boolean. */ this.invoker = MH.insertArguments(methodHandle, 0, false); - this.constructor = MH.insertArguments(methodHandle, 0, true); + this.constructor = adaptConstructor(MH.insertArguments(methodHandle, 0, true)); if (specs != null) { this.invokeSpecializations = new MethodHandle[specs.length]; this.constructSpecializations = new MethodHandle[specs.length]; for (int i = 0; i < specs.length; i++) { this.invokeSpecializations[i] = MH.insertArguments(specs[i], 0, false); - this.constructSpecializations[i] = MH.insertArguments(specs[i], 0, true); + this.constructSpecializations[i] = adaptConstructor(MH.insertArguments(specs[i], 0, true)); } } } else { this.invoker = methodHandle; - this.constructor = methodHandle; + this.constructor = adaptConstructor(methodHandle); this.invokeSpecializations = specs; this.constructSpecializations = specs; } @@ -353,7 +352,7 @@ public class ScriptFunctionData { // and they're set when first called, so we enforce set-once here. if (this.invoker == null) { this.invoker = invoker; - this.constructor = invoker; + this.constructor = adaptConstructor(invoker); this.allocator = allocator; } } @@ -408,9 +407,9 @@ public class ScriptFunctionData { return false; } if(type.parameterType(0) == boolean.class) { - return len > 2 && type.parameterType(2) == ScriptFunction.class; + return len > 1 && type.parameterType(1) == ScriptFunction.class; } - return len > 1 && type.parameterType(1) == ScriptFunction.class; + return type.parameterType(0) == ScriptFunction.class; } /** @@ -434,9 +433,29 @@ public class ScriptFunctionData { newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class); } if (needsCallee()) { - newType = newType.changeParameterType(1, ScriptFunction.class); + newType = newType.changeParameterType(0, ScriptFunction.class); } return type.equals(newType) ? handle : handle.asType(newType); } + /** + * Adapts a method handle to conform to requirements of a constructor. Right now this consists of making sure its + * return value is {@code Object}. We might consider moving the caller-this argument swap here too from + * {@link ScriptFunction#findNewMethod(org.dynalang.dynalink.CallSiteDescriptor)}. + * @param ctorHandle the constructor method handle + * @return adapted constructor method handle + */ + private static MethodHandle adaptConstructor(final MethodHandle ctorHandle) { + return changeReturnTypeToObject(ctorHandle); + } + + /** + * Adapts the method handle so its return type is {@code Object}. If the handle's return type is already + * {@code Object}, the handle is returned unchanged. + * @param mh the handle to adapt + * @return the adapted handle + */ + private static MethodHandle changeReturnTypeToObject(final MethodHandle mh) { + return MH.asType(mh, mh.type().changeReturnType(Object.class)); + } } From 1e1537c13f84a7daaaa6aa429bdf90b995945a9a Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Mon, 11 Feb 2013 21:26:06 +0530 Subject: [PATCH 130/311] 8007915: Nashorn IR, codegen, parser packages and Context instance should be inaccessible to user code Reviewed-by: lagergren, jlaskey, attila --- nashorn/bin/jjssecure | 2 +- nashorn/bin/jjssecure.bat | 2 +- nashorn/bin/nashornsecure | 2 +- nashorn/bin/nashornsecure.bat | 2 +- nashorn/make/Makefile | 2 +- nashorn/make/build.xml | 4 +- nashorn/make/java.security.override | 14 ++ nashorn/make/project.properties | 2 +- .../jdk/nashorn/internal/codegen/Attr.java | 1 + .../internal/codegen/CodeGenerator.java | 2 +- .../nashorn/internal/codegen/Compiler.java | 3 + .../internal/codegen/RuntimeCallSite.java | 20 +- .../src/jdk/nashorn/internal/ir/Symbol.java | 2 +- .../nashorn/internal/ir/debug/JSONWriter.java | 10 +- .../objects/AccessorPropertyDescriptor.java | 2 +- .../objects/DataPropertyDescriptor.java | 2 +- .../objects/GenericPropertyDescriptor.java | 2 +- .../jdk/nashorn/internal/objects/Global.java | 33 ++- .../nashorn/internal/objects/NativeArray.java | 4 +- .../internal/objects/NativeArrayBuffer.java | 2 +- .../nashorn/internal/objects/NativeDebug.java | 6 +- .../nashorn/internal/objects/NativeError.java | 2 +- .../internal/objects/NativeEvalError.java | 2 +- .../internal/objects/NativeFloat32Array.java | 2 +- .../internal/objects/NativeFloat64Array.java | 2 +- .../internal/objects/NativeFunction.java | 2 +- .../internal/objects/NativeInt16Array.java | 2 +- .../internal/objects/NativeInt32Array.java | 2 +- .../internal/objects/NativeInt8Array.java | 2 +- .../internal/objects/NativeJSAdapter.java | 2 +- .../nashorn/internal/objects/NativeJSON.java | 173 +------------- .../nashorn/internal/objects/NativeJava.java | 2 +- .../internal/objects/NativeJavaImporter.java | 4 +- .../internal/objects/NativeRangeError.java | 2 +- .../objects/NativeReferenceError.java | 2 +- .../internal/objects/NativeRegExp.java | 2 +- .../objects/NativeRegExpExecResult.java | 2 +- .../internal/objects/NativeString.java | 5 +- .../internal/objects/NativeSyntaxError.java | 2 +- .../internal/objects/NativeTypeError.java | 2 +- .../internal/objects/NativeURIError.java | 2 +- .../internal/objects/NativeUint16Array.java | 2 +- .../internal/objects/NativeUint32Array.java | 2 +- .../internal/objects/NativeUint8Array.java | 2 +- .../objects/NativeUint8ClampedArray.java | 2 +- .../internal/objects/ScriptFunctionImpl.java | 12 +- .../internal/parser/AbstractParser.java | 1 + .../jdk/nashorn/internal/parser/Lexer.java | 2 +- .../internal/runtime/ArgumentSetter.java | 3 +- .../nashorn/internal/runtime/BitVector.java | 2 +- .../nashorn/internal/runtime/ConsString.java | 2 +- .../jdk/nashorn/internal/runtime/Context.java | 22 +- .../jdk/nashorn/internal/runtime/Debug.java | 2 +- .../nashorn/internal/runtime/DebugLogger.java | 2 +- .../internal/runtime/GlobalFunctions.java | 2 +- .../internal/runtime/JSONFunctions.java | 224 ++++++++++++++++++ .../jdk/nashorn/internal/runtime/Logging.java | 2 +- .../internal/runtime/NashornLoader.java | 13 +- .../internal/runtime/NativeJavaPackage.java | 2 +- .../internal/{parser => runtime}/RegExp.java | 5 +- .../{parser => runtime}/RegExpScanner.java | 7 +- .../internal/runtime/ScriptFunction.java | 2 +- .../internal/runtime/ScriptFunctionData.java | 2 +- .../internal/runtime/ScriptLoader.java | 21 +- .../internal/runtime/ScriptObject.java | 2 +- .../internal/runtime/ScriptRuntime.java | 28 +++ .../internal/runtime/ScriptingFunctions.java | 4 +- .../internal/runtime/SetMethodCreator.java | 2 +- .../internal/runtime/StructureLoader.java | 13 +- .../nashorn/internal/runtime/WithObject.java | 2 +- .../arrays/EmptyArrayLikeIterator.java | 4 +- .../internal/runtime/arrays/MapIterator.java | 7 +- .../internal/runtime/linker/Bootstrap.java | 16 ++ .../internal/runtime/resources/parser.js | 2 +- .../test/script/sandbox/nashorninternals.js | 57 +++++ nashorn/test/script/trusted/JDK-8006529.js | 85 +++++-- .../javaaccess}/BooleanAccessTest.java | 2 +- .../javaaccess}/MethodAccessTest.java | 2 +- .../javaaccess}/NumberAccessTest.java | 2 +- .../javaaccess}/NumberBoxingTest.java | 2 +- .../javaaccess}/ObjectAccessTest.java | 2 +- .../access => api/javaaccess}/Person.java | 2 +- .../javaaccess}/SharedObject.java | 2 +- .../javaaccess}/StringAccessTest.java | 2 +- .../internal/codegen/CompilerAccess.java | 35 --- 85 files changed, 559 insertions(+), 385 deletions(-) create mode 100644 nashorn/make/java.security.override create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java rename nashorn/src/jdk/nashorn/internal/{parser => runtime}/RegExp.java (96%) rename nashorn/src/jdk/nashorn/internal/{parser => runtime}/RegExpScanner.java (99%) create mode 100644 nashorn/test/script/sandbox/nashorninternals.js rename nashorn/test/src/jdk/nashorn/{internal/access => api/javaaccess}/BooleanAccessTest.java (99%) rename nashorn/test/src/jdk/nashorn/{internal/access => api/javaaccess}/MethodAccessTest.java (99%) rename nashorn/test/src/jdk/nashorn/{internal/access => api/javaaccess}/NumberAccessTest.java (99%) rename nashorn/test/src/jdk/nashorn/{internal/access => api/javaaccess}/NumberBoxingTest.java (99%) rename nashorn/test/src/jdk/nashorn/{internal/access => api/javaaccess}/ObjectAccessTest.java (99%) rename nashorn/test/src/jdk/nashorn/{internal/access => api/javaaccess}/Person.java (97%) rename nashorn/test/src/jdk/nashorn/{internal/access => api/javaaccess}/SharedObject.java (99%) rename nashorn/test/src/jdk/nashorn/{internal/access => api/javaaccess}/StringAccessTest.java (99%) delete mode 100644 nashorn/test/src/jdk/nashorn/internal/codegen/CompilerAccess.java diff --git a/nashorn/bin/jjssecure b/nashorn/bin/jjssecure index 93d38218ac6..614ffd36213 100644 --- a/nashorn/bin/jjssecure +++ b/nashorn/bin/jjssecure @@ -26,4 +26,4 @@ [ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1; -$JAVA_HOME/bin/java -Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -XX:+HeapDumpOnOutOfMemoryError -Dnashorn.debug=true -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=true -Dnashorn.home=`dirname $0`/.. -Djava.security.manager jdk.nashorn.tools.Shell $* +$JAVA_HOME/bin/java -Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -Djava.security.properties=`dirname $0`/../make/java.security.override -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -XX:+HeapDumpOnOutOfMemoryError -Dnashorn.debug=true -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=true -Dnashorn.home=`dirname $0`/.. -Djava.security.manager jdk.nashorn.tools.Shell $* diff --git a/nashorn/bin/jjssecure.bat b/nashorn/bin/jjssecure.bat index 2960cfc0acf..f8da10aaaf6 100644 --- a/nashorn/bin/jjssecure.bat +++ b/nashorn/bin/jjssecure.bat @@ -24,4 +24,4 @@ rem questions. rem @echo off -java -Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -Djava.ext.dirs=%~dp0\..\dist -XX:+HeapDumpOnOutOfMemoryError -Dnashorn.debug=true -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.home=%~dp0\.. -Djava.security.manager jdk.nashorn.tools.Shell +java -Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -Djava.security.properties=%~dp0\..\make\java.security.override -Djava.ext.dirs=%~dp0\..\dist -XX:+HeapDumpOnOutOfMemoryError -Dnashorn.debug=true -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.home=%~dp0\.. -Djava.security.manager jdk.nashorn.tools.Shell diff --git a/nashorn/bin/nashornsecure b/nashorn/bin/nashornsecure index caec38731d0..3d02c5293e5 100644 --- a/nashorn/bin/nashornsecure +++ b/nashorn/bin/nashornsecure @@ -26,4 +26,4 @@ [ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1; -$JAVA_HOME/bin/jrunscript -J-Djava.security.manager -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -J-XX:+HeapDumpOnOutOfMemoryError -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -J-Dnashorn.debug=true -l nashorn $* +$JAVA_HOME/bin/jrunscript -J-Djava.security.properties=`dirname $0`/../make/java.security.override -J-Djava.security.manager -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -J-XX:+HeapDumpOnOutOfMemoryError -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -J-Dnashorn.debug=true -l nashorn $* diff --git a/nashorn/bin/nashornsecure.bat b/nashorn/bin/nashornsecure.bat index d35eeb48f25..5a4eca63c64 100644 --- a/nashorn/bin/nashornsecure.bat +++ b/nashorn/bin/nashornsecure.bat @@ -24,4 +24,4 @@ rem questions. rem @echo off -jrunscript -J-Djava.security.manager -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=%~dp0\..\dist -J-XX:+HeapDumpOnOutOfMemoryError -J-Dnashorn.debug=true -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -l nashorn +jrunscript -J-Djava.security.properties=%~dp0\..\make\java.security.override -J-Djava.security.manager -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=%~dp0\..\dist -J-XX:+HeapDumpOnOutOfMemoryError -J-Dnashorn.debug=true -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -l nashorn diff --git a/nashorn/make/Makefile b/nashorn/make/Makefile index 965c30a43a1..899f9362a82 100644 --- a/nashorn/make/Makefile +++ b/nashorn/make/Makefile @@ -181,7 +181,7 @@ else endif # Default target and expected 'do everything' target -all: test docs +all: test # Standard make clobber target clobber: clean diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml index 04766c17387..fbf9a9e5dd2 100644 --- a/nashorn/make/build.xml +++ b/nashorn/make/build.xml @@ -201,12 +201,12 @@ - + - + diff --git a/nashorn/make/java.security.override b/nashorn/make/java.security.override new file mode 100644 index 00000000000..45f2687a6d7 --- /dev/null +++ b/nashorn/make/java.security.override @@ -0,0 +1,14 @@ +# We would like to avoid references from anywhere outside nashorn +# to codegen, IR and parser packages, in particular script generated classes. +# We ensure that by overriding "package.access" security property. + +# The following "package.access" value was copied from default java.security +# of jre/lib/security and appended with nashorn IR, Codegen and Parser packages. + +# +# List of comma-separated packages that start with or equal this string +# will cause a security exception to be thrown when +# 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.,jdk.nashorn.internal.ir., jdk.nashorn.internal.codegen., jdk.nashorn.internal.parser. diff --git a/nashorn/make/project.properties b/nashorn/make/project.properties index 70107f4caed..544b1e91388 100644 --- a/nashorn/make/project.properties +++ b/nashorn/make/project.properties @@ -225,7 +225,7 @@ run.test.jvmargs=-server -Xmx${run.test.xmx} -XX:-TieredCompilation -esa -ea -Dn #-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M run.test.jvmargs.octane=-Xms${run.test.xms} ${run.test.jvmargs} -run.test.jvmsecurityargs=-Xverify:all -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy +run.test.jvmsecurityargs=-Xverify:all -Djava.security.properties=${basedir}/make/java.security.override -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy # path of rhino.jar for benchmarks rhino.jar= diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java index bb0f3a2e95a..e3bd8ab3881 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java @@ -415,6 +415,7 @@ final class Attr extends NodeOperatorVisitor { symbol.setIsScope(); } + assert symbol != null; if(symbol.isGlobal()) { getCurrentFunctionNode().setUsesGlobalSymbol(); } else if(symbol.isScope()) { diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java index c8742e67772..da7c72147c1 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -3183,6 +3183,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { @Override public Node enter(final IdentNode node) { final Symbol symbol = node.getSymbol(); + assert symbol != null; if (symbol.isScope()) { if (symbol.isFastScope(currentFunction)) { storeFastScopeVar(node.getType(), symbol, CALLSITE_SCOPE | getCallSiteFlags()); @@ -3190,7 +3191,6 @@ public final class CodeGenerator extends NodeOperatorVisitor { method.dynamicSet(node.getType(), node.getName(), CALLSITE_SCOPE | getCallSiteFlags()); } } else { - assert symbol != null; method.store(symbol); } return null; diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java index a70fc6924a2..3b21ab581a7 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java @@ -108,6 +108,9 @@ public final class Compiler { /** Name of the objects package */ public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects"; + /** Name of the runtime package */ + public static final String RUNTIME_PACKAGE = "jdk/nashorn/internal/runtime"; + /** Name of the Global object, cannot be referred to as .class, @see CodeGenerator */ public static final String GLOBAL_OBJECT = OBJECTS_PACKAGE + '/' + "Global"; diff --git a/nashorn/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java b/nashorn/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java index 95b592df98b..96ed8a48a2c 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java @@ -42,6 +42,7 @@ import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.RuntimeNode; import jdk.nashorn.internal.ir.RuntimeNode.Request; import jdk.nashorn.internal.runtime.ScriptRuntime; +import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.Lookup; import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; @@ -55,8 +56,8 @@ import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; * {@code Object a === int b} is a good idea to specialize to {@code ((Integer)a).intValue() == b} * surrounded by catch blocks that will try less narrow specializations */ -public class RuntimeCallSite extends MutableCallSite { - static final Call BOOTSTRAP = staticCallNoLookup(RuntimeCallSite.class, "bootstrap", CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class); +public final class RuntimeCallSite extends MutableCallSite { + static final Call BOOTSTRAP = staticCallNoLookup(Bootstrap.class, "runtimeBootstrap", CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class); private static final MethodHandle NEXT = findOwnMH("next", MethodHandle.class); @@ -200,26 +201,13 @@ public class RuntimeCallSite extends MutableCallSite { * @param type method type for call site * @param name name of runtime call */ - RuntimeCallSite(final MethodType type, final String name) { + public RuntimeCallSite(final MethodType type, final String name) { super(type); this.name = name; this.request = Request.valueOf(name.substring(0, name.indexOf(SpecializedRuntimeNode.REQUEST_SEPARATOR))); setTarget(makeMethod(name)); } - /** - * Bootstrapper for a specialized Runtime call - * - * @param lookup lookup - * @param initialName initial name for callsite - * @param type method type for call site - * - * @return callsite for a runtime node - */ - public static CallSite bootstrap(final MethodHandles.Lookup lookup, final String initialName, final MethodType type) { - return new RuntimeCallSite(type, initialName); - } - private String nextName(final String requestName) { if (requestName.equals(request.toString())) { return null; diff --git a/nashorn/src/jdk/nashorn/internal/ir/Symbol.java b/nashorn/src/jdk/nashorn/internal/ir/Symbol.java index b6d8e9b336b..081df86604d 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/Symbol.java +++ b/nashorn/src/jdk/nashorn/internal/ir/Symbol.java @@ -660,7 +660,7 @@ public final class Symbol implements Comparable { if (TRACE_SYMBOLS != null && (TRACE_SYMBOLS.isEmpty() || TRACE_SYMBOLS.contains(name))) { Context.err("SYMBOL: '" + name + "' " + desc); if (TRACE_SYMBOLS_STACKTRACE != null && (TRACE_SYMBOLS_STACKTRACE.isEmpty() || TRACE_SYMBOLS_STACKTRACE.contains(name))) { - new Throwable().printStackTrace(Context.getContext().getErr()); + new Throwable().printStackTrace(Context.getCurrentErr()); } } } diff --git a/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java b/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java index 122d3edc10c..103670d024a 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java +++ b/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java @@ -80,19 +80,13 @@ public final class JSONWriter extends NodeVisitor { /** * Returns AST as JSON compatible string. * + * @param context nashorn context to use * @param code code to be parsed * @param name name of the code source (used for location) * @param includeLoc tells whether to include location information for nodes or not * @return JSON string representation of AST of the supplied code */ - public static String parse(final String code, final String name, final boolean includeLoc) { - final Context context = AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public Context run() { - return Context.getContext(); - } - }); + public static String parse(final Context context, final String code, final String name, final boolean includeLoc) { final Compiler compiler = Compiler.compiler(new Source(name, code), context, new Context.ThrowErrorManager(), context._strict); final Parser parser = new Parser(compiler, context._strict); final JSONWriter jsonWriter = new JSONWriter(includeLoc); diff --git a/nashorn/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java b/nashorn/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java index 6951c0389fe..bef0a86827d 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java +++ b/nashorn/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java @@ -138,7 +138,7 @@ public final class AccessorPropertyDescriptor extends ScriptObject implements Pr @Override public PropertyDescriptor fillFrom(final ScriptObject sobj) { - final boolean strict = getContext()._strict; + final boolean strict = isStrictContext(); if (sobj.has(CONFIGURABLE)) { this.configurable = JSType.toBoolean(sobj.get(CONFIGURABLE)); diff --git a/nashorn/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java b/nashorn/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java index cfc704765d1..e5f7de318ab 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java +++ b/nashorn/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java @@ -136,7 +136,7 @@ public final class DataPropertyDescriptor extends ScriptObject implements Proper @Override public PropertyDescriptor fillFrom(final ScriptObject sobj) { - final boolean strict = getContext()._strict; + final boolean strict = isStrictContext(); if (sobj.has(CONFIGURABLE)) { this.configurable = JSType.toBoolean(sobj.get(CONFIGURABLE)); } else { diff --git a/nashorn/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java b/nashorn/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java index bd8ad453d5a..f76f7f19878 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java +++ b/nashorn/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java @@ -124,7 +124,7 @@ public final class GenericPropertyDescriptor extends ScriptObject implements Pro @Override public PropertyDescriptor fillFrom(final ScriptObject sobj) { - final boolean strict = getContext()._strict; + final boolean strict = isStrictContext(); if (sobj.has(CONFIGURABLE)) { this.configurable = JSType.toBoolean(sobj.get(CONFIGURABLE)); } else { diff --git a/nashorn/src/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk/nashorn/internal/objects/Global.java index 4ea7fd0979e..d1664d11296 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java @@ -347,10 +347,13 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { private static final MethodHandle LOAD = findOwnMH("load", Object.class, Object.class, Object.class); private static final MethodHandle EXIT = findOwnMH("exit", Object.class, Object.class, Object.class); + private final Context context; + /** * Constructor */ - public Global() { + public Global(final Context context) { + this.context = context; this.setIsScope(); /* * Duplicate global's map and use it. This way the initial Map filled @@ -359,19 +362,23 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { */ this.setMap(getMap().duplicate()); - final int cacheSize = getContext()._class_cache_size; + final int cacheSize = context._class_cache_size; if (cacheSize > 0) { classCache = new ClassCache(cacheSize); } } /** - * Script access to unique context specific Global instance + * Script access to "current" Global instance * * @return the global singleton */ public static Global instance() { - return (Global)Context.getGlobal(); + ScriptObject global = Context.getGlobal(); + if (! (global instanceof Global)) { + throw new IllegalStateException("no current global instance"); + } + return (Global)global; } /** @@ -380,7 +387,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { * @return the context */ static Context getThisContext() { - return instance().getContext(); + return instance().context; } /** @@ -569,7 +576,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) { final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set); - final boolean strict = getContext()._strict; + final boolean strict = context._strict; if (get == null) { desc.delete(PropertyDescriptor.GET, strict); @@ -658,7 +665,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { final Global global = Global.instance(); final ScriptObject scope = (self instanceof ScriptObject) ? (ScriptObject)self : global; - return global.getContext().eval(scope, str.toString(), callThis, location, Boolean.TRUE.equals(strict)); + return global.context.eval(scope, str.toString(), callThis, location, Boolean.TRUE.equals(strict)); } /** @@ -698,7 +705,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { public static Object load(final Object self, final Object source) throws IOException { final Global global = Global.instance(); final ScriptObject scope = (self instanceof ScriptObject) ? (ScriptObject)self : global; - return global.getContext().load(scope, source); + return global.context.load(scope, source); } /** @@ -1344,7 +1351,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { this.decodeURIComponent = ScriptFunctionImpl.makeFunction("decodeURIComponent", GlobalFunctions.DECODE_URICOMPONENT); this.escape = ScriptFunctionImpl.makeFunction("escape", GlobalFunctions.ESCAPE); this.unescape = ScriptFunctionImpl.makeFunction("unescape", GlobalFunctions.UNESCAPE); - this.print = ScriptFunctionImpl.makeFunction("print", getContext()._print_no_newline ? PRINT : PRINTLN); + this.print = ScriptFunctionImpl.makeFunction("print", context._print_no_newline ? PRINT : PRINTLN); this.load = ScriptFunctionImpl.makeFunction("load", LOAD); this.exit = ScriptFunctionImpl.makeFunction("exit", EXIT); this.quit = ScriptFunctionImpl.makeFunction("quit", EXIT); @@ -1387,7 +1394,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { initTypedArray(); - if (getContext()._scripting) { + if (context._scripting) { initScripting(); } @@ -1403,11 +1410,11 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { this.__LINE__ = 0.0; // expose script (command line) arguments as "arguments" property of global - final List arguments = getContext().getOptions().getArguments(); + final List arguments = context.getOptions().getArguments(); final Object argsObj = wrapAsObject(arguments.toArray()); addOwnProperty("arguments", Attribute.NOT_ENUMERABLE, argsObj); - if (getContext()._scripting) { + if (context._scripting) { // synonym for "arguments" in scripting mode addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, argsObj); } @@ -1485,7 +1492,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { addOwnProperty("echo", Attribute.NOT_ENUMERABLE, value); // Nashorn extension: global.$OPTIONS (scripting-mode-only) - value = new OptionsObject(this.getContext()); + value = new OptionsObject(context); addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, value); // Nashorn extension: global.$ENV (scripting-mode-only) diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java index 923afa34598..7edd2419573 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java @@ -118,7 +118,7 @@ public final class NativeArray extends ScriptObject { if (value == ScriptRuntime.EMPTY) { arrayData = arrayData.delete(index); } else { - arrayData = arrayData.set(index, value, getContext()._strict); + arrayData = arrayData.set(index, value, isStrictContext()); } } @@ -644,7 +644,7 @@ public final class NativeArray extends ScriptObject { if (bulkable(sobj)) { final NativeArray nativeArray = (NativeArray)sobj; if (nativeArray.getArray().length() + args.length <= JSType.MAX_UINT) { - final ArrayData newData = nativeArray.getArray().push(nativeArray.getContext()._strict, args); + final ArrayData newData = nativeArray.getArray().push(nativeArray.isStrictContext(), args); nativeArray.setArray(newData); return newData.length(); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java index ce954f893bc..542b2aebb46 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java @@ -36,7 +36,7 @@ import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; @ScriptClass("ArrayBuffer") -class NativeArrayBuffer extends ScriptObject { +final class NativeArrayBuffer extends ScriptObject { private final byte[] buffer; @Constructor(arity = 1) diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java index 9100cb1a699..3d6fcbc8e7a 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java @@ -46,7 +46,7 @@ import jdk.nashorn.internal.runtime.linker.LinkerCallSite; * */ @ScriptClass("Debug") -public class NativeDebug extends ScriptObject { +public final class NativeDebug extends ScriptObject { NativeDebug() { this.setProto(Global.objectPrototype()); } @@ -64,6 +64,10 @@ public class NativeDebug extends ScriptObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object getContext(final Object self) { + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new RuntimePermission("getNashornContext")); + } return Global.getThisContext(); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java index 9ab4e983d80..626c3c0991a 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java @@ -47,7 +47,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; * ECMA 15.11 Error Objects */ @ScriptClass("Error") -public class NativeError extends ScriptObject { +public final class NativeError extends ScriptObject { static final MethodHandle GET_COLUMNNUMBER = findOwnMH("getColumnNumber", Object.class, Object.class); static final MethodHandle SET_COLUMNNUMBER = findOwnMH("setColumnNumber", Object.class, Object.class, Object.class); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java index e4e0498fc29..a33fb0db351 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java @@ -40,7 +40,7 @@ import jdk.nashorn.internal.runtime.ScriptObject; * */ @ScriptClass("Error") -public class NativeEvalError extends ScriptObject { +public final class NativeEvalError extends ScriptObject { /** message property in instance */ @Property(name = NativeError.MESSAGE) diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java index 7275320e114..98db34ba046 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java @@ -37,7 +37,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData; * Float32 array for the TypedArray extension */ @ScriptClass("Float32Array") -public class NativeFloat32Array extends ArrayBufferView { +public final class NativeFloat32Array extends ArrayBufferView { private static final int BYTES_PER_ELEMENT = 4; private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java index 21cc35488d0..e2ce624753f 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java @@ -37,7 +37,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData; * Float64 array for the TypedArray extension */ @ScriptClass("Float64Array") -public class NativeFloat64Array extends ArrayBufferView { +public final class NativeFloat64Array extends ArrayBufferView { private static final int BYTES_PER_ELEMENT = 8; private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java b/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java index ed6a876d543..86863a143bb 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java @@ -168,7 +168,7 @@ public final class NativeFunction { arguments = ScriptRuntime.EMPTY_ARRAY; } - return ((ScriptFunction)self).makeBoundFunction(thiz, arguments); + return ((ScriptFunctionImpl)self).makeBoundFunction(thiz, arguments); } /** diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java index 9991b29b4b9..c5951d91760 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java @@ -36,7 +36,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData; * Int16 array for the TypedArray extension */ @ScriptClass("Int16Array") -public class NativeInt16Array extends ArrayBufferView { +public final class NativeInt16Array extends ArrayBufferView { private static final int BYTES_PER_ELEMENT = 2; private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java index 833e2dce957..486e7a61fd5 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java @@ -36,7 +36,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData; * Int32 array for the TypedArray extension */ @ScriptClass("Int32Array") -public class NativeInt32Array extends ArrayBufferView { +public final class NativeInt32Array extends ArrayBufferView { private static final int BYTES_PER_ELEMENT = 4; private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java index 1d527ba9139..9ad7d24c280 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java @@ -36,7 +36,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData; * Int8Array for the TypedArray extension */ @ScriptClass("Int8Array") -public class NativeInt8Array extends ArrayBufferView { +public final class NativeInt8Array extends ArrayBufferView { private static final int BYTES_PER_ELEMENT = 1; private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java index a4eef8068ca..f8aafb70bdd 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java @@ -617,7 +617,7 @@ public final class NativeJSAdapter extends ScriptObject { case "getMethod": final FindProperty find = adaptee.findProperty(__call__, true); if (find != null) { - final ScriptFunction func = (ScriptFunction)getObjectValue(find); + final ScriptFunctionImpl func = (ScriptFunctionImpl)getObjectValue(find); // TODO: It's a shame we need to produce a function bound to this and name, when we'd only need it bound // to name. Probably not a big deal, but if we can ever make it leaner, it'd be nice. return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class, diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java index 5c7d74015f0..68f59a5b111 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java @@ -25,7 +25,6 @@ package jdk.nashorn.internal.objects; -import static jdk.nashorn.internal.runtime.ECMAErrors.syntaxError; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; @@ -36,25 +35,15 @@ import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import jdk.nashorn.internal.ir.LiteralNode; -import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; -import jdk.nashorn.internal.ir.Node; -import jdk.nashorn.internal.ir.ObjectNode; -import jdk.nashorn.internal.ir.PropertyNode; -import jdk.nashorn.internal.ir.UnaryNode; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Function; import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.objects.annotations.Where; -import jdk.nashorn.internal.parser.JSONParser; -import jdk.nashorn.internal.parser.TokenType; import jdk.nashorn.internal.runtime.ConsString; -import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.JSONFunctions; import jdk.nashorn.internal.runtime.JSType; -import jdk.nashorn.internal.runtime.ParserException; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; -import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator; import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.InvokeByName; @@ -68,8 +57,6 @@ public final class NativeJSON extends ScriptObject { private static final InvokeByName TO_JSON = new InvokeByName("toJSON", ScriptObject.class, Object.class, Object.class); private static final MethodHandle REPLACER_INVOKER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, ScriptFunction.class, ScriptObject.class, Object.class, Object.class); - private static final MethodHandle REVIVER_INVOKER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, - ScriptFunction.class, ScriptObject.class, String.class, Object.class); NativeJSON() { @@ -87,27 +74,7 @@ public final class NativeJSON extends ScriptObject { */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object parse(final Object self, final Object text, final Object reviver) { - final String str = JSType.toString(text); - final Context context = Global.getThisContext(); - final JSONParser parser = new JSONParser( - new Source("", str), - new Context.ThrowErrorManager(), - (context != null) ? - context._strict : - false); - - Node node; - - try { - node = parser.parse(); - } catch (final ParserException e) { - syntaxError(e, "invalid.json", e.getMessage()); - return UNDEFINED; - } - - final Object unfiltered = convertNode(node); - - return applyReviver(unfiltered, reviver); + return JSONFunctions.parse(text, reviver); } /** @@ -198,136 +165,6 @@ public final class NativeJSON extends ScriptObject { // -- Internals only below this point - // parse helpers - - // apply 'reviver' function if available - private static Object applyReviver(final Object unfiltered, final Object reviver) { - if (reviver instanceof ScriptFunction) { - final ScriptObject root = Global.newEmptyInstance(); - root.set("", unfiltered, Global.isStrict()); - return walk(root, "", (ScriptFunction)reviver); - } - return unfiltered; - } - - // This is the abstract "Walk" operation from the spec. - private static Object walk(final ScriptObject holder, final Object name, final ScriptFunction reviver) { - final Object val = holder.get(name); - if (val == UNDEFINED) { - return val; - } else if (val instanceof ScriptObject) { - final ScriptObject valueObj = (ScriptObject)val; - final boolean strict = Global.isStrict(); - final Iterator iter = valueObj.propertyIterator(); - - while (iter.hasNext()) { - final String key = iter.next(); - final Object newElement = walk(valueObj, key, reviver); - - if (newElement == UNDEFINED) { - valueObj.delete(key, strict); - } else { - valueObj.set(key, newElement, strict); - } - } - - return valueObj; - } else if (isArray(val)) { - final NativeArray valueArray = (NativeArray)val; - final boolean strict = Global.isStrict(); - final Iterator iter = valueArray.propertyIterator(); - - while (iter.hasNext()) { - final String key = iter.next(); - final Object newElement = walk(valueArray, valueArray.get(key), reviver); - - if (newElement == UNDEFINED) { - valueArray.delete(key, strict); - } else { - valueArray.set(key, newElement, strict); - } - } - return valueArray; - } else { - try { - // Object.class, ScriptFunction.class, ScriptObject.class, String.class, Object.class); - return REVIVER_INVOKER.invokeExact(reviver, holder, JSType.toString(name), val); - } catch(Error|RuntimeException t) { - throw t; - } catch(final Throwable t) { - throw new RuntimeException(t); - } - } - } - - // Converts IR node to runtime value - private static Object convertNode(final Node node) { - - if (node instanceof LiteralNode) { - // check for array literal - if (node.tokenType() == TokenType.ARRAY) { - assert node instanceof ArrayLiteralNode; - final Node[] elements = ((ArrayLiteralNode)node).getValue(); - - // NOTE: We cannot use LiteralNode.isNumericArray() here as that - // method uses symbols of element nodes. Since we don't do lower - // pass, there won't be any symbols! - if (isNumericArray(elements)) { - final double[] values = new double[elements.length]; - int index = 0; - - for (final Node elem : elements) { - values[index++] = JSType.toNumber(convertNode(elem)); - } - return Global.allocate(values); - } - - final Object[] values = new Object[elements.length]; - int index = 0; - - for (final Node elem : elements) { - values[index++] = convertNode(elem); - } - - return Global.allocate(values); - } - - return ((LiteralNode)node).getValue(); - - } else if (node instanceof ObjectNode) { - final ObjectNode objNode = (ObjectNode) node; - final ScriptObject object = Global.newEmptyInstance(); - final boolean strict = Global.isStrict(); - final List elements = objNode.getElements(); - - for (final Node elem : elements) { - final PropertyNode pNode = (PropertyNode) elem; - final Node valueNode = pNode.getValue(); - - object.set(pNode.getKeyName(), convertNode(valueNode), strict); - } - - return object; - } else if (node instanceof UnaryNode) { - // UnaryNode used only to represent negative number JSON value - final UnaryNode unaryNode = (UnaryNode)node; - return -((LiteralNode)unaryNode.rhs()).getNumber(); - } else { - return null; - } - } - - // does the given IR node represent a numeric array? - private static boolean isNumericArray(final Node[] values) { - for (final Node node : values) { - if (node instanceof LiteralNode && ((LiteralNode)node).getValue() instanceof Number) { - continue; - } - return false; - } - return true; - } - // stringify helpers. private static class StringifyState { @@ -380,9 +217,9 @@ public final class NativeJSON extends ScriptObject { } if (value instanceof String) { - return JSONParser.quote((String)value); + return JSONFunctions.quote((String)value); } else if (value instanceof ConsString) { - return JSONParser.quote(value.toString()); + return JSONFunctions.quote(value.toString()); } if (value instanceof Number) { @@ -421,7 +258,7 @@ public final class NativeJSON extends ScriptObject { if (strP != UNDEFINED) { final StringBuilder member = new StringBuilder(); - member.append(JSONParser.quote(p.toString())).append(':'); + member.append(JSONFunctions.quote(p.toString())).append(':'); if (!state.gap.isEmpty()) { member.append(' '); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java index 2c68a417fd6..5fa845d5141 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java @@ -47,7 +47,7 @@ import org.dynalang.dynalink.support.TypeUtilities; * arrays, and so forth. */ @ScriptClass("Java") -public class NativeJava { +public final class NativeJava { private NativeJava() { } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java index b31f853bc14..22923b1c4fd 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java @@ -52,7 +52,7 @@ import org.dynalang.dynalink.linker.LinkRequest; * {@link NativeJava#type(Object, Object) Java.type()} method. */ @ScriptClass("JavaImporter") -public class NativeJavaImporter extends ScriptObject { +public final class NativeJavaImporter extends ScriptObject { private final Object[] args; NativeJavaImporter(final Object[] args) { @@ -121,7 +121,7 @@ public class NativeJavaImporter extends ScriptObject { final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); final Object value = createProperty(name); if(value != null) { - set(name, value, getContext()._strict); + set(name, value, isStrictContext()); return true; } return false; diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java index 460edf44b84..dcdd517edd2 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java @@ -40,7 +40,7 @@ import jdk.nashorn.internal.runtime.ScriptObject; * */ @ScriptClass("Error") -public class NativeRangeError extends ScriptObject { +public final class NativeRangeError extends ScriptObject { /** message property in instance */ @Property(name = NativeError.MESSAGE) diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java index 16d7752dfd5..a3ae89e8013 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java @@ -40,7 +40,7 @@ import jdk.nashorn.internal.runtime.ScriptObject; * */ @ScriptClass("Error") -public class NativeReferenceError extends ScriptObject { +public final class NativeReferenceError extends ScriptObject { /** message property in instance */ @Property(name = NativeError.MESSAGE) diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java index 781d2333b35..19cca84bdc3 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java @@ -41,10 +41,10 @@ import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.objects.annotations.SpecializedConstructor; import jdk.nashorn.internal.objects.annotations.Where; -import jdk.nashorn.internal.parser.RegExp; import jdk.nashorn.internal.runtime.BitVector; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ParserException; +import jdk.nashorn.internal.runtime.RegExp; import jdk.nashorn.internal.runtime.RegExpMatch; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java index 628441cf541..5291c76a504 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java @@ -40,7 +40,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData; * RegExp.prototype.exec method. */ @ScriptClass("RegExpExecResult") -public class NativeRegExpExecResult extends ScriptObject { +public final class NativeRegExpExecResult extends ScriptObject { /** index property */ @Property public Object index; diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java index 6895426f298..20a40f99737 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java @@ -47,7 +47,6 @@ import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.objects.annotations.SpecializedConstructor; import jdk.nashorn.internal.objects.annotations.SpecializedFunction; import jdk.nashorn.internal.objects.annotations.Where; -import jdk.nashorn.internal.parser.Lexer; import jdk.nashorn.internal.runtime.ConsString; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptFunction; @@ -1034,10 +1033,10 @@ public final class NativeString extends ScriptObject { int start = 0; int end = len - 1; - while (start <= end && Lexer.isJSWhitespace(str.charAt(start))) { + while (start <= end && ScriptRuntime.isJSWhitespace(str.charAt(start))) { start++; } - while (end > start && Lexer.isJSWhitespace(str.charAt(end))) { + while (end > start && ScriptRuntime.isJSWhitespace(str.charAt(end))) { end--; } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java index 477006f4005..db54c48397e 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java @@ -40,7 +40,7 @@ import jdk.nashorn.internal.runtime.ScriptObject; * */ @ScriptClass("Error") -public class NativeSyntaxError extends ScriptObject { +public final class NativeSyntaxError extends ScriptObject { /** message property in instance */ @Property(name = NativeError.MESSAGE) diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java index 9d7d524153a..5e87fbb2676 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java @@ -40,7 +40,7 @@ import jdk.nashorn.internal.runtime.ScriptObject; * */ @ScriptClass("Error") -public class NativeTypeError extends ScriptObject { +public final class NativeTypeError extends ScriptObject { /** message property in instance */ @Property(name = NativeError.MESSAGE) diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java index eaad3400939..958c14acd81 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java @@ -39,7 +39,7 @@ import jdk.nashorn.internal.runtime.ScriptObject; * ECMA 15.11.6.6 URIError */ @ScriptClass("Error") -public class NativeURIError extends ScriptObject { +public final class NativeURIError extends ScriptObject { /** message property in instance */ @Property(name = NativeError.MESSAGE) diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java index 1e508963294..740bb394511 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java @@ -36,7 +36,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData; * Uint16 array for TypedArray extension */ @ScriptClass("Uint16Array") -public class NativeUint16Array extends ArrayBufferView { +public final class NativeUint16Array extends ArrayBufferView { private static final int BYTES_PER_ELEMENT = 2; private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java index 8956fe5583e..7ad8a9390a1 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java @@ -36,7 +36,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData; * Uint32 array for TypedArray extension */ @ScriptClass("Uint32Array") -public class NativeUint32Array extends ArrayBufferView { +public final class NativeUint32Array extends ArrayBufferView { private static final int BYTES_PER_ELEMENT = 4; private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java index 349a43c33db..7d506c1d6b9 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java @@ -36,7 +36,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData; * Uint8 array for TypedArray extension */ @ScriptClass("Uint8Array") -public class NativeUint8Array extends ArrayBufferView { +public final class NativeUint8Array extends ArrayBufferView { private static final int BYTES_PER_ELEMENT = 1; private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java index 8ce922476af..e3bacc2b9db 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java @@ -37,7 +37,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData; * Uint8 clamped array for TypedArray extension */ @ScriptClass("Uint8ClampedArray") -public class NativeUint8ClampedArray extends ArrayBufferView { +public final class NativeUint8ClampedArray extends ArrayBufferView { private static final int BYTES_PER_ELEMENT = 1; private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java index f3b4a665908..9caf498aa90 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java +++ b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java @@ -30,12 +30,12 @@ import static jdk.nashorn.internal.runtime.linker.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import jdk.nashorn.internal.codegen.objects.FunctionObjectCreator; + +import jdk.nashorn.internal.runtime.ScriptFunctionData; import jdk.nashorn.internal.runtime.GlobalFunctions; import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.ScriptFunction; -import jdk.nashorn.internal.runtime.ScriptFunctionData; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.linker.Lookup; @@ -184,7 +184,7 @@ public class ScriptFunctionImpl extends ScriptFunction { * @param strict are we in strict mode * @return new ScriptFunction */ - public static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict) { + static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict) { final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, strict, true); func.setConstructHandle(null); func.setPrototype(UNDEFINED); @@ -200,7 +200,7 @@ public class ScriptFunctionImpl extends ScriptFunction { * @param specs specialized versions of function if available, null otherwise * @return new ScriptFunction */ - public static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs) { + static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs) { return makeFunction(name, methodHandle, specs, false); } @@ -211,7 +211,7 @@ public class ScriptFunctionImpl extends ScriptFunction { * @param methodHandle handle for invocation * @return new ScriptFunction */ - public static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle) { + static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle) { return makeFunction(name, methodHandle, null); } @@ -223,7 +223,7 @@ public class ScriptFunctionImpl extends ScriptFunction { * @param args arguments to bind */ @Override - public ScriptFunction makeBoundFunction(final Object thiz, final Object[] args) { + protected ScriptFunction makeBoundFunction(final Object thiz, final Object[] args) { Object[] allArgs = args; if (allArgs == null) { diff --git a/nashorn/src/jdk/nashorn/internal/parser/AbstractParser.java b/nashorn/src/jdk/nashorn/internal/parser/AbstractParser.java index 5dd5d187bbb..6a91565be77 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/AbstractParser.java +++ b/nashorn/src/jdk/nashorn/internal/parser/AbstractParser.java @@ -37,6 +37,7 @@ import jdk.nashorn.internal.runtime.ECMAErrors; import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.JSErrorType; import jdk.nashorn.internal.runtime.ParserException; +import jdk.nashorn.internal.runtime.RegExp; import jdk.nashorn.internal.runtime.Source; /** diff --git a/nashorn/src/jdk/nashorn/internal/parser/Lexer.java b/nashorn/src/jdk/nashorn/internal/parser/Lexer.java index 954b2a5a24e..5b890b350d5 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/Lexer.java +++ b/nashorn/src/jdk/nashorn/internal/parser/Lexer.java @@ -289,7 +289,7 @@ public class Lexer extends Scanner { add(type, start, position); } - static String getWhitespaceRegExp() { + public static String getWhitespaceRegExp() { return JAVASCRIPT_WHITESPACE_IN_REGEXP; } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ArgumentSetter.java b/nashorn/src/jdk/nashorn/internal/runtime/ArgumentSetter.java index bc5b6d38709..5efca4a7436 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ArgumentSetter.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ArgumentSetter.java @@ -32,7 +32,8 @@ import jdk.nashorn.internal.codegen.CompilerConstants.Call; * A class with static helper methods invoked from generated bytecode for setting values of parameters of variable-arity * functions. */ -public class ArgumentSetter { +public final class ArgumentSetter { + private ArgumentSetter() {} /** Method handle for setting a function argument at a given index in an arguments object. Used from generated bytecode */ public static final Call SET_ARGUMENT = staticCall(ArgumentSetter.class, "setArgument", void.class, Object.class, ScriptObject.class, int.class); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/BitVector.java b/nashorn/src/jdk/nashorn/internal/runtime/BitVector.java index 59580b24e6e..b64e1bd4867 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/BitVector.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/BitVector.java @@ -30,7 +30,7 @@ import java.util.Arrays; /** * Faster implementation of BitSet */ -public class BitVector implements Cloneable { +public final class BitVector implements Cloneable { /** Number of bits per slot. */ private static final int BITSPERSLOT = 64; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ConsString.java b/nashorn/src/jdk/nashorn/internal/runtime/ConsString.java index 5a15fdf6e94..9cf51552f94 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ConsString.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ConsString.java @@ -33,7 +33,7 @@ import java.util.Deque; * instances of ConsString or {@link String}. Copying of characters to * a proper string is delayed until it becomes necessary. */ -public class ConsString implements CharSequence { +public final class ConsString implements CharSequence { private CharSequence left, right; final private int length; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index 46a3a7b7197..4f5cb1296fd 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -36,6 +36,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.reflect.Constructor; import java.net.MalformedURLException; import java.net.URL; import java.security.AccessController; @@ -84,11 +85,11 @@ public final class Context { Class caller = Reflection.getCallerClass(2); ClassLoader callerLoader = caller.getClassLoader(); - // Allow this method only for nashorn's own classes, script - // generated classes and Java adapter classes. Rest should + // Allow this method only for nashorn's own classes, objects + // package classes and Java adapter classes. Rest should // have the necessary security permission. if (callerLoader != myLoader && - !(callerLoader instanceof NashornLoader) && + !(callerLoader instanceof StructureLoader) && !(JavaAdapterFactory.isAdapterClass(caller))) { sm.checkPermission(new RuntimePermission("getNashornGlobal")); } @@ -332,7 +333,7 @@ public final class Context { new PrivilegedAction() { @Override public ClassLoader run() { - final ClassLoader structureLoader = new StructureLoader(sharedLoader, Context.this); + final StructureLoader structureLoader = new StructureLoader(sharedLoader, Context.this); return new ScriptLoader(structureLoader, Context.this); } }); @@ -959,7 +960,7 @@ public final class Context { // Generated code won't refer to any class generated by context // script loader and so parent loader can be the structure // loader -- which is parent of the context script loader. - return new ScriptLoader(scriptLoader.getParent(), Context.this); + return new ScriptLoader((StructureLoader)scriptLoader.getParent(), Context.this); } }); } @@ -967,10 +968,15 @@ public final class Context { private ScriptObject newGlobalTrusted() { try { final Class clazz = Class.forName("jdk.nashorn.internal.objects.Global", true, scriptLoader); - return (ScriptObject) clazz.newInstance(); - } catch (final ClassNotFoundException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException e) { + final Constructor cstr = clazz.getConstructor(Context.class); + return (ScriptObject) cstr.newInstance(this); + } catch (final Exception e) { printStackTrace(e); - throw new RuntimeException(e); + if (e instanceof RuntimeException) { + throw (RuntimeException)e; + } else { + throw new RuntimeException(e); + } } } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Debug.java b/nashorn/src/jdk/nashorn/internal/runtime/Debug.java index a087792c6c4..b712f1d0401 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Debug.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Debug.java @@ -36,7 +36,7 @@ import jdk.nashorn.internal.parser.TokenType; * Utilities for debugging Nashorn. * */ -public class Debug { +public final class Debug { private Debug() { } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java b/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java index 352750e5f07..dbbaeef6f2a 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java @@ -34,7 +34,7 @@ import jdk.nashorn.internal.runtime.options.Options; * Wrapper class for Logging system. This is how you are supposed to register a logger and use it */ -public class DebugLogger { +public final class DebugLogger { @SuppressWarnings("NonConstantLogger") private final Logger logger; private final boolean isEnabled; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java b/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java index 425548433f2..96ce6c33063 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java @@ -37,7 +37,7 @@ import java.lang.invoke.MethodHandles; * These are actual implementation methods for functions exposed by global * scope. The code lives here to share the code across the contexts. */ -public class GlobalFunctions { +public final class GlobalFunctions { /** Methodhandle to implementation of ECMA 15.1.2.2, parseInt */ public static final MethodHandle PARSEINT = findOwnMH("parseInt", double.class, Object.class, Object.class, Object.class); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java new file mode 100644 index 00000000000..4a2f73d55d1 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java @@ -0,0 +1,224 @@ +/* + * 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 jdk.nashorn.internal.runtime; + +import static jdk.nashorn.internal.runtime.ScriptObject.isArray; + +import java.lang.invoke.MethodHandle; +import java.util.Iterator; +import java.util.List; +import jdk.nashorn.internal.ir.LiteralNode; +import jdk.nashorn.internal.ir.Node; +import jdk.nashorn.internal.ir.ObjectNode; +import jdk.nashorn.internal.ir.PropertyNode; +import jdk.nashorn.internal.ir.UnaryNode; +import jdk.nashorn.internal.parser.JSONParser; +import jdk.nashorn.internal.parser.TokenType; +import jdk.nashorn.internal.runtime.linker.Bootstrap; + +/** + * Utilities used by "JSON" object implementation. + */ +public final class JSONFunctions { + private JSONFunctions() {} + private static final MethodHandle REVIVER_INVOKER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, + ScriptFunction.class, ScriptObject.class, String.class, Object.class); + + /** + * Returns JSON-compatible quoted version of the given string. + * + * @param str String to be quoted + * @return JSON-compatible quoted string + */ + public static String quote(final String str) { + return JSONParser.quote(str); + } + + /** + * Parses the given JSON text string and returns object representation. + * + * @param text JSON text to be parsed + * @param reviver optional value: function that takes two parameters (key, value) + * @return Object representation of JSON text given + */ + public static Object parse(final Object text, final Object reviver) { + final String str = JSType.toString(text); + final Context context = Context.getContextTrusted(); + final JSONParser parser = new JSONParser( + new Source("", str), + new Context.ThrowErrorManager(), + (context != null) ? + context._strict : + false); + + Node node; + + try { + node = parser.parse(); + } catch (final ParserException e) { + ECMAErrors.syntaxError(e, "invalid.json", e.getMessage()); + return ScriptRuntime.UNDEFINED; + } + + final ScriptObject global = Context.getGlobalTrusted(); + Object unfiltered = convertNode(global, node); + return applyReviver(global, unfiltered, reviver); + } + + // -- Internals only below this point + + // parse helpers + + // apply 'reviver' function if available + private static Object applyReviver(final ScriptObject global, final Object unfiltered, final Object reviver) { + if (reviver instanceof ScriptFunction) { + assert global instanceof GlobalObject; + final ScriptObject root = ((GlobalObject)global).newObject(); + root.set("", unfiltered, root.isStrictContext()); + return walk(root, "", (ScriptFunction)reviver); + } + return unfiltered; + } + + // This is the abstract "Walk" operation from the spec. + private static Object walk(final ScriptObject holder, final Object name, final ScriptFunction reviver) { + final Object val = holder.get(name); + if (val == ScriptRuntime.UNDEFINED) { + return val; + } else if (val instanceof ScriptObject) { + final ScriptObject valueObj = (ScriptObject)val; + final boolean strict = valueObj.isStrictContext(); + final Iterator iter = valueObj.propertyIterator(); + + while (iter.hasNext()) { + final String key = iter.next(); + final Object newElement = walk(valueObj, key, reviver); + + if (newElement == ScriptRuntime.UNDEFINED) { + valueObj.delete(key, strict); + } else { + valueObj.set(key, newElement, strict); + } + } + + return valueObj; + } else if (isArray(val)) { + final ScriptObject valueArray = (ScriptObject)val; + final boolean strict = valueArray.isStrictContext(); + final Iterator iter = valueArray.propertyIterator(); + + while (iter.hasNext()) { + final String key = iter.next(); + final Object newElement = walk(valueArray, valueArray.get(key), reviver); + + if (newElement == ScriptRuntime.UNDEFINED) { + valueArray.delete(key, strict); + } else { + valueArray.set(key, newElement, strict); + } + } + return valueArray; + } else { + try { + // Object.class, ScriptFunction.class, ScriptObject.class, String.class, Object.class); + return REVIVER_INVOKER.invokeExact(reviver, holder, JSType.toString(name), val); + } catch(Error|RuntimeException t) { + throw t; + } catch(final Throwable t) { + throw new RuntimeException(t); + } + } + } + + // Converts IR node to runtime value + private static Object convertNode(final ScriptObject global, final Node node) { + assert global instanceof GlobalObject; + + if (node instanceof LiteralNode) { + // check for array literal + if (node.tokenType() == TokenType.ARRAY) { + assert node instanceof LiteralNode.ArrayLiteralNode; + final Node[] elements = ((LiteralNode.ArrayLiteralNode)node).getValue(); + + // NOTE: We cannot use LiteralNode.isNumericArray() here as that + // method uses symbols of element nodes. Since we don't do lower + // pass, there won't be any symbols! + if (isNumericArray(elements)) { + final double[] values = new double[elements.length]; + int index = 0; + + for (final Node elem : elements) { + values[index++] = JSType.toNumber(convertNode(global, elem)); + } + return ((GlobalObject)global).wrapAsObject(values); + } + + final Object[] values = new Object[elements.length]; + int index = 0; + + for (final Node elem : elements) { + values[index++] = convertNode(global, elem); + } + + return ((GlobalObject)global).wrapAsObject(values); + } + + return ((LiteralNode)node).getValue(); + + } else if (node instanceof ObjectNode) { + final ObjectNode objNode = (ObjectNode) node; + final ScriptObject object = ((GlobalObject)global).newObject(); + final boolean strict = global.isStrictContext(); + final List elements = objNode.getElements(); + + for (final Node elem : elements) { + final PropertyNode pNode = (PropertyNode) elem; + final Node valueNode = pNode.getValue(); + + object.set(pNode.getKeyName(), convertNode(global, valueNode), strict); + } + + return object; + } else if (node instanceof UnaryNode) { + // UnaryNode used only to represent negative number JSON value + final UnaryNode unaryNode = (UnaryNode)node; + return -((LiteralNode)unaryNode.rhs()).getNumber(); + } else { + return null; + } + } + + // does the given IR node represent a numeric array? + private static boolean isNumericArray(final Node[] values) { + for (final Node node : values) { + if (node instanceof LiteralNode && ((LiteralNode)node).getValue() instanceof Number) { + continue; + } + return false; + } + return true; + } +} diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Logging.java b/nashorn/src/jdk/nashorn/internal/runtime/Logging.java index 6aca193c325..8a69ebf93a7 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Logging.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Logging.java @@ -40,7 +40,7 @@ import java.util.logging.Logger; * specified on the command line. Supports all standard log levels * */ -public class Logging { +public final class Logging { private Logging() { } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/NashornLoader.java b/nashorn/src/jdk/nashorn/internal/runtime/NashornLoader.java index 57c33c1dd0b..cf82ac67f3a 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/NashornLoader.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/NashornLoader.java @@ -51,13 +51,16 @@ abstract class NashornLoader extends SecureClassLoader { this.context = context; } + /** - * Override loadClass so that we can checkPackageAccess. + * Called by subclass after package access check is done + * @param name name of the class to be loaded + * @param resolve whether the class should be resolved or not + * @return Class object + * @throws ClassNotFoundException */ - @Override - public Class loadClass(final String name) throws ClassNotFoundException { - checkPackageAccess(name); - return super.loadClass(name); + protected final Class loadClassTrusted(final String name, final boolean resolve) throws ClassNotFoundException { + return super.loadClass(name, resolve); } protected static void checkPackageAccess(final String name) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java index 1809247e750..296473a390b 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java @@ -64,7 +64,7 @@ import org.dynalang.dynalink.linker.LinkRequest; * var ftype4 = Java.asType("java.awt.geom.Arc2D").Float * */ -public class NativeJavaPackage extends ScriptObject { +public final class NativeJavaPackage extends ScriptObject { /** Full name of package (includes path.) */ private final String name; diff --git a/nashorn/src/jdk/nashorn/internal/parser/RegExp.java b/nashorn/src/jdk/nashorn/internal/runtime/RegExp.java similarity index 96% rename from nashorn/src/jdk/nashorn/internal/parser/RegExp.java rename to nashorn/src/jdk/nashorn/internal/runtime/RegExp.java index 1b20eab7419..b318b754ab1 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/RegExp.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/RegExp.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.nashorn.internal.parser; +package jdk.nashorn.internal.runtime; import static java.util.regex.Pattern.CASE_INSENSITIVE; import static java.util.regex.Pattern.MULTILINE; @@ -32,9 +32,6 @@ import static java.util.regex.Pattern.UNICODE_CASE; import java.util.HashSet; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; -import jdk.nashorn.internal.runtime.BitVector; -import jdk.nashorn.internal.runtime.ECMAErrors; -import jdk.nashorn.internal.runtime.ParserException; /** * This class is used to represent a parsed regular expression. Accepts input diff --git a/nashorn/src/jdk/nashorn/internal/parser/RegExpScanner.java b/nashorn/src/jdk/nashorn/internal/runtime/RegExpScanner.java similarity index 99% rename from nashorn/src/jdk/nashorn/internal/parser/RegExpScanner.java rename to nashorn/src/jdk/nashorn/internal/runtime/RegExpScanner.java index fba2f3f2471..0d7038e6627 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/RegExpScanner.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/RegExpScanner.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.nashorn.internal.parser; +package jdk.nashorn.internal.runtime; import java.util.ArrayList; import java.util.HashMap; @@ -33,13 +33,14 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.regex.PatternSyntaxException; -import jdk.nashorn.internal.runtime.BitVector; +import jdk.nashorn.internal.parser.Lexer; +import jdk.nashorn.internal.parser.Scanner; /** * Scan a JavaScript regexp, converting to Java regex if necessary. * */ -public class RegExpScanner extends Scanner { +final class RegExpScanner extends Scanner { /** * String builder to accumulate the result - this contains verbatim parsed JavaScript. diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java index 4542c8f7ebd..17e5b2d15a7 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java @@ -377,7 +377,7 @@ public abstract class ScriptFunction extends ScriptObject { * @param args other arguments (beside self) to bind the function to * @return the bound function */ - public abstract ScriptFunction makeBoundFunction(Object self, Object[] args); + protected abstract ScriptFunction makeBoundFunction(Object self, Object[] args); @Override diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java index c72037c24a0..a701ceabeb7 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java @@ -38,7 +38,7 @@ import jdk.nashorn.internal.parser.TokenType; * Instances of this class are created during codegen and stored in script classes' * constants array to reduce function instantiation overhead during runtime. */ -public class ScriptFunctionData { +public final class ScriptFunctionData { // per-function object flags private static final int IS_STRICT = 0b0000_0001; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java index 4d89292a14b..689ca1ab5a9 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java @@ -28,34 +28,17 @@ package jdk.nashorn.internal.runtime; import java.security.CodeSource; /** - * Responsible for loading generated and disk based classes. + * Responsible for loading script generated classes. * */ final class ScriptLoader extends NashornLoader { /** * Constructor. */ - ScriptLoader(final ClassLoader parent, final Context context) { + ScriptLoader(final StructureLoader parent, final Context context) { super(parent, context); } - @Override - protected synchronized Class loadClass(final String name, final boolean resolve) throws ClassNotFoundException { - checkPackageAccess(name); - - // check the cache first - Class cl = findLoadedClass(name); - if (cl == null) { - cl = getParent().loadClass(name); - } - - if (resolve) { - resolveClass(cl); - } - - return cl; - } - // package-private and private stuff below this point /** diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java index c12ec723a39..33a68a8cd26 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -1053,7 +1053,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr * Return the current context from the object's map. * @return Current context. */ - protected final Context getContext() { + final Context getContext() { return getMap().getContext(); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java index 9ff04880c25..4b455621f24 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java @@ -36,8 +36,11 @@ import java.lang.invoke.MethodHandle; import java.lang.reflect.Array; import java.util.Collections; import java.util.Iterator; +import java.util.NoSuchElementException; import java.util.Objects; import jdk.nashorn.internal.codegen.CompilerConstants.Call; +import jdk.nashorn.internal.ir.debug.JSONWriter; +import jdk.nashorn.internal.parser.Lexer; import jdk.nashorn.internal.runtime.linker.Bootstrap; import org.dynalang.dynalink.beans.StaticClass; @@ -265,6 +268,9 @@ public final class ScriptRuntime { @Override public Object next() { + if (index >= length) { + throw new NoSuchElementException(); + } return Array.get(array, index++); } @@ -376,6 +382,28 @@ public final class ScriptRuntime { return (x == y); } + /** + * Returns AST as JSON compatible string. This is used to + * implement "parse" function in resources/parse.js script. + * + * @param code code to be parsed + * @param name name of the code source (used for location) + * @param includeLoc tells whether to include location information for nodes or not + * @return JSON string representation of AST of the supplied code + */ + public static String parse(final String code, final String name, final boolean includeLoc) { + return JSONWriter.parse(Context.getContextTrusted(), code, name, includeLoc); + } + + /** + * Test whether a char is valid JavaScript whitespace + * @param ch a char + * @return true if valid JavaScript whitespace + */ + public static boolean isJSWhitespace(final char ch) { + return Lexer.isJSWhitespace(ch); + } + /** * Entering a {@code with} node requires new scope. This is the implementation * diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java index 71011395b46..523179ad820 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java @@ -37,15 +37,13 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import java.util.HashMap; import java.util.Map; -import java.util.Set; import java.util.StringTokenizer; /** * Global functions supported only in scripting mode. */ -public class ScriptingFunctions { +public final class ScriptingFunctions { /** Handle to implementation of {@link ScriptingFunctions#readLine} - Nashorn extension */ public static final MethodHandle READLINE = findOwnMH("readLine", Object.class, Object.class); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java index fc75cf9f586..6bd3a3fdcc4 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java @@ -43,7 +43,7 @@ import org.dynalang.dynalink.linker.GuardedInvocation; * {@link ScriptObject#findSetMethod(CallSiteDescriptor, org.dynalang.dynalink.linker.LinkRequest)} and * serve as the actual encapsulation of the algorithm for creating an appropriate property setter method. */ -class SetMethodCreator { +final class SetMethodCreator { // See constructor parameters for description of fields private final ScriptObject sobj; private final PropertyMap map; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java b/nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java index 18f3c30ded7..b14e43ccd31 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java @@ -104,7 +104,7 @@ final class StructureLoader extends NashornLoader { } } - return super.loadClass(name, resolve); + return super.loadClassTrusted(name, resolve); } @@ -117,8 +117,6 @@ final class StructureLoader extends NashornLoader { return super.findClass(name); } - private static final boolean IS_JAVA_7 = System.getProperty("java.version").indexOf("1.7") != -1; - /** * Generate a layout class. * @param name Name of class. @@ -133,13 +131,6 @@ final class StructureLoader extends NashornLoader { } final byte[] code = new ObjectClassGenerator(context).generate(descriptor); - - try { - return IS_JAVA_7 ? sun.misc.Unsafe.getUnsafe().defineClass(name, code, 0, code.length) : defineClass(name, code, 0, code.length); - } catch (final SecurityException e) { - throw new AssertionError("Nashorn needs to run in the bootclasspath when using Java7, or the NoClassDefFoundError bug in Java7 will trigger." + - "(This may not be enough - it has been known to happen anyway. Please use Java8)"); - } - + return defineClass(name, code, 0, code.length); } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java index 84e4d542ca9..b16cf923acb 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java @@ -40,7 +40,7 @@ import org.dynalang.dynalink.support.CallSiteDescriptorFactory; * This class supports the handling of scope in a with body. * */ -public class WithObject extends ScriptObject implements Scope { +public final class WithObject extends ScriptObject implements Scope { private static final MethodHandle WITHEXPRESSIONFILTER = findOwnMH("withFilterExpression", Object.class, Object.class); private static final MethodHandle WITHSCOPEFILTER = findOwnMH("withFilterScope", Object.class, Object.class); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/EmptyArrayLikeIterator.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/EmptyArrayLikeIterator.java index 0feab2fa5db..5264283a3a9 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/EmptyArrayLikeIterator.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/EmptyArrayLikeIterator.java @@ -25,6 +25,8 @@ package jdk.nashorn.internal.runtime.arrays; +import java.util.NoSuchElementException; + /** * Dummy array iterator that has no elements */ @@ -41,7 +43,7 @@ final class EmptyArrayLikeIterator extends ArrayLikeIterator { @Override public Object next() { - return null; + throw new NoSuchElementException(); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/MapIterator.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/MapIterator.java index 6eaa216229c..be9bc23dd1e 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/MapIterator.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/MapIterator.java @@ -25,6 +25,7 @@ package jdk.nashorn.internal.runtime.arrays; +import java.util.NoSuchElementException; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptObject; @@ -71,6 +72,10 @@ class MapIterator extends ArrayLikeIterator { @Override public Object next() { - return indexInArray() ? obj.get(bumpIndex()) : null; + if (indexInArray()) { + return obj.get(bumpIndex()); + } + + throw new NoSuchElementException(); } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java index a658960ac29..73d3663a978 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java @@ -29,9 +29,11 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; import jdk.nashorn.internal.codegen.CompilerConstants.Call; +import jdk.nashorn.internal.codegen.RuntimeCallSite; import jdk.nashorn.internal.runtime.options.Options; import org.dynalang.dynalink.CallSiteDescriptor; import org.dynalang.dynalink.DynamicLinker; @@ -79,6 +81,20 @@ public final class Bootstrap { return dynamicLinker.link(LinkerCallSite.newLinkerCallSite(opDesc, type, flags)); } + /** + * Bootstrapper for a specialized Runtime call + * + * @param lookup lookup + * @param initialName initial name for callsite + * @param type method type for call site + * + * @return callsite for a runtime node + */ + public static CallSite runtimeBootstrap(final MethodHandles.Lookup lookup, final String initialName, final MethodType type) { + return new RuntimeCallSite(type, initialName); + } + + /** * Returns a dynamic invoker for a specified dynamic operation. You can use this method to create a method handle * that when invoked acts completely as if it were a Nashorn-linked call site. An overview of available dynamic diff --git a/nashorn/src/jdk/nashorn/internal/runtime/resources/parser.js b/nashorn/src/jdk/nashorn/internal/runtime/resources/parser.js index a721fd97c8d..b89f7e12873 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/parser.js +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/parser.js @@ -47,7 +47,7 @@ function parse(/*code, [name], [location]*/) { code = arguments[0]; } - var jsonStr = Packages.jdk.nashorn.internal.ir.debug.JSONWriter.parse(code, name, location); + var jsonStr = Packages.jdk.nashorn.internal.runtime.ScriptRuntime.parse(code, name, location); return JSON.parse(jsonStr, function (prop, value) { if (typeof(value) == 'string' && prop == "value") { diff --git a/nashorn/test/script/sandbox/nashorninternals.js b/nashorn/test/script/sandbox/nashorninternals.js new file mode 100644 index 00000000000..4072e0719a8 --- /dev/null +++ b/nashorn/test/script/sandbox/nashorninternals.js @@ -0,0 +1,57 @@ +/* + * 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 to check that nashorn "internal" classes in codegen, parser, ir + * packages cannot * be accessed from sandbox scripts. + * + * @test + * @run + * @security + */ + +function checkClass(name) { + try { + Java.type(name); + fail("should have thrown exception for: " + name); + } catch (e) { + if (! (e instanceof java.lang.SecurityException)) { + fail("Expected SecurityException, but got " + e); + } + } +} + +// Not exhaustive - but a representative list of classes +checkClass("jdk.nashorn.internal.codegen.Compiler"); +checkClass("jdk.nashorn.internal.codegen.objects.MapCreator"); +checkClass("jdk.nashorn.internal.codegen.types.Type"); +checkClass("jdk.nashorn.internal.ir.Node"); +checkClass("jdk.nashorn.internal.ir.FunctionNode"); +checkClass("jdk.nashorn.internal.ir.debug.JSONWriter"); +checkClass("jdk.nashorn.internal.ir.visitor.NodeVisitor"); +checkClass("jdk.nashorn.internal.parser.AbstractParser"); +checkClass("jdk.nashorn.internal.parser.Parser"); +checkClass("jdk.nashorn.internal.parser.JSONParser"); +checkClass("jdk.nashorn.internal.parser.Lexer"); +checkClass("jdk.nashorn.internal.parser.Scanner"); diff --git a/nashorn/test/script/trusted/JDK-8006529.js b/nashorn/test/script/trusted/JDK-8006529.js index 7c18603c1ac..f748649f727 100644 --- a/nashorn/test/script/trusted/JDK-8006529.js +++ b/nashorn/test/script/trusted/JDK-8006529.js @@ -29,23 +29,74 @@ * @run */ -// compile(script) -- compiles a script specified as a string with its -// source code, returns a jdk.nashorn.internal.ir.FunctionNode object -// representing it. -var compile = (function() { - var Compiler = Java.type("jdk.nashorn.internal.codegen.Compiler") - var Context = Java.type("jdk.nashorn.internal.runtime.Context") - var Source = Java.type("jdk.nashorn.internal.runtime.Source") - var CompilerAccess = Java.type("jdk.nashorn.internal.codegen.CompilerAccess") - return function(source) { - var compiler = Compiler.compiler(new Source("", source), Context.getContext()) - compiler.compile() - return CompilerAccess.getScriptNode(compiler) +/* + * This test script depends on nashorn Compiler internals. It uses reflection + * to get access to private field and many public methods of Compiler and + * FunctionNode classes. Note that this is trusted code and access to such + * internal package classes and methods is okay. But, if you modify any + * Compiler or FunctionNode class, you may have to revisit this script. + * We cannot use direct Java class (via dynalink bean linker) to Compiler + * and FunctionNode because of package-access check and so reflective calls. + */ + +var Compiler = Java.type("jdk.nashorn.internal.codegen.Compiler") +var Context = Java.type("jdk.nashorn.internal.runtime.Context") +var Source = Java.type("jdk.nashorn.internal.runtime.Source") +var FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode") + +// Compiler class methods and fields + +// Compiler.compile(Source, Context) +var compilerMethod = Compiler.class.getMethod("compiler", Source.class, Context.class); +// Compiler.compile() +var compileMethod = Compiler.class.getMethod("compile"); + +// NOTE: private field. But this is a trusted test! +// Compiler.functionNode +var functionNodeField = Compiler.class.getDeclaredField("functionNode"); +functionNodeField.setAccessible(true); + +// FunctionNode methods + +// FunctionNode.getFunctions method +var getFunctionsMethod = FunctionNode.class.getMethod("getFunctions"); + +// These are method names of methods in FunctionNode class +var allAssertionList = ['isVarArg', 'needsParentScope', 'needsCallee', 'needsScope', 'needsSelfSymbol', 'isSplit', 'hasEval', 'hasWith', 'hasDeepWithOrEval', 'varsInScope', 'isStrictMode'] + +// corresponding Method objects of FunctionNode class +var functionNodeMethods = {}; +// initialize FunctionNode methods +(function() { + for (var f in allAssertionList) { + var method = allAssertionList[f]; + functionNodeMethods[method] = FunctionNode.class.getMethod(method); } })(); +// returns "script" functionNode from Compiler instance +function getScriptNode(compiler) { + // compiler.functionNode + return functionNodeField.get(compiler); +} + +// returns functionNode.getFunctions().get(0) +function getFirstFunction(functionNode) { + // functionNode.getFunctions().get(0) + return getFunctionsMethod.invoke(functionNode).get(0); +} + +// compile(script) -- compiles a script specified as a string with its +// source code, returns a jdk.nashorn.internal.ir.FunctionNode object +// representing it. +function compile(source) { + var compiler = compilerMethod.invoke(null, + new Source("", source), Context.getContext()) + compileMethod.invoke(compiler); + return getScriptNode(compiler) +}; + var allAssertions = (function() { - var allAssertionList = ['isVarArg', 'needsParentScope', 'needsCallee', 'needsScope', 'needsSelfSymbol', 'isSplit', 'hasEval', 'hasWith', 'hasDeepWithOrEval', 'varsInScope', 'isStrictMode'] var allAssertions = {} for(var assertion in allAssertionList) { allAssertions[allAssertionList[assertion]] = true @@ -53,6 +104,7 @@ var allAssertions = (function() { return allAssertions; })(); + // test(f[, assertions...]) tests whether all the specified assertions on the // passed function node are true. function test(f) { @@ -66,10 +118,7 @@ function test(f) { } for(var assertion in allAssertions) { var expectedValue = !!assertions[assertion] - if(f[assertion] == null) { - throw "Can't find " + assertion + " on " + f; - } - if(f[assertion]() !== expectedValue) { + if(functionNodeMethods[assertion].invoke(f) !== expectedValue) { throw "Expected " + assertion + " === " + expectedValue + " for " + f; } } @@ -79,7 +128,7 @@ function test(f) { // assertions are true in the first function in the given script; "script" // is a string with the source text of the script. function testFirstFn(script) { - arguments[0] = compile(script).functions[0] + arguments[0] = getFirstFunction(compile(script)) test.apply(null, arguments) } diff --git a/nashorn/test/src/jdk/nashorn/internal/access/BooleanAccessTest.java b/nashorn/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java similarity index 99% rename from nashorn/test/src/jdk/nashorn/internal/access/BooleanAccessTest.java rename to nashorn/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java index 1cbef249f5e..c7dbc2e7629 100644 --- a/nashorn/test/src/jdk/nashorn/internal/access/BooleanAccessTest.java +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.nashorn.internal.access; +package jdk.nashorn.api.javaaccess; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; diff --git a/nashorn/test/src/jdk/nashorn/internal/access/MethodAccessTest.java b/nashorn/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java similarity index 99% rename from nashorn/test/src/jdk/nashorn/internal/access/MethodAccessTest.java rename to nashorn/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java index 655a11eee9d..21adc9c1343 100644 --- a/nashorn/test/src/jdk/nashorn/internal/access/MethodAccessTest.java +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.nashorn.internal.access; +package jdk.nashorn.api.javaaccess; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; diff --git a/nashorn/test/src/jdk/nashorn/internal/access/NumberAccessTest.java b/nashorn/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java similarity index 99% rename from nashorn/test/src/jdk/nashorn/internal/access/NumberAccessTest.java rename to nashorn/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java index 579cfd6f00e..63c471fd3b6 100644 --- a/nashorn/test/src/jdk/nashorn/internal/access/NumberAccessTest.java +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.nashorn.internal.access; +package jdk.nashorn.api.javaaccess; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; diff --git a/nashorn/test/src/jdk/nashorn/internal/access/NumberBoxingTest.java b/nashorn/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java similarity index 99% rename from nashorn/test/src/jdk/nashorn/internal/access/NumberBoxingTest.java rename to nashorn/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java index 179f397a45b..ae2a9827233 100644 --- a/nashorn/test/src/jdk/nashorn/internal/access/NumberBoxingTest.java +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.nashorn.internal.access; +package jdk.nashorn.api.javaaccess; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; diff --git a/nashorn/test/src/jdk/nashorn/internal/access/ObjectAccessTest.java b/nashorn/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java similarity index 99% rename from nashorn/test/src/jdk/nashorn/internal/access/ObjectAccessTest.java rename to nashorn/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java index 05d1f698534..d082fc0e579 100644 --- a/nashorn/test/src/jdk/nashorn/internal/access/ObjectAccessTest.java +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.nashorn.internal.access; +package jdk.nashorn.api.javaaccess; import static org.testng.AssertJUnit.assertEquals; import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; diff --git a/nashorn/test/src/jdk/nashorn/internal/access/Person.java b/nashorn/test/src/jdk/nashorn/api/javaaccess/Person.java similarity index 97% rename from nashorn/test/src/jdk/nashorn/internal/access/Person.java rename to nashorn/test/src/jdk/nashorn/api/javaaccess/Person.java index 232146a2c46..9012e6365a3 100644 --- a/nashorn/test/src/jdk/nashorn/internal/access/Person.java +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/Person.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.nashorn.internal.access; +package jdk.nashorn.api.javaaccess; public class Person { diff --git a/nashorn/test/src/jdk/nashorn/internal/access/SharedObject.java b/nashorn/test/src/jdk/nashorn/api/javaaccess/SharedObject.java similarity index 99% rename from nashorn/test/src/jdk/nashorn/internal/access/SharedObject.java rename to nashorn/test/src/jdk/nashorn/api/javaaccess/SharedObject.java index d9046fa94bc..a7ef3ab3edc 100644 --- a/nashorn/test/src/jdk/nashorn/internal/access/SharedObject.java +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/SharedObject.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.nashorn.internal.access; +package jdk.nashorn.api.javaaccess; import javax.script.Invocable; import javax.script.ScriptEngine; diff --git a/nashorn/test/src/jdk/nashorn/internal/access/StringAccessTest.java b/nashorn/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java similarity index 99% rename from nashorn/test/src/jdk/nashorn/internal/access/StringAccessTest.java rename to nashorn/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java index 3eec154b9b2..423c99a640e 100644 --- a/nashorn/test/src/jdk/nashorn/internal/access/StringAccessTest.java +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.nashorn.internal.access; +package jdk.nashorn.api.javaaccess; import static org.testng.AssertJUnit.assertEquals; import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; diff --git a/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerAccess.java b/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerAccess.java deleted file mode 100644 index df94050d404..00000000000 --- a/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerAccess.java +++ /dev/null @@ -1,35 +0,0 @@ - -package jdk.nashorn.internal.codegen; - -import java.lang.reflect.Field; -import jdk.nashorn.internal.ir.FunctionNode; - -/** - * Since Compiler class doesn't give us access to its private {@code functionNode} field, we use this reflection-based - * access-check disabling helper to get to it in compilation tests. - * - */ -public class CompilerAccess { - private static final Field FUNCTION_NODE_FIELD = getCompilerFunctionNodeField(); - static { - FUNCTION_NODE_FIELD.setAccessible(true); - } - - /** - * Given a compiler, return its {@code functionNode} field, representing the root function (i.e. the compiled script). - * @param compiler the compiler that already run its {@link Compiler#compile()} method. - * @return the root function node representing the compiled script. - * @throws IllegalAccessException - */ - public static FunctionNode getScriptNode(Compiler compiler) throws IllegalAccessException { - return (FunctionNode)FUNCTION_NODE_FIELD.get(compiler); - } - - private static Field getCompilerFunctionNodeField() { - try { - return Compiler.class.getDeclaredField("functionNode"); - } catch (NoSuchFieldException e) { - throw new AssertionError("", e); - } - } -} From b98a77d26c2b079e3cedda213f186e555d733d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Tue, 12 Feb 2013 13:55:05 +0100 Subject: [PATCH 131/311] 8007956: Wrong or obsolete system properties in docs/DEVELOPER_README Reviewed-by: attila, jlaskey --- nashorn/docs/DEVELOPER_README | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/nashorn/docs/DEVELOPER_README b/nashorn/docs/DEVELOPER_README index f628d0c058f..f88091cde24 100644 --- a/nashorn/docs/DEVELOPER_README +++ b/nashorn/docs/DEVELOPER_README @@ -23,20 +23,14 @@ has a default value (currently 8 relinks) for this property if it is not explicitly set. -SYSTEM PROPERTY: -Dnashorn.compiler.split.threshold=x +SYSTEM PROPERTY: -Dnashorn.compiler.splitter.threshold=x This will change the node weight that requires a subgraph of the IR to be split into several classes in order not to run out of bytecode space. The default value is 0x8000 (32768). -SYSTEM PROPERTY: -Dnashorn.callsiteaccess.debug - -See the description of the access logger below. This flag is -equivalent to enabling the access logger with "info" level. - - -SYSTEM PROPERTY: -Dnashorn.compiler.intarithmetic +SYSTEM PROPERTY: -Dnashorn.compiler.intarithmetic Arithmetic operations in Nashorn (except bitwise ones) typically coerce the operands to doubles (as per the JavaScript spec). To switch From d50e3823e4a4f468403301d2d99af4a3c9235371 Mon Sep 17 00:00:00 2001 From: Attila Szegedi Date: Tue, 12 Feb 2013 12:47:51 +0100 Subject: [PATCH 132/311] 8007900: Function binding is inefficient Reviewed-by: jlaskey, lagergren --- .../objects/BoundScriptFunctionImpl.java | 51 ++ .../jdk/nashorn/internal/objects/Global.java | 3 +- .../objects/NativeStrictArguments.java | 4 +- .../internal/objects/ScriptFunctionImpl.java | 167 ++---- .../internal/runtime/ArgumentSetter.java | 6 +- .../nashorn/internal/runtime/PropertyMap.java | 2 +- .../internal/runtime/ScriptFunction.java | 414 ++----------- .../internal/runtime/ScriptFunctionData.java | 563 ++++++++++++++---- .../internal/runtime/ScriptRuntime.java | 18 - .../runtime/SpecializedMethodChooser.java | 99 +++ nashorn/test/script/basic/funcbind2.js | 94 +++ .../test/script/basic/funcbind2.js.EXPECTED | 42 ++ nashorn/test/script/basic/funcbind3.js | 59 ++ .../test/script/basic/funcbind3.js.EXPECTED | 15 + 14 files changed, 924 insertions(+), 613 deletions(-) create mode 100644 nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/SpecializedMethodChooser.java create mode 100644 nashorn/test/script/basic/funcbind2.js create mode 100644 nashorn/test/script/basic/funcbind2.js.EXPECTED create mode 100644 nashorn/test/script/basic/funcbind3.js create mode 100644 nashorn/test/script/basic/funcbind3.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java b/nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java new file mode 100644 index 00000000000..2b8691946b0 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.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 jdk.nashorn.internal.objects; + +import jdk.nashorn.internal.runtime.ScriptFunction; +import jdk.nashorn.internal.runtime.ScriptFunctionData; +import jdk.nashorn.internal.runtime.ScriptObject; +import jdk.nashorn.internal.runtime.ScriptRuntime; + +/** + * A {@code ScriptFunctionImpl} subclass for functions created using {@code Function.prototype.bind}. Such functions + * must track their {@code [[TargetFunction]] property for purposes of correctly implementing {@code [[HasInstance]]}; + * see {@link ScriptFunction#isInstance(ScriptObject)}. + */ +class BoundScriptFunctionImpl extends ScriptFunctionImpl { + private final ScriptFunction targetFunction; + + BoundScriptFunctionImpl(ScriptFunctionData data, ScriptFunction targetFunction) { + super(data); + this.prototype = ScriptRuntime.UNDEFINED; + this.targetFunction = targetFunction; + } + + @Override + protected ScriptFunction getTargetFunction() { + return targetFunction; + } +} diff --git a/nashorn/src/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk/nashorn/internal/objects/Global.java index d1664d11296..f1993f7f542 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java @@ -413,7 +413,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { @Override public ScriptFunction newScriptFunction(final String name, final MethodHandle handle, final ScriptObject scope, final boolean strict) { - return new ScriptFunctionImpl(name, handle, scope, null, strict, false); + return new ScriptFunctionImpl(name, handle, scope, null, strict, false, true); } @Override @@ -1339,7 +1339,6 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { // initialize global function properties this.eval = this.builtinEval = ScriptFunctionImpl.makeFunction("eval", EVAL); - ((ScriptFunction)this.eval).setArity(1); this.parseInt = ScriptFunctionImpl.makeFunction("parseInt", GlobalFunctions.PARSEINT); this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeStrictArguments.java b/nashorn/src/jdk/nashorn/internal/objects/NativeStrictArguments.java index dce6c4fef95..8b5a7b5ed47 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeStrictArguments.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeStrictArguments.java @@ -56,8 +56,8 @@ public final class NativeStrictArguments extends ScriptObject { PropertyMap map = PropertyMap.newMap(NativeStrictArguments.class); map = Lookup.newProperty(map, "length", Property.NOT_ENUMERABLE, G$LENGTH, S$LENGTH); // In strict mode, the caller and callee properties should throw TypeError - map = ScriptFunctionImpl.newThrowerProperty(map, "caller", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE); - map = ScriptFunctionImpl.newThrowerProperty(map, "callee", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE); + map = ScriptFunctionImpl.newThrowerProperty(map, "caller"); + map = ScriptFunctionImpl.newThrowerProperty(map, "callee"); nasgenmap$ = map; } diff --git a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java index 9caf498aa90..3ca57ee8062 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java +++ b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java @@ -26,30 +26,27 @@ package jdk.nashorn.internal.objects; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; -import static jdk.nashorn.internal.runtime.linker.Lookup.MH; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; - -import jdk.nashorn.internal.runtime.ScriptFunctionData; +import jdk.nashorn.internal.codegen.objects.FunctionObjectCreator; import jdk.nashorn.internal.runtime.GlobalFunctions; import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.ScriptFunction; +import jdk.nashorn.internal.runtime.ScriptFunctionData; import jdk.nashorn.internal.runtime.ScriptObject; -import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.linker.Lookup; -import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; /** * Concrete implementation of ScriptFunction. This sets correct map for the * function objects -- to expose properties like "prototype", "length" etc. */ public class ScriptFunctionImpl extends ScriptFunction { - - private static final MethodHandle BOUND_FUNCTION = findOwnMH("boundFunction", Object.class, ScriptFunction.class, Object.class, Object[].class, Object.class, Object[].class); - private static final MethodHandle BOUND_CONSTRUCTOR = findOwnMH("boundConstructor", Object.class, ScriptFunction.class, Object[].class, Object.class, Object[].class); - + // property map for strict mode functions + private static final PropertyMap strictmodemap$; + // property map for bound functions + private static final PropertyMap boundfunctionmap$; + // property map for non-strict, non-bound functions. private static final PropertyMap nasgenmap$; /** @@ -61,7 +58,7 @@ public class ScriptFunctionImpl extends ScriptFunction { * @param specs specialized versions of this method, if available, null otherwise */ ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final MethodHandle[] specs) { - super(name, invokeHandle, nasgenmap$, null, specs, false, true); + super(name, invokeHandle, nasgenmap$, null, specs, false, true, true); init(); } @@ -75,7 +72,7 @@ public class ScriptFunctionImpl extends ScriptFunction { * @param specs specialized versions of this method, if available, null otherwise */ ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final MethodHandle[] specs) { - super(name, invokeHandle, map.addAll(nasgenmap$), null, specs, false, true); + super(name, invokeHandle, map.addAll(nasgenmap$), null, specs, false, true, true); init(); } @@ -88,9 +85,10 @@ public class ScriptFunctionImpl extends ScriptFunction { * @param specs specialized versions of this method, if available, null otherwise * @param strict are we in strict mode * @param builtin is this a built-in function + * @param isConstructor can the function be used as a constructor (most can; some built-ins are restricted). */ - ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean strict, final boolean builtin) { - super(name, methodHandle, getMap(strict), scope, specs, strict, builtin); + ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean strict, final boolean builtin, final boolean isConstructor) { + super(name, methodHandle, getMap(strict), scope, specs, strict, builtin, isConstructor); init(); } @@ -106,9 +104,16 @@ public class ScriptFunctionImpl extends ScriptFunction { public ScriptFunctionImpl(final ScriptFunctionData data, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle allocator) { super(data, getMap(data.isStrict()), scope); // Set method handles in script data - if (data.getInvoker() == null) { - data.setMethodHandles(methodHandle, allocator); - } + data.setMethodHandles(methodHandle, allocator); + init(); + } + + /** + * Only invoked internally from {@link BoundScriptFunctionImpl} constructor. + * @param data the script function data for the bound function. + */ + ScriptFunctionImpl(final ScriptFunctionData data) { + super(data, boundfunctionmap$, null); init(); } @@ -118,6 +123,8 @@ public class ScriptFunctionImpl extends ScriptFunction { map = Lookup.newProperty(map, "length", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$LENGTH, null); map = Lookup.newProperty(map, "name", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$NAME, null); nasgenmap$ = map; + strictmodemap$ = createStrictModeMap(nasgenmap$); + boundfunctionmap$ = createBoundFunctionMap(strictmodemap$); } // function object representing TypeErrorThrower @@ -126,9 +133,7 @@ public class ScriptFunctionImpl extends ScriptFunction { static synchronized ScriptFunction getTypeErrorThrower() { if (typeErrorThrower == null) { //name handle - final ScriptFunctionImpl func = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_SETTER, null, null, false, false); - // clear constructor handle... - func.setConstructHandle(null); + final ScriptFunctionImpl func = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_SETTER, null, null, false, false, false); func.setPrototype(UNDEFINED); typeErrorThrower = func; } @@ -137,28 +142,24 @@ public class ScriptFunctionImpl extends ScriptFunction { } // add a new property that throws TypeError on get as well as set - static synchronized PropertyMap newThrowerProperty(final PropertyMap map, final String name, final int flags) { - return map.newProperty(name, flags, -1, Lookup.TYPE_ERROR_THROWER_GETTER, Lookup.TYPE_ERROR_THROWER_SETTER); + static synchronized PropertyMap newThrowerProperty(final PropertyMap map, final String name) { + return map.newProperty(name, Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE, -1, + Lookup.TYPE_ERROR_THROWER_GETTER, Lookup.TYPE_ERROR_THROWER_SETTER); } - // property map for strict mode functions - lazily initialized - private static PropertyMap strictmodemap$; + private static PropertyMap createStrictModeMap(final PropertyMap functionMap) { + return newThrowerProperty(newThrowerProperty(functionMap, "arguments"), "caller"); + } // Choose the map based on strict mode! private static PropertyMap getMap(final boolean strict) { - if (strict) { - synchronized (ScriptFunctionImpl.class) { - if (strictmodemap$ == null) { - // In strict mode, the following properties should throw TypeError - strictmodemap$ = nasgenmap$; - strictmodemap$ = newThrowerProperty(strictmodemap$, "arguments", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE); - strictmodemap$ = newThrowerProperty(strictmodemap$, "caller", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE); - } - } - return strictmodemap$; - } + return strict ? strictmodemap$ : nasgenmap$; + } - return nasgenmap$; + private static PropertyMap createBoundFunctionMap(final PropertyMap strictModeMap) { + // Bond function map is same as strict function map, but additionally lacks the "prototype" property, see + // ECMAScript 5.1 section 15.3.4.5 + return strictModeMap.deleteProperty(strictModeMap.findProperty("prototype")); } // Instance of this class is used as global anonymous function which @@ -175,23 +176,6 @@ public class ScriptFunctionImpl extends ScriptFunction { return new AnonymousFunction(); } - /** - * Factory method for non-constructor built-in functions - * - * @param name function name - * @param methodHandle handle for invocation - * @param specs specialized versions of function if available, null otherwise - * @param strict are we in strict mode - * @return new ScriptFunction - */ - static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict) { - final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, strict, true); - func.setConstructHandle(null); - func.setPrototype(UNDEFINED); - - return func; - } - /** * Factory method for non-constructor built-in functions * @@ -201,7 +185,10 @@ public class ScriptFunctionImpl extends ScriptFunction { * @return new ScriptFunction */ static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs) { - return makeFunction(name, methodHandle, specs, false); + final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, false, true, false); + func.setPrototype(UNDEFINED); + + return func; } /** @@ -216,57 +203,27 @@ public class ScriptFunctionImpl extends ScriptFunction { } /** - * This method is used to create a bound function. See also - * {@link NativeFunction#bind(Object, Object...)} method implementation. - * - * @param thiz this reference to bind - * @param args arguments to bind + * Same as {@link ScriptFunction#makeBoundFunction(Object, Object[])}. The only reason we override it is so that we + * can expose it to methods in this package. + * @param self the self to bind to this function. Can be null (in which case, null is bound as this). + * @param args additional arguments to bind to this function. Can be null or empty to not bind additional arguments. + * @return a function with the specified self and parameters bound. */ @Override - protected ScriptFunction makeBoundFunction(final Object thiz, final Object[] args) { - Object[] allArgs = args; - - if (allArgs == null) { - allArgs = ScriptRuntime.EMPTY_ARRAY; - } - - final Object boundThiz = convertThisObject(thiz); - final MethodHandle boundMethod = MH.insertArguments(BOUND_FUNCTION, 0, this, boundThiz, allArgs); - final ScriptFunction boundFunc = makeFunction("", boundMethod, null, true); - - MethodHandle consHandle = this.getConstructHandle(); - - if (consHandle != null) { - consHandle = MH.insertArguments(BOUND_CONSTRUCTOR, 0, this, allArgs); - } - - boundFunc.setConstructHandle(consHandle); - int newArity = this.getArity(); - if (newArity != -1) { - newArity -= Math.min(newArity, allArgs.length); - } - boundFunc.setArity(newArity); - - return boundFunc; + protected ScriptFunction makeBoundFunction(Object self, Object[] args) { + return super.makeBoundFunction(self, args); } - @SuppressWarnings("unused") - private static Object boundFunction(final ScriptFunction wrapped, final Object boundThiz, final Object[] boundArgs, final Object thiz, final Object[] args) { - final Object[] allArgs = new Object[boundArgs.length + args.length]; - - System.arraycopy(boundArgs, 0, allArgs, 0, boundArgs.length); - System.arraycopy(args, 0, allArgs, boundArgs.length, args.length); - - return ScriptRuntime.apply(wrapped, boundThiz, allArgs); - } - - @SuppressWarnings("unused") - private static Object boundConstructor(final ScriptFunction wrapped, final Object[] boundArgs, final Object thiz, final Object[] args) { - final Object[] allArgs = new Object[boundArgs.length + args.length]; - System.arraycopy(boundArgs, 0, allArgs, 0, boundArgs.length); - System.arraycopy(args, 0, allArgs, boundArgs.length, args.length); - - return ScriptRuntime.construct(wrapped, allArgs); + /** + * This method is used to create a bound function based on this function. + * + * @param data the {@code ScriptFunctionData} specifying the functions immutable portion. + * @return a function initialized from the specified data. Its parent scope will be set to null, therefore the + * passed in data should not expect a callee. + */ + @Override + protected ScriptFunction makeBoundFunction(final ScriptFunctionData data) { + return new BoundScriptFunctionImpl(data, getTargetFunction()); } // return Object.prototype - used by "allocate" @@ -288,12 +245,4 @@ public class ScriptFunctionImpl extends ScriptFunction { setUserAccessors("caller", func, func); } } - - private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { - try { - return MethodHandles.lookup().findStatic(ScriptFunctionImpl.class, name, MH.type(rtype, types)); - } catch (final NoSuchMethodException | IllegalAccessException e) { - throw new MethodHandleFactory.LookupException(e); - } - } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ArgumentSetter.java b/nashorn/src/jdk/nashorn/internal/runtime/ArgumentSetter.java index 5efca4a7436..8546ead188f 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ArgumentSetter.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ArgumentSetter.java @@ -24,7 +24,7 @@ */ package jdk.nashorn.internal.runtime; -import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; +import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; import jdk.nashorn.internal.codegen.CompilerConstants.Call; @@ -36,10 +36,10 @@ public final class ArgumentSetter { private ArgumentSetter() {} /** Method handle for setting a function argument at a given index in an arguments object. Used from generated bytecode */ - public static final Call SET_ARGUMENT = staticCall(ArgumentSetter.class, "setArgument", void.class, Object.class, ScriptObject.class, int.class); + public static final Call SET_ARGUMENT = staticCallNoLookup(ArgumentSetter.class, "setArgument", void.class, Object.class, ScriptObject.class, int.class); /** Method handle for setting a function argument at a given index in an arguments array. Used from generated bytecode */ - public static final Call SET_ARRAY_ELEMENT = staticCall(ArgumentSetter.class, "setArrayElement", void.class, Object.class, Object[].class, int.class); + public static final Call SET_ARRAY_ELEMENT = staticCallNoLookup(ArgumentSetter.class, "setArrayElement", void.class, Object.class, Object[].class, int.class); /** diff --git a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java index 9a99c74d08b..872200ba5fe 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java @@ -308,7 +308,7 @@ public final class PropertyMap implements Iterable, PropertyListener { * * @return New {@link PropertyMap} with {@link Property} removed or {@code null} if not found. */ - PropertyMap deleteProperty(final Property property) { + public PropertyMap deleteProperty(final Property property) { PropertyMap newMap = checkHistory(property); final String key = property.getKey(); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java index 17e5b2d15a7..fb3b419e150 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java @@ -34,13 +34,10 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import jdk.nashorn.internal.codegen.CompilerConstants.Call; -import jdk.nashorn.internal.codegen.types.Type; -import jdk.nashorn.internal.objects.annotations.SpecializedConstructor; import jdk.nashorn.internal.objects.annotations.SpecializedFunction; import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; import jdk.nashorn.internal.runtime.linker.NashornGuards; -import jdk.nashorn.internal.runtime.options.Options; import org.dynalang.dynalink.CallSiteDescriptor; import org.dynalang.dynalink.linker.GuardedInvocation; import org.dynalang.dynalink.linker.LinkRequest; @@ -63,18 +60,13 @@ public abstract class ScriptFunction extends ScriptObject { public static final MethodHandle G$NAME = findOwnMH("G$name", Object.class, Object.class); /** Method handle for allocate function for this ScriptFunction */ - public static final MethodHandle ALLOCATE = findOwnMH("allocate", Object.class); - - private static final MethodHandle NEWFILTER = findOwnMH("newFilter", Object.class, Object.class, Object.class); + static final MethodHandle ALLOCATE = findOwnMH("allocate", Object.class); private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", Object.class, Object.class); /** method handle to scope getter for this ScriptFunction */ public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class); - /** Should specialized function and specialized constructors for the builtin be used if available? */ - private static final boolean DISABLE_SPECIALIZATION = Options.getBooleanProperty("nashorn.scriptfunction.specialization.disable"); - private final ScriptFunctionData data; /** Reference to constructor prototype. */ @@ -100,9 +92,10 @@ public abstract class ScriptFunction extends ScriptObject { final ScriptObject scope, final MethodHandle[] specs, final boolean strict, - final boolean builtin) { + final boolean builtin, + final boolean isConstructor) { - this (new ScriptFunctionData(name, methodHandle, specs, strict, builtin), map, scope); + this (new ScriptFunctionData(name, methodHandle, specs, strict, builtin, isConstructor), map, scope); } /** @@ -138,12 +131,13 @@ public abstract class ScriptFunction extends ScriptObject { */ @Override public boolean isInstance(final ScriptObject instance) { - if (!(prototype instanceof ScriptObject)) { - typeError("prototype.not.an.object", ScriptRuntime.safeToString(this), ScriptRuntime.safeToString(prototype)); + final Object basePrototype = getTargetFunction().getPrototype(); + if (!(basePrototype instanceof ScriptObject)) { + typeError("prototype.not.an.object", ScriptRuntime.safeToString(getTargetFunction()), ScriptRuntime.safeToString(basePrototype)); } for (ScriptObject proto = instance.getProto(); proto != null; proto = proto.getProto()) { - if (proto == prototype) { + if (proto == basePrototype) { return true; } } @@ -152,11 +146,18 @@ public abstract class ScriptFunction extends ScriptObject { } /** - * Get the arity of this ScriptFunction - * @return arity + * Returns the target function for this function. If the function was not created using + * {@link #makeBoundFunction(Object, Object[])}, its target function is itself. If it is bound, its target function + * is the target function of the function it was made from (therefore, the target function is always the final, + * unbound recipient of the calls). + * @return the target function for this function. */ - public final int getArity() { - return data.getArity(); + protected ScriptFunction getTargetFunction() { + return this; + } + + boolean isBoundFunction() { + return getTargetFunction() != this; } /** @@ -175,14 +176,6 @@ public abstract class ScriptFunction extends ScriptObject { return data.isStrict(); } - /** - * Is this a ECMAScript built-in function (like parseInt, Array.isArray) ? - * @return true if built-in - */ - public boolean isBuiltin() { - return data.isBuiltin(); - } - /** * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument * according to ECMA 10.4.3. @@ -203,126 +196,7 @@ public abstract class ScriptFunction extends ScriptObject { if (Context.DEBUG) { invokes++; } - - final MethodHandle invoker = data.getGenericInvoker(); - final Object selfObj = convertThisObject(self); - final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; - - if (data.isVarArg()) { - if (data.needsCallee()) { - return invoker.invokeExact(this, selfObj, args); - } - return invoker.invokeExact(selfObj, args); - } - - final int paramCount = invoker.type().parameterCount(); - if (data.needsCallee()) { - switch (paramCount) { - case 2: - return invoker.invokeExact(this, selfObj); - case 3: - return invoker.invokeExact(this, selfObj, getArg(args, 0)); - case 4: - return invoker.invokeExact(this, selfObj, getArg(args, 0), getArg(args, 1)); - case 5: - return invoker.invokeExact(this, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); - default: - return invoker.invokeWithArguments(withArguments(selfObj, paramCount, args)); - } - } - - switch (paramCount) { - case 1: - return invoker.invokeExact(selfObj); - case 2: - return invoker.invokeExact(selfObj, getArg(args, 0)); - case 3: - return invoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1)); - case 4: - return invoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); - default: - return invoker.invokeWithArguments(withArguments(selfObj, paramCount, args)); - } - } - - private static Object getArg(final Object[] args, final int i) { - return i < args.length ? args[i] : UNDEFINED; - } - - /** - * Construct new object using this constructor. - * @param self Target object. - * @param args Call arguments. - * @return ScriptFunction result. - * @throws Throwable if there is an exception/error with the constructor invocation or thrown from it - */ - public Object construct(final Object self, final Object... args) throws Throwable { - if (data.getConstructor() == null) { - typeError("not.a.constructor", ScriptRuntime.safeToString(this)); - } - - final MethodHandle constructor = data.getGenericConstructor(); - if (data.isVarArg()) { - if (data.needsCallee()) { - return constructor.invokeExact(this, self, args); - } - return constructor.invokeExact(self, args); - } - - final int paramCount = constructor.type().parameterCount(); - if (data.needsCallee()) { - switch (paramCount) { - case 2: - return constructor.invokeExact(this, self); - case 3: - return constructor.invokeExact(this, self, getArg(args, 0)); - case 4: - return constructor.invokeExact(this, self, getArg(args, 0), getArg(args, 1)); - case 5: - return constructor.invokeExact(this, self, getArg(args, 0), getArg(args, 1), getArg(args, 2)); - default: - return constructor.invokeWithArguments(withArguments(self, args)); - } - } - - switch(paramCount) { - case 1: - return constructor.invokeExact(self); - case 2: - return constructor.invokeExact(self, getArg(args, 0)); - case 3: - return constructor.invokeExact(self, getArg(args, 0), getArg(args, 1)); - case 4: - return constructor.invokeExact(self, getArg(args, 0), getArg(args, 1), getArg(args, 2)); - default: - return constructor.invokeWithArguments(withArguments(self, args)); - } - } - - private Object[] withArguments(final Object self, final Object[] args) { - return withArguments(self, args.length + (data.needsCallee() ? 2 : 1), args); - } - - private Object[] withArguments(final Object self, final int argCount, final Object[] args) { - final Object[] finalArgs = new Object[argCount]; - - int nextArg = 0; - if (data.needsCallee()) { - finalArgs[nextArg++] = this; - } - finalArgs[nextArg++] = self; - - // Don't add more args that there is argCount in the handle (including self and callee). - for (int i = 0; i < args.length && nextArg < argCount;) { - finalArgs[nextArg++] = args[i++]; - } - - // If we have fewer args than argCount, pad with undefined. - while (nextArg < argCount) { - finalArgs[nextArg++] = UNDEFINED; - } - - return finalArgs; + return data.invoke(this, self, arguments); } /** @@ -331,26 +205,14 @@ public abstract class ScriptFunction extends ScriptObject { * * @return a new instance of the {@link ScriptObject} whose allocator this is */ - public Object allocate() { + @SuppressWarnings("unused") + private Object allocate() { if (Context.DEBUG) { allocations++; } + assert !isBoundFunction(); // allocate never invoked on bound functions - if (getConstructHandle() == null) { - typeError("not.a.constructor", ScriptRuntime.safeToString(this)); - } - - ScriptObject object = null; - - if (data.getAllocator() != null) { - try { - object = (ScriptObject)data.getAllocator().invokeExact(data.getAllocatorMap()); - } catch (final RuntimeException | Error e) { - throw e; - } catch (final Throwable t) { - throw new RuntimeException(t); - } - } + final ScriptObject object = data.allocate(); if (object != null) { if (prototype instanceof ScriptObject) { @@ -372,13 +234,17 @@ public abstract class ScriptFunction extends ScriptObject { protected abstract ScriptObject getObjectPrototype(); /** - * Creates a version of this function bound to a specific "self" and other argumentss - * @param self the self to bind the function to - * @param args other arguments (beside self) to bind the function to - * @return the bound function + * Creates a version of this function bound to a specific "self" and other arguments, as per + * {@code Function.prototype.bind} functionality in ECMAScript 5.1 section 15.3.4.5. + * @param self the self to bind to this function. Can be null (in which case, null is bound as this). + * @param args additional arguments to bind to this function. Can be null or empty to not bind additional arguments. + * @return a function with the specified self and parameters bound. */ - protected abstract ScriptFunction makeBoundFunction(Object self, Object[] args); + protected ScriptFunction makeBoundFunction(Object self, Object[] args) { + return makeBoundFunction(data.makeBoundFunctionData(this, self, args)); + } + protected abstract ScriptFunction makeBoundFunction(ScriptFunctionData boundData); @Override public final String safeToString() { @@ -417,80 +283,13 @@ public abstract class ScriptFunction extends ScriptObject { return prototype; } - private static int weigh(final MethodType t) { - int weight = Type.typeFor(t.returnType()).getWeight(); - for (final Class paramType : t.parameterArray()) { - final int pweight = Type.typeFor(paramType).getWeight(); - weight += pweight; - } - return weight; - } - - private static boolean typeCompatible(final MethodType desc, final MethodType spec) { - //spec must fit in desc - final Class[] dparray = desc.parameterArray(); - final Class[] sparray = spec.parameterArray(); - - if (dparray.length != sparray.length) { - return false; - } - - for (int i = 0; i < dparray.length; i++) { - final Type dp = Type.typeFor(dparray[i]); - final Type sp = Type.typeFor(sparray[i]); - - if (dp.isBoolean()) { - return false; //don't specialize on booleans, we have the "true" vs int 1 ambiguity in resolution - } - - //specialization arguments must be at least as wide as dp, if not wider - if (Type.widest(dp, sp) != sp) { - //e.g. specialization takes double and callsite says "object". reject. - //but if specialization says double and callsite says "int" or "long" or "double", that's fine - return false; - } - } - - return true; // anything goes for return type, take the convenient one and it will be upcasted thru dynalink magic. - } - - private MethodHandle candidateWithLowestWeight(final MethodType descType, final MethodHandle initialCandidate, final MethodHandle[] specs) { - if (DISABLE_SPECIALIZATION || specs == null) { - return initialCandidate; - } - - int minimumWeight = Integer.MAX_VALUE; - MethodHandle candidate = initialCandidate; - - for (final MethodHandle spec : specs) { - final MethodType specType = spec.type(); - - if (!typeCompatible(descType, specType)) { - continue; - } - - //return type is ok. we want a wider or equal one for our callsite. - final int specWeight = weigh(specType); - if (specWeight < minimumWeight) { - candidate = spec; - minimumWeight = specWeight; - } - } - - if (DISABLE_SPECIALIZATION && candidate != initialCandidate) { - Context.err("### Specializing builtin " + getName() + " -> " + candidate + "?"); - } - - return candidate; - } - /** * Return the most appropriate invoke handle if there are specializations * @param type most specific method type to look for invocation with * @return invoke method handle */ - public final MethodHandle getBestSpecializedInvokeHandle(final MethodType type) { - return candidateWithLowestWeight(type, getInvokeHandle(), data.getInvokeSpecializations()); + private final MethodHandle getBestInvoker(final MethodType type) { + return data.getBestInvoker(type); } /** @@ -524,33 +323,6 @@ public abstract class ScriptFunction extends ScriptObject { return data.needsCallee() ? MH.bindTo(methodHandle, this) : methodHandle; } - /** - * Get the construct handle - the most generic (and if no specializations are in place, only) constructor - * method handle for this ScriptFunction - * @see SpecializedConstructor - * @param type type for wanted constructor - * @return construct handle - */ - private final MethodHandle getConstructHandle(final MethodType type) { - return candidateWithLowestWeight(type, getConstructHandle(), data.getConstructSpecializations()); - } - - /** - * Get a method handle to the constructor for this function - * @return constructor handle - */ - public final MethodHandle getConstructHandle() { - return data.getConstructor(); - } - - /** - * Set a method handle to the constructor for this function. - * @param constructHandle constructor handle. Can be null to prevent the function from being used as a constructor. - */ - public final void setConstructHandle(final MethodHandle constructHandle) { - data.setConstructor(constructHandle); - } - /** * Get the name for this function * @return the name @@ -569,14 +341,6 @@ public abstract class ScriptFunction extends ScriptObject { return data.getInvoker() == null; } - /** - * Get token for this function - * @return token - */ - public final long getToken() { - return data.getToken(); - } - /** * Get the scope for this function * @return the scope @@ -618,7 +382,7 @@ public abstract class ScriptFunction extends ScriptObject { */ public static int G$length(final Object self) { if (self instanceof ScriptFunction) { - return ((ScriptFunction)self).getArity(); + return ((ScriptFunction)self).data.getArity(); } return 0; @@ -681,81 +445,13 @@ public abstract class ScriptFunction extends ScriptObject { @Override protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc) { - // Call site type is (callee, args...) - dyn:new doesn't specify a "this", it's our job to allocate it final MethodType type = desc.getMethodType(); - - // Constructor arguments are either (callee, this, args...) or (this, args...), depending on whether it needs a - // callee or not. - MethodHandle constructor = getConstructHandle(type); - - if (constructor == null) { - typeError("not.a.constructor", ScriptRuntime.safeToString(this)); - return null; - } - - // If it was (callee, this, args...), permute it to (this, callee, args...). We're doing this because having - // "this" in the first argument position is what allows the elegant folded composition of - // (newFilter x constructor x allocator) further down below in the code. - constructor = swapCalleeAndThis(constructor); - - final MethodType ctorType = constructor.type(); - // Drop constructor "this", so it's also captured as "allocation" parameter of newFilter after we fold the - // constructor into newFilter. - // (this, [callee, ]args...) => ([callee, ]args...) - final Class[] ctorArgs = ctorType.dropParameterTypes(0, 1).parameterArray(); - // Fold constructor into newFilter that replaces the return value from the constructor with the originally - // allocated value when the originally allocated value is a primitive. - // (result, this, [callee, ]args...) x (this, [callee, ]args...) => (this, [callee, ]args...) - MethodHandle handle = MH.foldArguments(MH.dropArguments(NEWFILTER, 2, ctorArgs), constructor); - - // allocate() takes a ScriptFunction and returns a newly allocated ScriptObject... - if (data.needsCallee()) { - // ...we either fold it into the previous composition, if we need both the ScriptFunction callee object and - // the newly allocated object in the arguments, so (this, callee, args...) x (callee) => (callee, args...), - // or... - handle = MH.foldArguments(handle, ALLOCATE); - } else { - // ...replace the ScriptFunction argument with the newly allocated object, if it doesn't need the callee - // (this, args...) filter (callee) => (callee, args...) - handle = MH.filterArguments(handle, 0, ALLOCATE); - } - - final MethodHandle filterIn = MH.asType(pairArguments(handle, type), type); - return new GuardedInvocation(filterIn, null, NashornGuards.getFunctionGuard(this)); - } - - /** - * If this function's method handles need a callee parameter, swap the order of first two arguments for the passed - * method handle. If this function's method handles don't need a callee parameter, returns the original method - * handle unchanged. - * @param mh a method handle with order of arguments {@code (callee, this, args...)} - * @return a method handle with order of arguments {@code (this, callee, args...)} - */ - private MethodHandle swapCalleeAndThis(final MethodHandle mh) { - if (!data.needsCallee()) { - return mh; - } - final MethodType type = mh.type(); - assert type.parameterType(0) == ScriptFunction.class; - assert type.parameterType(1) == Object.class; - final MethodType newType = type.changeParameterType(0, Object.class).changeParameterType(1, ScriptFunction.class); - final int[] reorder = new int[type.parameterCount()]; - reorder[0] = 1; - assert reorder[1] == 0; - for (int i = 2; i < reorder.length; ++i) { - reorder[i] = i; - } - return MethodHandles.permuteArguments(mh, newType, reorder); - } - - @SuppressWarnings("unused") - private static Object newFilter(final Object result, final Object allocation) { - return (result instanceof ScriptObject || !JSType.isPrimitive(result))? result : allocation; + return new GuardedInvocation(pairArguments(data.getBestConstructor(type), type), null, NashornGuards.getFunctionGuard(this)); } @SuppressWarnings("unused") private static Object wrapFilter(final Object obj) { - if (obj instanceof ScriptObject || !isPrimitiveThis(obj)) { + if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) { return obj; } return ((GlobalObject) Context.getGlobalTrusted()).wrapAsObject(obj); @@ -792,7 +488,7 @@ public abstract class ScriptFunction extends ScriptObject { MethodHandle guard = null; if (data.needsCallee()) { - final MethodHandle callHandle = getBestSpecializedInvokeHandle(type); + final MethodHandle callHandle = getBestInvoker(type); if (NashornCallSiteDescriptor.isScope(desc)) { // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined @@ -808,7 +504,7 @@ public abstract class ScriptFunction extends ScriptObject { // If so add a to-object-wrapper argument filter. // Else install a guard that will trigger a relink when the argument becomes primitive. if (needsWrappedThis()) { - if (isPrimitiveThis(request.getArguments()[1])) { + if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) { boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER); } else { guard = NashornGuards.getNonStrictFunctionGuard(this); @@ -816,7 +512,7 @@ public abstract class ScriptFunction extends ScriptObject { } } } else { - final MethodHandle callHandle = getBestSpecializedInvokeHandle(type.dropParameterTypes(0, 1)); + final MethodHandle callHandle = getBestInvoker(type.dropParameterTypes(0, 1)); if (NashornCallSiteDescriptor.isScope(desc)) { // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined @@ -840,39 +536,13 @@ public abstract class ScriptFunction extends ScriptObject { * These don't want a callee parameter, so bind that. Name binding is optional. */ MethodHandle getCallMethodHandle(final MethodType type, final String bindName) { - return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(getBestSpecializedInvokeHandle(type)), bindName), type); + return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(getBestInvoker(type)), bindName), type); } private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) { return bindName == null ? methodHandle : MH.insertArguments(methodHandle, 1, bindName); } - /** - * Convert this argument for non-strict functions according to ES 10.4.3 - * - * @param thiz the this argument - * - * @return the converted this object - */ - protected Object convertThisObject(final Object thiz) { - if (!(thiz instanceof ScriptObject) && needsWrappedThis()) { - if (JSType.nullOrUndefined(thiz)) { - return Context.getGlobalTrusted(); - } - - if (isPrimitiveThis(thiz)) { - return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(thiz); - } - } - - return thiz; - } - - private static boolean isPrimitiveThis(Object obj) { - return obj instanceof String || obj instanceof ConsString || - obj instanceof Number || obj instanceof Boolean; - } - private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { final Class own = ScriptFunction.class; final MethodType mt = MH.type(rtype, types); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java index a701ceabeb7..3366993cdf1 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java @@ -25,9 +25,12 @@ package jdk.nashorn.internal.runtime; +import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; +import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import static jdk.nashorn.internal.runtime.linker.Lookup.MH; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.parser.Token; @@ -39,12 +42,15 @@ import jdk.nashorn.internal.parser.TokenType; * constants array to reduce function instantiation overhead during runtime. */ public final class ScriptFunctionData { + private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class); + private static final MethodHandle NEWFILTER = findOwnMH("newFilter", Object.class, Object.class, Object.class); // per-function object flags - private static final int IS_STRICT = 0b0000_0001; - private static final int IS_BUILTIN = 0b0000_0010; - private static final int HAS_CALLEE = 0b0000_0100; - private static final int IS_VARARGS = 0b0000_1000; + private static final int IS_STRICT = 0b0000_0001; + private static final int IS_BUILTIN = 0b0000_0010; + private static final int HAS_CALLEE = 0b0000_0100; + private static final int IS_VARARGS = 0b0000_1000; + private static final int IS_CONSTRUCTOR = 0b0001_0000; /** Name of the function or "" */ private final String name; @@ -56,22 +62,21 @@ public final class ScriptFunctionData { private final long token; /** Number of expected arguments, either taken from FunctionNode or calculated from method handle signature*/ private int arity; - /** Does this function need a callee argument? */ private final int flags; /** Reference to code for this method. */ private MethodHandle invoker; - /** Reference to code for this method when called to create "new" object */ + /** Reference to code for this method when called to create "new" object. This must always be populated with a + * result of calling {@link #composeConstructor(MethodHandle)} on the value of the {@link #invoker} field. */ private MethodHandle constructor; /** Constructor to create a new instance. */ private MethodHandle allocator; /** Generic invoker to used in {@link ScriptFunction#invoke(Object, Object...)}. */ private MethodHandle genericInvoker; - /** Generic constructor used in {@link ScriptFunction#construct(Object, Object...)}. */ - private MethodHandle genericConstructor; /** Specializations - see @SpecializedFunction */ private MethodHandle[] invokeSpecializations; - /** Specializations - see @SpecializedFunction */ + /** Specializations - see @SpecializedFunction. Same restrictions as for {@link #constructor} apply; only populate + * with method handles returned from {@link #composeConstructor(MethodHandle)}. */ private MethodHandle[] constructSpecializations; /** @@ -91,7 +96,7 @@ public final class ScriptFunctionData { this.allocatorMap = allocatorMap; this.token = Token.toDesc(TokenType.FUNCTION, position, length); this.arity = fn.getParameters().size(); - this.flags = makeFlags(fn.needsCallee(), fn.isVarArg(), fn.isStrictMode(), false); + this.flags = makeFlags(fn.needsCallee(), fn.isVarArg(), fn.isStrictMode(), false, true); } /** @@ -102,55 +107,59 @@ public final class ScriptFunctionData { * @param strict strict flag * @param builtin builtin flag */ - public ScriptFunctionData(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict, final boolean builtin) { - this.name = name; - this.source = null; - this.token = 0; + public ScriptFunctionData(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict, final boolean builtin, final boolean isConstructor) { + this(name, null, 0L, methodHandle, specs, strict, builtin, isConstructor); + } - final MethodType type = methodHandle.type(); - final int paramCount = type.parameterCount(); - final boolean isVarArg = type.parameterType(paramCount - 1).isArray(); + private ScriptFunctionData(final String name, final Source source, final long token, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict, final boolean builtin, final boolean isConstructor) { + this.name = name; + this.source = source; + this.token = token; + + final boolean isVarArg = isVarArg(methodHandle); final boolean needsCallee = needsCallee(methodHandle); - this.flags = makeFlags(needsCallee, isVarArg, strict, builtin); - this.arity = isVarArg ? -1 : paramCount - 1; //drop the self param for arity + this.flags = makeFlags(needsCallee, isVarArg, strict, builtin, isConstructor); + int lArity = isVarArg ? -1 : methodHandle.type().parameterCount() - 1; //drop the self param for arity if (needsCallee && !isVarArg) { - this.arity--; + lArity--; } if (isConstructor(methodHandle)) { + assert isConstructor; if (!isVarArg) { - this.arity--; // drop the boolean flag for arity + lArity--; // drop the boolean flag for arity } /* - * We insert a boolean argument to tell if the method was invoked as - * constructor or not if the method handle's first argument is boolean. + * We insert a boolean argument to tell if the method was invoked as constructor or not if the method + * handle's first argument is boolean. */ this.invoker = MH.insertArguments(methodHandle, 0, false); - this.constructor = adaptConstructor(MH.insertArguments(methodHandle, 0, true)); + this.constructor = composeConstructor(MH.insertArguments(methodHandle, 0, true)); if (specs != null) { this.invokeSpecializations = new MethodHandle[specs.length]; this.constructSpecializations = new MethodHandle[specs.length]; for (int i = 0; i < specs.length; i++) { this.invokeSpecializations[i] = MH.insertArguments(specs[i], 0, false); - this.constructSpecializations[i] = adaptConstructor(MH.insertArguments(specs[i], 0, true)); + this.constructSpecializations[i] = composeConstructor(MH.insertArguments(specs[i], 0, true)); } } } else { this.invoker = methodHandle; - this.constructor = adaptConstructor(methodHandle); + this.constructor = null; // delay composition of the constructor this.invokeSpecializations = specs; - this.constructSpecializations = specs; + this.constructSpecializations = null; // delay composition of the constructors } + this.arity = lArity; } /** * Get the arity of the function. * @return the arity */ - public int getArity() { + int getArity() { return arity; } @@ -158,7 +167,7 @@ public final class ScriptFunctionData { * Set the arity of the function. * @param arity the arity */ - public void setArity(int arity) { + void setArity(int arity) { this.arity = arity; } @@ -166,24 +175,16 @@ public final class ScriptFunctionData { * Get the function name. * @return function name */ - public String getName() { + String getName() { return name; } - /** - * Get the source of the function. - * @return the source - */ - public Source getSource() { - return source; - } - /** * Get this function as a String containing its source code. If no source code * exists in this ScriptFunction, its contents will be displayed as {@code [native code]} * @return string representation of this function's source */ - public String toSource() { + String toSource() { if (source != null && token != 0) { return source.getString(Token.descPosition(token), Token.descLength(token)); } @@ -212,27 +213,11 @@ public final class ScriptFunctionData { return sb.toString(); } - /** - * Get the allocator property map. - * @return the allocator map - */ - public PropertyMap getAllocatorMap() { - return allocatorMap; - } - - /** - * Get the function's parse token. - * @return the token - */ - public long getToken() { - return token; - } - /** * Returns true if the function needs a callee argument. * @return the needsCallee flag */ - public boolean needsCallee() { + boolean needsCallee() { return (flags & HAS_CALLEE) != 0; } @@ -248,15 +233,23 @@ public final class ScriptFunctionData { * Returns true if this is a built-in function. * @return the built-in flag */ - public boolean isBuiltin() { + private boolean isBuiltin() { return (flags & IS_BUILTIN) != 0; } + /** + * Returns true if this function can be used as a constructor. + * @return the constructor flag + */ + private boolean isConstructor() { + return (flags & IS_CONSTRUCTOR) != 0; + } + /** * Returns true if this is a var-arg function. * @return the var-arg flag */ - public boolean isVarArg() { + private boolean isVarArg() { return (flags & IS_VARARGS) != 0; } @@ -265,7 +258,7 @@ public final class ScriptFunctionData { * according to ECMA 10.4.3. * @return true if this argument must be an object */ - public boolean needsWrappedThis() { + boolean needsWrappedThis() { return (flags & (IS_STRICT | IS_BUILTIN)) == 0; } @@ -273,72 +266,164 @@ public final class ScriptFunctionData { * Get the method handle used to invoke this function. * @return the invoke handle */ - public MethodHandle getInvoker() { + MethodHandle getInvoker() { return invoker; } + MethodHandle getBestInvoker(final MethodType type) { + return SpecializedMethodChooser.candidateWithLowestWeight(type, invoker, invokeSpecializations); + } + /** * Get the method handle used to invoke this function as a constructor. * @return the constructor handle */ - public MethodHandle getConstructor() { + private MethodHandle getConstructor() { + if (constructor == null) { + constructor = composeConstructor(invoker); + } + return constructor; } - /** - * Set the constructor method handle. - * @param constructor the constructor handle - */ - public void setConstructor(MethodHandle constructor) { - this.constructor = constructor; - this.constructSpecializations = null; + MethodHandle getBestConstructor(MethodType descType) { + if (!isConstructor()) { + typeError("not.a.constructor", toSource()); + } + return SpecializedMethodChooser.candidateWithLowestWeight(descType, getConstructor(), getConstructSpecializations()); } - /** - * Get the method handle used to allocate a new object for this constructor. - * @return the allocator handle - */ - public MethodHandle getAllocator() { - return allocator; + private MethodHandle composeConstructor(MethodHandle ctor) { + // If it was (callee, this, args...), permute it to (this, callee, args...). We're doing this because having + // "this" in the first argument position is what allows the elegant folded composition of + // (newFilter x constructor x allocator) further down below in the code. Also, ensure the composite constructor + // always returns Object. + MethodHandle composedCtor = changeReturnTypeToObject(swapCalleeAndThis(ctor)); + + final MethodType ctorType = composedCtor.type(); + // Construct a dropping type list for NEWFILTER, but don't include constructor "this" into it, so it's actually + // captured as "allocation" parameter of NEWFILTER after we fold the constructor into it. + // (this, [callee, ]args...) => ([callee, ]args...) + final Class[] ctorArgs = ctorType.dropParameterTypes(0, 1).parameterArray(); + // Fold constructor into newFilter that replaces the return value from the constructor with the originally + // allocated value when the originally allocated value is a primitive. + // (result, this, [callee, ]args...) x (this, [callee, ]args...) => (this, [callee, ]args...) + composedCtor = MH.foldArguments(MH.dropArguments(NEWFILTER, 2, ctorArgs), composedCtor); + + // allocate() takes a ScriptFunction and returns a newly allocated ScriptObject... + if (needsCallee()) { + // ...we either fold it into the previous composition, if we need both the ScriptFunction callee object and + // the newly allocated object in the arguments, so (this, callee, args...) x (callee) => (callee, args...), + // or... + return MH.foldArguments(composedCtor, ScriptFunction.ALLOCATE); + } + // ...replace the ScriptFunction argument with the newly allocated object, if it doesn't need the callee + // (this, args...) filter (callee) => (callee, args...) + return MH.filterArguments(composedCtor, 0, ScriptFunction.ALLOCATE); } /** * Get an adapted version of the invoker handle that only uses {@code Object} as parameter and return types. * @return the generic invoke handle */ - public MethodHandle getGenericInvoker() { + private MethodHandle getGenericInvoker() { if (genericInvoker == null) { assert invoker != null : "invoker is null"; - genericInvoker = adaptMethodType(invoker); + genericInvoker = makeGenericMethod(invoker); } return genericInvoker; } /** - * Get an adapted version of the constructor handle that only uses {@code Object} as parameter and return types. - * @return the generic constructor handle + * Execute this script function. + * @param self Target object. + * @param arguments Call arguments. + * @return ScriptFunction result. + * @throws Throwable if there is an exception/error with the invocation or thrown from it */ - public MethodHandle getGenericConstructor() { - if (genericConstructor == null) { - assert constructor != null : "constructor is null"; - genericConstructor = adaptMethodType(constructor); + Object invoke(final ScriptFunction fn, final Object self, final Object... arguments) throws Throwable { + final MethodHandle genInvoker = getGenericInvoker(); + final Object selfObj = convertThisObject(self); + final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; + + if (isVarArg()) { + if (needsCallee()) { + return genInvoker.invokeExact(fn, selfObj, args); + } + return genInvoker.invokeExact(selfObj, args); + } + + final int paramCount = genInvoker.type().parameterCount(); + if (needsCallee()) { + switch (paramCount) { + case 2: + return genInvoker.invokeExact(fn, selfObj); + case 3: + return genInvoker.invokeExact(fn, selfObj, getArg(args, 0)); + case 4: + return genInvoker.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1)); + case 5: + return genInvoker.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + default: + return genInvoker.invokeWithArguments(withArguments(fn, selfObj, paramCount, args)); + } + } + + switch (paramCount) { + case 1: + return genInvoker.invokeExact(selfObj); + case 2: + return genInvoker.invokeExact(selfObj, getArg(args, 0)); + case 3: + return genInvoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1)); + case 4: + return genInvoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); + default: + return genInvoker.invokeWithArguments(withArguments(null, selfObj, paramCount, args)); } - return genericConstructor; } - /** - * Get the specialized invoke handles for this function. - * @return array of specialized invoke handles - */ - public MethodHandle[] getInvokeSpecializations() { - return invokeSpecializations; + private static Object getArg(final Object[] args, final int i) { + return i < args.length ? args[i] : UNDEFINED; + } + + private Object[] withArguments(final ScriptFunction fn, final Object self, final int argCount, final Object[] args) { + final Object[] finalArgs = new Object[argCount]; + + int nextArg = 0; + if (needsCallee()) { + assert fn != null; + finalArgs[nextArg++] = fn; + } else { + assert fn == null; + } + finalArgs[nextArg++] = self; + + // Don't add more args that there is argCount in the handle (including self and callee). + for (int i = 0; i < args.length && nextArg < argCount;) { + finalArgs[nextArg++] = args[i++]; + } + + // If we have fewer args than argCount, pad with undefined. + while (nextArg < argCount) { + finalArgs[nextArg++] = UNDEFINED; + } + + return finalArgs; } /** * Get the specialized construct handles for this function. * @return array of specialized construct handles */ - public MethodHandle[] getConstructSpecializations() { + private MethodHandle[] getConstructSpecializations() { + if(constructSpecializations == null && invokeSpecializations != null) { + final MethodHandle[] ctors = new MethodHandle[invokeSpecializations.length]; + for(int i = 0; i < ctors.length; ++i) { + ctors[i] = composeConstructor(invokeSpecializations[i]); + } + constructSpecializations = ctors; + } return constructSpecializations; } @@ -352,11 +437,227 @@ public final class ScriptFunctionData { // and they're set when first called, so we enforce set-once here. if (this.invoker == null) { this.invoker = invoker; - this.constructor = adaptConstructor(invoker); + this.constructor = null; // delay constructor composition this.allocator = allocator; } } + /** + * Allocates an object using this function's allocator. + * @return the object allocated using this function's allocator, or null if the function doesn't have an allocator. + */ + ScriptObject allocate() { + if (allocator == null) { + return null; + } + + try { + return (ScriptObject)allocator.invokeExact(allocatorMap); + } catch (final RuntimeException | Error e) { + throw e; + } catch (final Throwable t) { + throw new RuntimeException(t); + } + } + + /** + * This method is used to create the immutable portion of a bound function. + * See {@link ScriptFunction#makeBoundFunction(Object, Object[])} + * + * @param fn the original function being bound + * @param self this reference to bind. Can be null. + * @param args additional arguments to bind. Can be null. + */ + ScriptFunctionData makeBoundFunctionData(final ScriptFunction fn, final Object self, final Object[] args) { + final Object[] allArgs = args == null ? ScriptRuntime.EMPTY_ARRAY : args; + + final boolean isConstructor = isConstructor(); + // Note that the new ScriptFunctionData's method handle will not need a callee regardless of whether the + // original did. + final ScriptFunctionData boundData = new ScriptFunctionData(name, source, token, + bindInvokeHandle(invoker, fn, self, allArgs), bindInvokeSpecializations(fn, self, allArgs), isStrict(), isBuiltin(), isConstructor); + if(isConstructor) { + // Can't just rely on bound invoke as a basis for constructor, as it ignores the passed "this" in favor of the + // bound "this"; constructor on the other hand must see the actual "this" received from the allocator. + + // Binding a function will force constructor composition in getConstructor(); not really any way around that + // as it's the composed constructor that has to be bound to the function. + boundData.constructor = bindConstructHandle(getConstructor(), fn, allArgs); + boundData.constructSpecializations = bindConstructorSpecializations(fn, allArgs); + } + assert boundData.allocator == null; + final int thisArity = getArity(); + if(thisArity != -1) { + boundData.setArity(Math.max(0, thisArity - args.length)); + } else { + assert boundData.getArity() == -1; + } + return boundData; + } + + /** + * Convert this argument for non-strict functions according to ES 10.4.3 + * + * @param thiz the this argument + * + * @return the converted this object + */ + Object convertThisObject(final Object thiz) { + if (!(thiz instanceof ScriptObject) && needsWrappedThis()) { + if (JSType.nullOrUndefined(thiz)) { + return Context.getGlobalTrusted(); + } + + if (isPrimitiveThis(thiz)) { + return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(thiz); + } + } + + return thiz; + } + + static boolean isPrimitiveThis(Object obj) { + return obj instanceof String || obj instanceof ConsString || + obj instanceof Number || obj instanceof Boolean; + } + + /** + * Creates an invoker method handle for a bound function. + * @param targetFn the function being bound + * @param originalInvoker an original invoker method handle for the function. This can be its generic invoker or + * any of its specializations. + * @param self the "this" value being bound + * @param args additional arguments being bound + * @return a bound invoker method handle that will bind the self value and the specified arguments. The resulting + * invoker never needs a callee; if the original invoker needed it, it will be bound to {@code fn}. The resulting + * invoker still takes an initial {@code this} parameter, but it is always dropped and the bound {@code self} passed + * to the original invoker on invocation. + */ + private MethodHandle bindInvokeHandle(final MethodHandle originalInvoker, final ScriptFunction targetFn, final Object self, final Object[] args) { + // Is the target already bound? If it is, we won't bother binding either callee or self as they're already bound + // in the target and will be ignored anyway. + final boolean isTargetBound = targetFn.isBoundFunction(); + assert !(isTargetBound && needsCallee()); // already bound functions don't need a callee + final Object boundSelf = isTargetBound ? null : convertThisObject(self); + final MethodHandle boundInvoker; + if(isVarArg(originalInvoker)) { + // First, bind callee and this without arguments + final MethodHandle noArgBoundInvoker; + if(isTargetBound) { + // Don't bind either callee or this + noArgBoundInvoker = originalInvoker; + } else if(needsCallee()) { + // Bind callee and this + noArgBoundInvoker = MH.insertArguments(originalInvoker, 0, targetFn, boundSelf); + } else { + // Only bind this + noArgBoundInvoker = MH.bindTo(originalInvoker, boundSelf); + } + // Now bind arguments + if(args.length > 0) { + boundInvoker = varArgBinder(noArgBoundInvoker, args); + } else { + boundInvoker = noArgBoundInvoker; + } + } else { + final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount(), + args.length + (isTargetBound ? 0 : (needsCallee() ? 2 : 1)))]; + int next = 0; + if(!isTargetBound) { + if(needsCallee()) { + boundArgs[next++] = targetFn; + } + boundArgs[next++] = boundSelf; + } + // If more bound args were specified than the function can take, we'll just drop those. + System.arraycopy(args, 0, boundArgs, next, boundArgs.length - next); + // If target is already bound, insert additional bound arguments after "this" argument, at position 1; + // "this" will get dropped anyway by the target invoker. We previously asserted that already bound functions + // don't take a callee parameter, so we can know that the signature is (this[, args...]) therefore args + // start at position 1. If the function is not bound, we start inserting arguments at position 0. + boundInvoker = MH.insertArguments(originalInvoker, isTargetBound ? 1 : 0, boundArgs); + } + if(isTargetBound) { + return boundInvoker; + } + // If the target is not already bound, add a dropArguments that'll throw away the passed this + return MH.dropArguments(boundInvoker, 0, Object.class); + } + + private MethodHandle[] bindInvokeSpecializations(final ScriptFunction fn, final Object self, final Object[] args) { + if(invokeSpecializations == null) { + return null; + } + final MethodHandle[] boundSpecializations = new MethodHandle[invokeSpecializations.length]; + for(int i = 0; i < invokeSpecializations.length; ++i) { + boundSpecializations[i] = bindInvokeHandle(invokeSpecializations[i], fn, self, args); + } + return boundSpecializations; + } + + /** + * Creates a constructor method handle for a bound function using the passed constructor handle. + * @param originalConstructor the constructor handle to bind. It must be a composed constructor. + * @param fn the function being bound + * @param args arguments being bound + * @return a bound constructor method handle that will bind the specified arguments. The resulting constructor never + * needs a callee; if the original constructor needed it, it will be bound to {@code fn}. The resulting constructor + * still takes an initial {@code this} parameter and passes it to the underlying original constructor. Finally, if + * this script function data object has no constructor handle, null is returned. + */ + private static MethodHandle bindConstructHandle(final MethodHandle originalConstructor, final ScriptFunction fn, final Object[] args) { + if(originalConstructor == null) { + return null; + } + + // If target function is already bound, don't bother binding the callee. + final MethodHandle calleeBoundConstructor = fn.isBoundFunction() ? originalConstructor : + MH.dropArguments(MH.bindTo(originalConstructor, fn), 0, ScriptFunction.class); + if(args.length == 0) { + return calleeBoundConstructor; + } + + if(isVarArg(calleeBoundConstructor)) { + return varArgBinder(calleeBoundConstructor, args); + } + + final Object[] boundArgs; + final int maxArgCount = calleeBoundConstructor.type().parameterCount() - 1; + if (args.length <= maxArgCount) { + boundArgs = args; + } else { + boundArgs = new Object[maxArgCount]; + System.arraycopy(args, 0, boundArgs, 0, maxArgCount); + } + return MH.insertArguments(calleeBoundConstructor, 1, boundArgs); + } + + private MethodHandle[] bindConstructorSpecializations(final ScriptFunction fn, final Object[] args) { + final MethodHandle[] ctorSpecs = getConstructSpecializations(); + if(ctorSpecs == null) { + return null; + } + final MethodHandle[] boundSpecializations = new MethodHandle[ctorSpecs.length]; + for(int i = 0; i < ctorSpecs.length; ++i) { + boundSpecializations[i] = bindConstructHandle(ctorSpecs[i], fn, args); + } + return boundSpecializations; + } + + /** + * Takes a variable-arity method and binds a variable number of arguments in it. The returned method will filter the + * vararg array and pass a different array that prepends the bound arguments in front of the arguments passed on + * invocation + * @param mh the handle + * @param args the bound arguments + * @return the bound method handle + */ + private static MethodHandle varArgBinder(final MethodHandle mh, final Object[] args) { + assert args != null; + assert args.length > 0; + return MH.filterArguments(mh, mh.type().parameterCount() - 1, MH.bindTo(BIND_VAR_ARGS, args)); + } + /** * Convert boolean flags to int. * @param needsCallee needs-callee flag @@ -365,7 +666,7 @@ public final class ScriptFunctionData { * @param isBuiltin builtin flag * @return int flags */ - private static int makeFlags(final boolean needsCallee, final boolean isVarArg, final boolean isStrict, final boolean isBuiltin) { + private static int makeFlags(final boolean needsCallee, final boolean isVarArg, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) { int flags = 0; if (needsCallee) { flags |= HAS_CALLEE; @@ -379,6 +680,10 @@ public final class ScriptFunctionData { if (isBuiltin) { flags |= IS_BUILTIN; } + if (isConstructor) { + flags |= IS_CONSTRUCTOR; + } + return flags; } @@ -412,6 +717,11 @@ public final class ScriptFunctionData { return type.parameterType(0) == ScriptFunction.class; } + private static boolean isVarArg(MethodHandle methodHandle) { + final MethodType type = methodHandle.type(); + return type.parameterType(type.parameterCount() - 1).isArray(); + } + /** * Takes a method handle, and returns a potentially different method handle that can be used in * {@link ScriptFunction#invoke(Object, Object...)} or {@link ScriptFunction#construct(Object, Object...)}. @@ -419,14 +729,14 @@ public final class ScriptFunctionData { * {@code Object} as well, except for the following ones: *
        *
      • a last parameter of type {@code Object[]} which is used for vararg functions,
      • - *
      • the second argument, which is forced to be {@link ScriptFunction}, in case the function receives itself - * (callee) as an argument
      • + *
      • the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself + * (callee) as an argument.
      • *
      * * @param handle the original method handle * @return the new handle, conforming to the rules above. */ - private MethodHandle adaptMethodType(final MethodHandle handle) { + private MethodHandle makeGenericMethod(final MethodHandle handle) { final MethodType type = handle.type(); MethodType newType = type.generic(); if (isVarArg()) { @@ -438,17 +748,6 @@ public final class ScriptFunctionData { return type.equals(newType) ? handle : handle.asType(newType); } - /** - * Adapts a method handle to conform to requirements of a constructor. Right now this consists of making sure its - * return value is {@code Object}. We might consider moving the caller-this argument swap here too from - * {@link ScriptFunction#findNewMethod(org.dynalang.dynalink.CallSiteDescriptor)}. - * @param ctorHandle the constructor method handle - * @return adapted constructor method handle - */ - private static MethodHandle adaptConstructor(final MethodHandle ctorHandle) { - return changeReturnTypeToObject(ctorHandle); - } - /** * Adapts the method handle so its return type is {@code Object}. If the handle's return type is already * {@code Object}, the handle is returned unchanged. @@ -458,4 +757,56 @@ public final class ScriptFunctionData { private static MethodHandle changeReturnTypeToObject(final MethodHandle mh) { return MH.asType(mh, mh.type().changeReturnType(Object.class)); } + + + /** + * If this function's method handles need a callee parameter, swap the order of first two arguments for the passed + * method handle. If this function's method handles don't need a callee parameter, returns the original method + * handle unchanged. + * @param mh a method handle with order of arguments {@code (callee, this, args...)} + * @return a method handle with order of arguments {@code (this, callee, args...)} + */ + private MethodHandle swapCalleeAndThis(final MethodHandle mh) { + if (!needsCallee()) { + return mh; + } + final MethodType type = mh.type(); + assert type.parameterType(0) == ScriptFunction.class; + assert type.parameterType(1) == Object.class; + final MethodType newType = type.changeParameterType(0, Object.class).changeParameterType(1, ScriptFunction.class); + final int[] reorder = new int[type.parameterCount()]; + reorder[0] = 1; + assert reorder[1] == 0; + for (int i = 2; i < reorder.length; ++i) { + reorder[i] = i; + } + return MethodHandles.permuteArguments(mh, newType, reorder); + } + + @SuppressWarnings("unused") + private static Object[] bindVarArgs(final Object[] array1, final Object[] array2) { + if(array2 == null) { + // Must clone it, as we can't allow the receiving method to alter the array + return array1.clone(); + } + final int l2 = array2.length; + if(l2 == 0) { + return array1.clone(); + } + final int l1 = array1.length; + final Object[] concat = new Object[l1 + l2]; + System.arraycopy(array1, 0, concat, 0, l1); + System.arraycopy(array2, 0, concat, l1, l2); + return concat; + } + + @SuppressWarnings("unused") + private static Object newFilter(final Object result, final Object allocation) { + return (result instanceof ScriptObject || !JSType.isPrimitive(result))? result : allocation; + } + + private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { + return MH.findStatic(MethodHandles.lookup(), ScriptFunctionData.class, name, MH.type(rtype, types)); + } + } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java index 4b455621f24..f491d388a91 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java @@ -321,24 +321,6 @@ public final class ScriptRuntime { } } - /** - * Constructor new object using given constructor function - * @param target ScriptFunction object. - * @param args Constructor arguments. - * @return newly constructed object. - */ - public static Object construct(final ScriptFunction target, final Object... args) { - try { - final ScriptObject allocation = (ScriptObject)target.allocate(); - final Object result = target.construct(allocation, args); - return result instanceof ScriptObject ? result : allocation; - } catch (final RuntimeException | Error e) { - throw e; - } catch (final Throwable t) { - throw new RuntimeException(t); - } - } - /** * Generic implementation of ECMA 9.12 - SameValue algorithm * diff --git a/nashorn/src/jdk/nashorn/internal/runtime/SpecializedMethodChooser.java b/nashorn/src/jdk/nashorn/internal/runtime/SpecializedMethodChooser.java new file mode 100644 index 00000000000..2853cdf2464 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/runtime/SpecializedMethodChooser.java @@ -0,0 +1,99 @@ +/* + * 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 jdk.nashorn.internal.runtime; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.runtime.options.Options; + +class SpecializedMethodChooser { + /** Should specialized function and specialized constructors for the builtin be used if available? */ + private static final boolean DISABLE_SPECIALIZATION = Options.getBooleanProperty("nashorn.scriptfunction.specialization.disable"); + + static MethodHandle candidateWithLowestWeight(final MethodType descType, final MethodHandle initialCandidate, final MethodHandle[] specs) { + if (DISABLE_SPECIALIZATION || specs == null) { + return initialCandidate; + } + + int minimumWeight = Integer.MAX_VALUE; + MethodHandle candidate = initialCandidate; + + for (final MethodHandle spec : specs) { + final MethodType specType = spec.type(); + + if (!typeCompatible(descType, specType)) { + continue; + } + + //return type is ok. we want a wider or equal one for our callsite. + final int specWeight = weigh(specType); + if (specWeight < minimumWeight) { + candidate = spec; + minimumWeight = specWeight; + } + } + + return candidate; + } + + private static boolean typeCompatible(final MethodType desc, final MethodType spec) { + //spec must fit in desc + final Class[] dparray = desc.parameterArray(); + final Class[] sparray = spec.parameterArray(); + + if (dparray.length != sparray.length) { + return false; + } + + for (int i = 0; i < dparray.length; i++) { + final Type dp = Type.typeFor(dparray[i]); + final Type sp = Type.typeFor(sparray[i]); + + if (dp.isBoolean()) { + return false; //don't specialize on booleans, we have the "true" vs int 1 ambiguity in resolution + } + + //specialization arguments must be at least as wide as dp, if not wider + if (Type.widest(dp, sp) != sp) { + //e.g. specialization takes double and callsite says "object". reject. + //but if specialization says double and callsite says "int" or "long" or "double", that's fine + return false; + } + } + + return true; // anything goes for return type, take the convenient one and it will be upcasted thru dynalink magic. + } + + private static int weigh(final MethodType t) { + int weight = Type.typeFor(t.returnType()).getWeight(); + for (final Class paramType : t.parameterArray()) { + final int pweight = Type.typeFor(paramType).getWeight(); + weight += pweight; + } + return weight; + } +} diff --git a/nashorn/test/script/basic/funcbind2.js b/nashorn/test/script/basic/funcbind2.js new file mode 100644 index 00000000000..697ee5292da --- /dev/null +++ b/nashorn/test/script/basic/funcbind2.js @@ -0,0 +1,94 @@ +/* + * 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 the functionality of Function.prototype.bind. + * + * @test + * @run + */ + +function f(a, b) { + print("f: this=" + this + ", a=" + a + ", b=" + b); +} +function v(a, b) { + print("v: this=" + this + ", a=" + a + ", b=" + b + ", c=" + arguments[2]); +} + +(f.bind(null))(); +(v.bind(null))(); + +var boundThis = "boundThis"; +(f.bind(boundThis))(); +(v.bind(boundThis))(); + +(f.bind(boundThis))("a0"); +(v.bind(boundThis))("a1"); + +(f.bind(boundThis, "a2"))(); +(v.bind(boundThis, "a3"))(); + +(f.bind(boundThis, "a4"))("b4"); +(v.bind(boundThis, "a5"))("b5"); + +(f.bind(boundThis, "a6", "b6"))(); +(v.bind(boundThis, "a7", "b7"))(); + +(f.bind(boundThis, "a8", "b8"))("c8"); // invoking with extra args after all were bound! +(v.bind(boundThis, "a9", "b9"))("c9"); + +(f.bind(boundThis, "a10", "b10", "c10"))(); // binding more args than it receives! +(v.bind(boundThis, "a11", "b11", "c11"))(); + +print("\nTest constructors\n"); + +new (f.bind(boundThis))(); +new (v.bind(boundThis))(); + +new (f.bind(boundThis))("a0"); +new (v.bind(boundThis))("a1"); + +new (f.bind(boundThis, "a2"))(); +new (v.bind(boundThis, "a3"))(); + +new (f.bind(boundThis, "a4"))("b4"); +new (v.bind(boundThis, "a5"))("b5"); + +new (f.bind(boundThis, "a6", "b6"))(); +new (v.bind(boundThis, "a7", "b7"))(); + +new (f.bind(boundThis, "a8", "b8"))("c8"); +new (v.bind(boundThis, "a9", "b9"))("c9"); + +new (f.bind(boundThis, "a10", "b10", "c10"))(); +new (v.bind(boundThis, "a11", "b11", "c11"))(); + +print("\nTest double binding\n"); + +(f.bind(boundThis).bind("thisIsIgnored"))(); +new (f.bind("thisIsIgnored").bind("thisIsIgnoredToo"))(); +new (f.bind("thisIsIgnored", "a12").bind("thisIsIgnoredToo"))(); + +(v.bind(boundThis).bind("thisIsIgnored"))(); +new (v.bind("thisIsIgnored").bind("thisIsIgnoredToo"))(); +new (v.bind("thisIsIgnored", "a13").bind("thisIsIgnoredToo"))(); diff --git a/nashorn/test/script/basic/funcbind2.js.EXPECTED b/nashorn/test/script/basic/funcbind2.js.EXPECTED new file mode 100644 index 00000000000..5b874535252 --- /dev/null +++ b/nashorn/test/script/basic/funcbind2.js.EXPECTED @@ -0,0 +1,42 @@ +f: this=[object global], a=undefined, b=undefined +v: this=[object global], a=undefined, b=undefined, c=undefined +f: this=boundThis, a=undefined, b=undefined +v: this=boundThis, a=undefined, b=undefined, c=undefined +f: this=boundThis, a=a0, b=undefined +v: this=boundThis, a=a1, b=undefined, c=undefined +f: this=boundThis, a=a2, b=undefined +v: this=boundThis, a=a3, b=undefined, c=undefined +f: this=boundThis, a=a4, b=b4 +v: this=boundThis, a=a5, b=b5, c=undefined +f: this=boundThis, a=a6, b=b6 +v: this=boundThis, a=a7, b=b7, c=undefined +f: this=boundThis, a=a8, b=b8 +v: this=boundThis, a=a9, b=b9, c=c9 +f: this=boundThis, a=a10, b=b10 +v: this=boundThis, a=a11, b=b11, c=c11 + +Test constructors + +f: this=[object Object], a=undefined, b=undefined +v: this=[object Object], a=undefined, b=undefined, c=undefined +f: this=[object Object], a=a0, b=undefined +v: this=[object Object], a=a1, b=undefined, c=undefined +f: this=[object Object], a=a2, b=undefined +v: this=[object Object], a=a3, b=undefined, c=undefined +f: this=[object Object], a=a4, b=b4 +v: this=[object Object], a=a5, b=b5, c=undefined +f: this=[object Object], a=a6, b=b6 +v: this=[object Object], a=a7, b=b7, c=undefined +f: this=[object Object], a=a8, b=b8 +v: this=[object Object], a=a9, b=b9, c=c9 +f: this=[object Object], a=a10, b=b10 +v: this=[object Object], a=a11, b=b11, c=c11 + +Test double binding + +f: this=boundThis, a=undefined, b=undefined +f: this=[object Object], a=undefined, b=undefined +f: this=[object Object], a=a12, b=undefined +v: this=boundThis, a=undefined, b=undefined, c=undefined +v: this=[object Object], a=undefined, b=undefined, c=undefined +v: this=[object Object], a=a13, b=undefined, c=undefined diff --git a/nashorn/test/script/basic/funcbind3.js b/nashorn/test/script/basic/funcbind3.js new file mode 100644 index 00000000000..25f448d2a87 --- /dev/null +++ b/nashorn/test/script/basic/funcbind3.js @@ -0,0 +1,59 @@ +/* + * 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 the assumptions about bound function prototypes + * + * @test + * @run + */ + +function printAssumption(__x__) { + print(__x__ + ": " + eval(__x__)); +} + +function f() { } + +var b = f.bind(null) + +var x = new f() +var y = new b() + +printAssumption("x instanceof f") +printAssumption("x instanceof b") +printAssumption("y instanceof f") +printAssumption("y instanceof b") + +print("\nChanging prototype\n"); + +f.prototype=new Object() + +printAssumption("x instanceof f") +printAssumption("x instanceof b") +printAssumption("y instanceof f") +printAssumption("y instanceof b") + +print("\Bound function prototype\n"); + +printAssumption("f.hasOwnProperty('prototype')") +printAssumption("b.hasOwnProperty('prototype')") diff --git a/nashorn/test/script/basic/funcbind3.js.EXPECTED b/nashorn/test/script/basic/funcbind3.js.EXPECTED new file mode 100644 index 00000000000..f69126d3e9d --- /dev/null +++ b/nashorn/test/script/basic/funcbind3.js.EXPECTED @@ -0,0 +1,15 @@ +x instanceof f: true +x instanceof b: true +y instanceof f: true +y instanceof b: true + +Changing prototype + +x instanceof f: false +x instanceof b: false +y instanceof f: false +y instanceof b: false +Bound function prototype + +f.hasOwnProperty('prototype'): true +b.hasOwnProperty('prototype'): false From 71666c4c5ac79f96e2987e24c9015b0a03659ed0 Mon Sep 17 00:00:00 2001 From: Mike Duigou Date: Tue, 19 Feb 2013 11:56:49 -0800 Subject: [PATCH 133/311] 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 134/311] 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 135/311] 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 136/311] 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 137/311] 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 138/311] 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 139/311] 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 b8d10c0a0e214f8c87beaab9dd9a425beee0c218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 13 Feb 2013 13:30:21 +0100 Subject: [PATCH 140/311] 8008096: TokenStream buffer should grow exponentially Reviewed-by: attila, lagergren, sundar --- nashorn/src/jdk/nashorn/internal/parser/TokenStream.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nashorn/src/jdk/nashorn/internal/parser/TokenStream.java b/nashorn/src/jdk/nashorn/internal/parser/TokenStream.java index c31f5f4c9f0..ee81ce3921b 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/TokenStream.java +++ b/nashorn/src/jdk/nashorn/internal/parser/TokenStream.java @@ -34,8 +34,8 @@ package jdk.nashorn.internal.parser; * */ public class TokenStream { - /** Buffer growth factor. */ - private static final int growth = 256; + /** Initial buffer size. */ + private static final int INITIAL_SIZE = 256; /** Token buffer. */ private long[] buffer; @@ -56,7 +56,7 @@ public class TokenStream { * Constructor. */ public TokenStream() { - buffer = new long[growth]; + buffer = new long[INITIAL_SIZE]; count = 0; in = 0; out = 0; @@ -193,7 +193,7 @@ public class TokenStream { */ public void grow() { // Allocate new buffer. - final long[] newBuffer = new long[buffer.length + growth]; + final long[] newBuffer = new long[buffer.length * 2]; // If single chunk. if (in > out) { From ecc2be22e3dedc96c6e95d0d9eda2bc571760821 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Wed, 13 Feb 2013 19:59:30 +0530 Subject: [PATCH 141/311] 8008103: Source object should maintain URL of the script source as a private field Reviewed-by: lagergren, jlaskey --- .../api/scripting/NashornScriptEngine.java | 2 +- .../jdk/nashorn/internal/runtime/Context.java | 107 +++++------------- .../jdk/nashorn/internal/runtime/Source.java | 35 +++++- nashorn/src/jdk/nashorn/tools/Shell.java | 2 +- .../internal/codegen/CompilerTest.java | 2 +- .../nashorn/internal/runtime/ContextTest.java | 2 +- .../framework/SharedContextEvaluator.java | 3 +- 7 files changed, 64 insertions(+), 89 deletions(-) diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java index 5217555ff39..ded9afb7e6e 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java @@ -453,7 +453,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C setNashornGlobal(ctxtGlobal); } - return nashornContext.compileScript(source, ctxtGlobal, nashornContext._strict); + return nashornContext.compileScript(source, ctxtGlobal); } catch (final Exception e) { throwAsScriptException(e); throw new AssertionError("should not reach here"); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index 4f5cb1296fd..d220e29948c 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -492,29 +492,11 @@ public final class Context { * * @param source the source * @param scope the scope - * @param strict are we in strict mode * * @return top level function for script */ - public ScriptFunction compileScript(final Source source, final ScriptObject scope, final boolean strict) { - return compileScript(source, scope, this.errors, strict); - } - - /** - * Compile a top level script - no Source given, but an URL to - * load it from - * - * @param name name of script/source - * @param url URL to source - * @param scope the scope - * @param strict are we in strict mode - * - * @return top level function for the script - * - * @throws IOException if URL cannot be resolved - */ - public ScriptFunction compileScript(final String name, final URL url, final ScriptObject scope, final boolean strict) throws IOException { - return compileScript(name, url, scope, this.errors, strict); + public ScriptFunction compileScript(final Source source, final ScriptObject scope) { + return compileScript(source, scope, this.errors); } /** @@ -591,26 +573,25 @@ public final class Context { * expression * * @param scope the scope - * @param source source expression for script + * @param from source expression for script * * @return return value for load call (undefined) * * @throws IOException if source cannot be found or loaded */ - public Object load(final ScriptObject scope, final Object source) throws IOException { - Object src = source; - URL url = null; - String srcName = null; + public Object load(final ScriptObject scope, final Object from) throws IOException { + Object src = (from instanceof ConsString)? from.toString() : from; + Source source = null; - if (src instanceof ConsString) { - src = src.toString(); - } + // load accepts a String (which could be a URL or a file name), a File, a URL + // or a ScriptObject that has "name" and "source" (string valued) properties. if (src instanceof String) { - srcName = (String)src; + String srcStr = (String)src; final File file = new File((String)src); - if (srcName.indexOf(':') != -1) { + if (srcStr.indexOf(':') != -1) { try { - url = new URL((String)src); + final URL url = new URL((String)src); + source = new Source(url.toString(), url); } catch (final MalformedURLException e) { // fallback URL - nashorn:foo.js - check under jdk/nashorn/internal/runtime/resources final String str = (String)src; @@ -618,7 +599,7 @@ public final class Context { final String resource = "resources/" + str.substring("nashorn:".length()); // NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme // These scripts are always available and are loaded from nashorn.jar's resources. - final Source code = AccessController.doPrivileged( + source = AccessController.doPrivileged( new PrivilegedAction() { @Override public Source run() { @@ -630,45 +611,32 @@ public final class Context { } } }); - if (code == null) { - throw e; - } - return evaluateSource(code, scope, scope); } else { throw e; } } } else if (file.isFile()) { - url = file.toURI().toURL(); + source = new Source(srcStr, file); } - src = url; - } - - if (src instanceof File && ((File)src).isFile()) { + } else if (src instanceof File && ((File)src).isFile()) { final File file = (File)src; - url = file.toURI().toURL(); - if (srcName == null) { - srcName = file.getCanonicalPath(); - } + source = new Source(file.getName(), file); } else if (src instanceof URL) { - url = (URL)src; - if (srcName == null) { - srcName = url.toString(); - } - } - - if (url != null) { - assert srcName != null : "srcName null here!"; - return evaluateSource(srcName, url, scope, scope); + final URL url = (URL)src; + source = new Source(url.toString(), url); } else if (src instanceof ScriptObject) { final ScriptObject sobj = (ScriptObject)src; if (sobj.has("script") && sobj.has("name")) { final String script = JSType.toString(sobj.get("script")); final String name = JSType.toString(sobj.get("name")); - return evaluateSource(new Source(name, script), scope, scope); + source = new Source(name, script); } } + if (source != null) { + return evaluateSource(source, scope, scope); + } + typeError("cant.load.script", ScriptRuntime.safeToString(source)); return UNDEFINED; @@ -850,23 +818,11 @@ public final class Context { return (context != null) ? context : Context.getContextTrusted(); } - private Object evaluateSource(final String name, final URL url, final ScriptObject scope, final ScriptObject thiz) throws IOException { - ScriptFunction script = null; - - try { - script = compileScript(name, url, scope, new Context.ThrowErrorManager(), _strict); - } catch (final ParserException e) { - e.throwAsEcmaException(); - } - - return ScriptRuntime.apply(script, thiz); - } - private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) { ScriptFunction script = null; try { - script = compileScript(source, scope, new Context.ThrowErrorManager(), _strict); + script = compileScript(source, scope, new Context.ThrowErrorManager()); } catch (final ParserException e) { e.throwAsEcmaException(); } @@ -902,19 +858,11 @@ public final class Context { return ((GlobalObject)Context.getGlobalTrusted()).newScriptFunction(RUN_SCRIPT.tag(), runMethodHandle, scope, strict); } - private ScriptFunction compileScript(final String name, final URL url, final ScriptObject scope, final ErrorManager errMan, final boolean strict) throws IOException { - return getRunScriptFunction(compile(new Source(name, url), url, errMan, strict), scope); + private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan) { + return getRunScriptFunction(compile(source, errMan, this._strict), scope); } - private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan, final boolean strict) { - return getRunScriptFunction(compile(source, null, errMan, strict), scope); - } - - private Class compile(final Source source, final ErrorManager errMan, final boolean strict) { - return compile(source, null, errMan, strict); - } - - private synchronized Class compile(final Source source, final URL url, final ErrorManager errMan, final boolean strict) { + private synchronized Class compile(final Source source, final ErrorManager errMan, final boolean strict) { // start with no errors, no warnings. errMan.reset(); @@ -935,6 +883,7 @@ public final class Context { return null; } + final URL url = source.getURL(); final ScriptLoader loader = _loader_per_compile ? createNewLoader() : scriptLoader; final CodeSource cs = url == null ? null : new CodeSource(url, (CodeSigner[])null); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Source.java b/nashorn/src/jdk/nashorn/internal/runtime/Source.java index 822e0bb5242..1d093429f21 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Source.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Source.java @@ -71,13 +71,20 @@ public final class Source { /** Cached hash code */ private int hash; + /** Source URL if available */ + private final URL url; + private static final int BUFSIZE = 8 * 1024; - private Source(final String name, final String base, final char[] content) { + // Do *not* make this public ever! Trusts the URL and content. So has to be called + // from other public constructors. Note that this can not be some init method as + // we initialize final fields from here. + private Source(final String name, final String base, final char[] content, final URL url) { this.name = name; this.base = base; this.content = content; this.length = content.length; + this.url = url; } /** @@ -87,7 +94,7 @@ public final class Source { * @param content contents as char array */ public Source(final String name, final char[] content) { - this(name, baseName(name, null), content); + this(name, baseName(name, null), content, null); } /** @@ -109,7 +116,7 @@ public final class Source { * @throws IOException if source cannot be loaded */ public Source(final String name, final URL url) throws IOException { - this(name, baseURL(url, null), readFully(url.openStream())); + this(name, baseURL(url, null), readFully(url.openStream()), url); } /** @@ -121,7 +128,7 @@ public final class Source { * @throws IOException if source cannot be loaded */ public Source(final String name, final File file) throws IOException { - this(name, dirName(file, null), readFully(file)); + this(name, dirName(file, null), readFully(file), getURLFromFile(file)); } @Override @@ -205,6 +212,16 @@ public final class Source { return new String(content, start, end - start); } + /** + * Returns the source URL of this script Source. Can be null if Source + * was created from a String or a char[]. + * + * @return URL source or null + */ + public URL getURL() { + return url; + } + /** * Find the beginning of the line containing position. * @param position Index to offending token. @@ -288,7 +305,7 @@ public final class Source { * @return content */ public char[] getContent() { - return content; + return content.clone(); } /** @@ -433,4 +450,12 @@ public final class Source { public String toString() { return getName(); } + + private static URL getURLFromFile(final File file) { + try { + return file.toURI().toURL(); + } catch (final SecurityException | MalformedURLException ignored) { + return null; + } + } } diff --git a/nashorn/src/jdk/nashorn/tools/Shell.java b/nashorn/src/jdk/nashorn/tools/Shell.java index f4ea183763c..124e83c70c4 100644 --- a/nashorn/src/jdk/nashorn/tools/Shell.java +++ b/nashorn/src/jdk/nashorn/tools/Shell.java @@ -282,7 +282,7 @@ public class Shell { // For each file on the command line. for (final String fileName : files) { final File file = new File(fileName); - ScriptFunction script = context.compileScript(fileName, file.toURI().toURL(), global, context._strict); + ScriptFunction script = context.compileScript(new Source(fileName, file.toURI().toURL()), global); if (script == null || errors.getNumberOfErrors() != 0) { return COMPILATION_ERROR; } diff --git a/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java b/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java index 7e1c8715c76..adf361f4944 100644 --- a/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java +++ b/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java @@ -159,7 +159,7 @@ public class CompilerTest { Context.setGlobal(global); } final Source source = new Source(file.getAbsolutePath(), buffer); - final ScriptFunction script = context.compileScript(source, global, context._strict); + final ScriptFunction script = context.compileScript(source, global); if (script == null || context.getErrorManager().getNumberOfErrors() > 0) { log("Compile failed: " + file.getAbsolutePath()); failed++; diff --git a/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java b/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java index 396847661af..e894a371af2 100644 --- a/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java @@ -111,7 +111,7 @@ public class ContextTest { private Object eval(final Context cx, final String name, final String code) { final Source source = new Source(name, code); final ScriptObject global = Context.getGlobal(); - final ScriptFunction func = cx.compileScript(source, global, cx._strict); + final ScriptFunction func = cx.compileScript(source, global); return func != null ? ScriptRuntime.apply(func, global) : null; } diff --git a/nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java b/nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java index 305106b73d3..58557374e91 100644 --- a/nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java +++ b/nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java @@ -39,6 +39,7 @@ import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; +import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.options.Options; /** @@ -124,7 +125,7 @@ public final class SharedContextEvaluator implements ScriptEvaluator { continue; } final File file = new File(fileName); - ScriptFunction script = context.compileScript(fileName, file.toURI().toURL(), global, context._strict); + ScriptFunction script = context.compileScript(new Source(fileName, file.toURI().toURL()), global); if (script == null || errors.getNumberOfErrors() != 0) { return COMPILATION_ERROR; } From 24b144ccd9f9de649d43d7f4ef49d23f620d75e5 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Thu, 14 Feb 2013 13:01:03 +0000 Subject: [PATCH 142/311] 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 143/311] 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 9f6e3f08f2f1ac176e5a21ee18eaf349d6be3707 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Thu, 14 Feb 2013 09:14:31 +0530 Subject: [PATCH 144/311] 8008193: test262 tests should be run with security manager enabled Reviewed-by: jlaskey --- nashorn/make/build.xml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml index fbf9a9e5dd2..d5264cc70be 100644 --- a/nashorn/make/build.xml +++ b/nashorn/make/build.xml @@ -317,7 +317,7 @@ - + @@ -325,7 +325,7 @@ - + @@ -338,11 +338,14 @@ - + - + - + + + + From 022533a7498b793ae8de0f8660ebb3096a291f63 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Thu, 14 Feb 2013 14:16:58 +0530 Subject: [PATCH 145/311] 8008197: Cross script engine function calls do not work as expected Reviewed-by: lagergren, hannesw --- .../api/scripting/NashornScriptEngine.java | 5 +- .../api/scripting/ScriptObjectMirror.java | 57 ++++++++------- .../internal/runtime/ScriptFunction.java | 2 +- .../internal/runtime/ScriptRuntime.java | 31 +++++++++ nashorn/test/script/basic/JDK-8008197.js | 69 +++++++++++++++++++ nashorn/test/script/basic/jquery.js | 22 ++---- 6 files changed, 137 insertions(+), 49 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8008197.js diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java index ded9afb7e6e..fa8c3814302 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java @@ -329,7 +329,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C final ScriptObject ctxtGlobal = getNashornGlobalFrom(context); final boolean globalChanged = (oldGlobal != ctxtGlobal); - Object self = selfObject; + Object self = globalChanged? ScriptObjectMirror.wrap(selfObject, oldGlobal) : selfObject; try { if (globalChanged) { @@ -354,7 +354,8 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C if (value instanceof ScriptFunction) { final Object res; try { - res = ScriptRuntime.apply((ScriptFunction)value, self, ScriptObjectMirror.unwrapArray(args, ctxtGlobal)); + final Object[] modArgs = globalChanged? ScriptObjectMirror.wrapArray(args, oldGlobal) : args; + res = ScriptRuntime.checkAndApply((ScriptFunction)value, self, ScriptObjectMirror.unwrapArray(modArgs, ctxtGlobal)); } catch (final Exception e) { throwAsScriptException(e); throw new AssertionError("should not reach here"); diff --git a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java index 2aa9ad184c5..266ce87f48d 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java +++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java @@ -104,38 +104,30 @@ final class ScriptObjectMirror extends JSObject implements Bindings { // JSObject methods @Override public Object call(final String methodName, final Object args[]) { - final Object val = sobj.get(methodName); final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal(); final boolean globalChanged = (oldGlobal != global); - if (val instanceof ScriptFunction) { - final Object[] modifiedArgs = unwrapArray(args, global); - if (modifiedArgs != null) { - for (int i = 0; i < modifiedArgs.length; i++) { - final Object arg = modifiedArgs[i]; - if (arg instanceof ScriptObject) { - modifiedArgs[i] = wrap(arg, oldGlobal); - } - } + try { + if (globalChanged) { + NashornScriptEngine.setNashornGlobal(global); } - try { - if (globalChanged) { - NashornScriptEngine.setNashornGlobal(global); - } - return wrap(((ScriptFunction)val).invoke(sobj, modifiedArgs), global); - } catch (final RuntimeException | Error e) { - throw e; - } catch (final Throwable t) { - throw new RuntimeException(t); - } finally { - if (globalChanged) { - NashornScriptEngine.setNashornGlobal(oldGlobal); - } + final Object val = sobj.get(methodName); + if (! (val instanceof ScriptFunction)) { + throw new RuntimeException("No such method: " + methodName); } - } - throw new RuntimeException("No such method: " + methodName); + final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args; + return wrap(ScriptRuntime.checkAndApply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global); + } catch (final RuntimeException | Error e) { + throw e; + } catch (final Throwable t) { + throw new RuntimeException(t); + } finally { + if (globalChanged) { + NashornScriptEngine.setNashornGlobal(oldGlobal); + } + } } @Override @@ -180,7 +172,7 @@ final class ScriptObjectMirror extends JSObject implements Bindings { @Override public void setMember(final String name, final Object value) { - put(name, wrap(value, NashornScriptEngine.getNashornGlobal())); + put(name, value); } @Override @@ -275,20 +267,27 @@ final class ScriptObjectMirror extends JSObject implements Bindings { @Override public Object put(final String key, final Object value) { + final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal(); + final boolean globalChanged = (oldGlobal != global); return inGlobal(new Callable() { @Override public Object call() { - return sobj.put(key, unwrap(value, global)); + final Object modValue = globalChanged? wrap(value, oldGlobal) : value; + return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global)), global)); } }); } @Override public void putAll(final Map map) { + final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal(); + final boolean globalChanged = (oldGlobal != global); final boolean strict = sobj.isStrictContext(); inGlobal(new Callable() { @Override public Object call() { for (final Map.Entry entry : map.entrySet()) { - sobj.set(entry.getKey(), unwrap(entry.getValue(), global), strict); + final Object value = entry.getValue(); + final Object modValue = globalChanged? wrap(value, oldGlobal) : value; + sobj.set(entry.getKey(), unwrap(modValue, global), strict); } return null; } @@ -321,7 +320,7 @@ final class ScriptObjectMirror extends JSObject implements Bindings { final Iterator iter = sobj.valueIterator(); while (iter.hasNext()) { - values.add(wrap(iter.next(), global)); + values.add(translateUndefined(wrap(iter.next(), global))); } return Collections.unmodifiableList(values); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java index fb3b419e150..d0b24b2c80e 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java @@ -192,7 +192,7 @@ public abstract class ScriptFunction extends ScriptObject { * @return ScriptFunction result. * @throws Throwable if there is an exception/error with the invocation or thrown from it */ - public Object invoke(final Object self, final Object... arguments) throws Throwable { + Object invoke(final Object self, final Object... arguments) throws Throwable { if (Context.DEBUG) { invokes++; } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java index f491d388a91..3c910f4344c 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java @@ -301,6 +301,37 @@ public final class ScriptRuntime { return global; } + /** + * Check that the target function is associated with current Context. And also make sure that 'self', if + * ScriptObject, is from current context. + * + * Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve + * better performance by {@link Bootstrap#createDynamicInvoker(String, Class, Class...) creating a dynamic invoker} + * for operation {@code "dyn:call"}, then using its {@link MethodHandle#invokeExact(Object...)} method instead. + * + * @param target ScriptFunction object. + * @param self Receiver in call. + * @param args Call arguments. + * @return Call result. + */ + public static Object checkAndApply(final ScriptFunction target, final Object self, final Object... args) { + final ScriptObject global = Context.getGlobalTrusted(); + if (! (global instanceof GlobalObject)) { + throw new IllegalStateException("No current global set"); + } + + if (target.getContext() != global.getContext()) { + throw new IllegalArgumentException("'target' function is not from current Context"); + } + + if (self instanceof ScriptObject && ((ScriptObject)self).getContext() != global.getContext()) { + throw new IllegalArgumentException("'self' object is not from current Context"); + } + + // all in order - call real 'apply' + return apply(target, self, args); + } + /** * Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve * better performance by {@link Bootstrap#createDynamicInvoker(String, Class, Class...) creating a dynamic invoker} diff --git a/nashorn/test/script/basic/JDK-8008197.js b/nashorn/test/script/basic/JDK-8008197.js new file mode 100644 index 00000000000..e77a13a9ba1 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8008197.js @@ -0,0 +1,69 @@ +/* + * 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. + */ + +/** + * JDK-8008197: Cross script engine function calls do not work as expected + * + * @test + * @run + */ + + +var m = new javax.script.ScriptEngineManager(); +var e = m.getEngineByName("nashorn"); + +var obj = { + func: function(str) { + return /hello/.exec(str); + } +}; + +// set our object as object to the engine created +e.put("obj", obj); + +// try to invoke method from the other engine +if (e.eval("obj.func('hello')") == null) { + fail("FAILED: #1 obj.func('hello') returns null"); +} + +// define an object in the engine + e.eval("var foo = { callMe: function(callback) { return callback() } }"); + +// try to invoke a script method from here but callback is from this engine +var res = e.invokeMethod(e.get("foo"), "callMe", function() { + return /nashorn/; +}); + +if (! res.exec("nashorn")) { + fail("FAILED: #2 /nashorn/ does not match 'nashorn'"); +} + +// invoke a script method from here with callback from this engine. +// This uses JSObject.call interface +res = e.get("foo").callMe(function() { + return /ecmascript/; +}); + +if (! res.exec("ecmascript")) { + fail("FAILED: #3 /ecmascript/ does not match 'ecmascript'"); +} diff --git a/nashorn/test/script/basic/jquery.js b/nashorn/test/script/basic/jquery.js index 16cb077d07c..f88d94b0235 100644 --- a/nashorn/test/script/basic/jquery.js +++ b/nashorn/test/script/basic/jquery.js @@ -60,23 +60,13 @@ function test_jquery(url) { var name; try { + var split = url.split('/'); + name = split[split.length - 1]; + var path = __DIR__ + "../external/jquery/" + name; try { - var split = url.split('/'); - name = split[split.length - 1]; - var path = __DIR__ + "../external/jquery/" + name; - try { - load(path); - } catch (e) { - checkWindow(e); - } + load(path); } catch (e) { - // try to load it from the internet, if we for some licensing reason - // aren't allowed to ship third party code under MIT license - try { - load(url); - } catch (e) { - checkWindow(e); - } + checkWindow(e); } } catch (e) { print("Unexpected exception " + e); @@ -85,8 +75,6 @@ function test_jquery(url) { print("done " + name); } - - for each (url in urls) { test_jquery(url); } From 7c466c84eb53948edc585ac82fb618dfc275770f Mon Sep 17 00:00:00 2001 From: Marcus Lagergren Date: Thu, 14 Feb 2013 13:01:52 +0100 Subject: [PATCH 146/311] 8008199: Lazy compilation and trampoline implementation The code pipeline now supports lazy compilation, which can be used to only compile certain FunctionNodes and leave others be, saving startup time. When these uncompiled nodes are hit, a trampoline will force them to be recompiled. This can also be used to specialize compilation fixing parameter types and return types to a callsite specific compilation. This will give performance. Reviewed-by: attila, sundar --- .../jdk/nashorn/internal/codegen/Attr.java | 98 +- .../internal/codegen/ClassEmitter.java | 45 +- .../internal/codegen/CodeGenerator.java | 168 +-- .../internal/codegen/CompilationPhase.java | 366 +++++++ .../nashorn/internal/codegen/CompileUnit.java | 4 +- .../nashorn/internal/codegen/Compiler.java | 975 ++++++------------ .../internal/codegen/ConstantData.java | 2 +- .../internal/codegen/FinalizeTypes.java | 30 +- .../internal/codegen/FoldConstants.java | 5 +- .../internal/codegen/FunctionSignature.java | 51 +- .../jdk/nashorn/internal/codegen/Lower.java | 39 +- .../internal/codegen/SharedScopeCall.java | 6 +- .../nashorn/internal/codegen/Splitter.java | 49 +- .../nashorn/internal/codegen/WeighNodes.java | 2 +- .../objects/FunctionObjectCreator.java | 101 -- .../codegen/objects/ObjectClassGenerator.java | 4 +- .../jdk/nashorn/internal/ir/FunctionNode.java | 117 ++- .../nashorn/internal/ir/debug/JSONWriter.java | 6 +- .../internal/ir/visitor/NodeVisitor.java | 2 +- .../objects/BoundScriptFunctionImpl.java | 2 +- .../jdk/nashorn/internal/objects/Global.java | 2 + .../nashorn/internal/objects/NativeJava.java | 1 + .../internal/objects/ScriptFunctionImpl.java | 6 +- .../objects/ScriptFunctionTrampolineImpl.java | 122 +++ .../jdk/nashorn/internal/parser/Lexer.java | 7 + .../jdk/nashorn/internal/parser/Parser.java | 74 +- .../internal/runtime/CodeInstaller.java | 13 +- .../jdk/nashorn/internal/runtime/Context.java | 62 +- .../nashorn/internal/runtime/DebugLogger.java | 3 + .../internal/runtime/FindProperty.java | 2 +- .../internal/runtime/ScriptFunction.java | 32 +- .../internal/runtime/ScriptFunctionData.java | 14 +- .../internal/runtime/ScriptingFunctions.java | 20 +- nashorn/src/jdk/nashorn/tools/Shell.java | 13 +- nashorn/test/script/trusted/JDK-8006529.js | 20 +- .../nashorn/internal/parser/ParserTest.java | 5 +- .../framework/SharedContextEvaluator.java | 1 + 37 files changed, 1425 insertions(+), 1044 deletions(-) create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java delete mode 100644 nashorn/src/jdk/nashorn/internal/codegen/objects/FunctionObjectCreator.java create mode 100644 nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionTrampolineImpl.java diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java index e3bd8ab3881..1752cfbd3f1 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java @@ -84,7 +84,6 @@ import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; -import jdk.nashorn.internal.runtime.Source; /** * This is the attribution pass of the code generator. Attr takes Lowered IR, @@ -102,11 +101,8 @@ import jdk.nashorn.internal.runtime.Source; */ final class Attr extends NodeOperatorVisitor { - /** Current compiler. */ - private final Compiler compiler; - - /** Current source. */ - private final Source source; + /** Context compiler. */ + private final Context context; /** * Local definitions in current block (to discriminate from function @@ -122,16 +118,16 @@ final class Attr extends NodeOperatorVisitor { */ private Set localUses; - private static final DebugLogger LOG = new DebugLogger("attr"); + private static final DebugLogger LOG = new DebugLogger("attr"); + private static final boolean DEBUG = LOG.isEnabled(); /** * Constructor. * * @param compiler the compiler */ - Attr(final Compiler compiler) { - this.compiler = compiler; - this.source = compiler.getSource(); + Attr(final Context context) { + this.context = context; } @Override @@ -231,6 +227,11 @@ final class Attr extends NodeOperatorVisitor { @Override public Node enter(final FunctionNode functionNode) { start(functionNode, false); + if (functionNode.isLazy()) { + LOG.info("LAZY: " + functionNode.getName()); + end(functionNode); + return null; + } clearLocalDefs(); clearLocalUses(); @@ -257,7 +258,7 @@ final class Attr extends NodeOperatorVisitor { } if (functionNode.isScript()) { - initFromPropertyMap(compiler.getContext(), functionNode); + initFromPropertyMap(context, functionNode); } // Add function name as local symbol @@ -378,7 +379,7 @@ final class Attr extends NodeOperatorVisitor { final FunctionNode functionNode = (FunctionNode)symbol.getNode(); assert functionNode.getCalleeNode() != null; - final VarNode var = new VarNode(source, functionNode.getToken(), functionNode.getFinish(), functionNode.getIdent(), functionNode.getCalleeNode()); + final VarNode var = new VarNode(functionNode.getSource(), functionNode.getToken(), functionNode.getFinish(), functionNode.getIdent(), functionNode.getCalleeNode()); //newTemporary(Type.OBJECT, var); //ScriptFunction? TODO functionNode.setNeedsSelfSymbol(var); @@ -489,15 +490,21 @@ final class Attr extends NodeOperatorVisitor { if (functionNode != null) { functionNode.addReferencingParentBlock(getCurrentBlock()); } - end(referenceNode); - return referenceNode; } @Override public Node leave(final ReferenceNode referenceNode) { newTemporary(Type.OBJECT, referenceNode); //reference node type is always an object, i.e. the scriptFunction. the function return type varies though + + final FunctionNode functionNode = referenceNode.getReference(); + //assert !functionNode.getType().isUnknown() || functionNode.isLazy() : functionNode.getType(); + if (functionNode.isLazy()) { + LOG.info("Lazy function node call reference: " + functionNode.getName() + " => Promoting to OBJECT"); + functionNode.setReturnType(Type.OBJECT); + } end(referenceNode); + return referenceNode; } @@ -546,7 +553,7 @@ final class Attr extends NodeOperatorVisitor { type = Type.OBJECT; } - switchNode.setTag(newInternal(compiler.uniqueName(SWITCH_TAG_PREFIX.tag()), type)); + switchNode.setTag(newInternal(getCurrentFunctionNode().uniqueName(SWITCH_TAG_PREFIX.tag()), type)); end(switchNode); @@ -1111,7 +1118,7 @@ final class Attr extends NodeOperatorVisitor { @Override public Node leave(final ForNode forNode) { if (forNode.isForIn()) { - forNode.setIterator(newInternal(getCurrentFunctionNode(), compiler.uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73 + forNode.setIterator(newInternal(getCurrentFunctionNode(), getCurrentFunctionNode().uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73 /* * Iterators return objects, so we need to widen the scope of the * init variable if it, for example, has been assigned double type @@ -1321,7 +1328,7 @@ final class Attr extends NodeOperatorVisitor { } private Symbol exceptionSymbol() { - return newInternal(compiler.uniqueName(EXCEPTION_PREFIX.tag()), Type.typeFor(ECMAException.class)); + return newInternal(getCurrentFunctionNode().uniqueName(EXCEPTION_PREFIX.tag()), Type.typeFor(ECMAException.class)); } /** @@ -1382,6 +1389,11 @@ final class Attr extends NodeOperatorVisitor { } } + @Override + public Node enter(final FunctionNode node) { + return node.isLazy() ? null : node; + } + /** * Eg. * @@ -1553,17 +1565,19 @@ final class Attr extends NodeOperatorVisitor { } private Node start(final Node node, final boolean printNode) { - final StringBuilder sb = new StringBuilder(); + if (DEBUG) { + final StringBuilder sb = new StringBuilder(); - sb.append("[ENTER "). - append(name(node)). - append("] "). - append(printNode ? node.toString() : ""). - append(" in '"). - append(getCurrentFunctionNode().getName()). - append("'"); - LOG.info(sb.toString()); - LOG.indent(); + sb.append("[ENTER "). + append(name(node)). + append("] "). + append(printNode ? node.toString() : ""). + append(" in '"). + append(getCurrentFunctionNode().getName()). + append("'"); + LOG.info(sb.toString()); + LOG.indent(); + } return node; } @@ -1573,24 +1587,26 @@ final class Attr extends NodeOperatorVisitor { } private Node end(final Node node, final boolean printNode) { - final StringBuilder sb = new StringBuilder(); + if (DEBUG) { + final StringBuilder sb = new StringBuilder(); - sb.append("[LEAVE "). - append(name(node)). - append("] "). - append(printNode ? node.toString() : ""). - append(" in '"). - append(getCurrentFunctionNode().getName()); + sb.append("[LEAVE "). + append(name(node)). + append("] "). + append(printNode ? node.toString() : ""). + append(" in '"). + append(getCurrentFunctionNode().getName()); - if (node.getSymbol() == null) { - sb.append(" "); - } else { - sb.append(" '); + if (node.getSymbol() == null) { + sb.append(" "); + } else { + sb.append(" '); + } + + LOG.unindent(); + LOG.info(sb.toString()); } - LOG.unindent(); - LOG.info(sb.toString()); - return node; } } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java b/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java index 8ad8123822b..b9f645e47f5 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java @@ -52,6 +52,8 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor; +import java.io.ByteArrayOutputStream; +import java.io.PrintWriter; import java.util.Arrays; import java.util.EnumSet; import java.util.HashSet; @@ -166,8 +168,8 @@ public class ClassEmitter implements Emitter { * @param unitClassName Compile unit class name. * @param strictMode Should we generate this method in strict mode */ - ClassEmitter(final Compiler compiler, final String unitClassName, final boolean strictMode) { - this(compiler.getContext(), + ClassEmitter(final Context context, final String sourceName, final String unitClassName, final boolean strictMode) { + this(context, new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) { private static final String OBJECT_CLASS = "java/lang/Object"; @@ -187,12 +189,22 @@ public class ClassEmitter implements Emitter { this.unitClassName = unitClassName; this.constantMethodNeeded = new HashSet<>(); - cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, unitClassName, null, Compiler.pathName(jdk.nashorn.internal.scripts.JS$.class.getName()), null); - cw.visitSource(compiler.getSource().getName(), null); + cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, unitClassName, null, pathName(jdk.nashorn.internal.scripts.JS$.class.getName()), null); + cw.visitSource(sourceName, null); defineCommonStatics(strictMode); } + /** + * Convert a binary name to a package/class name. + * + * @param name Binary name. + * @return Package/class name. + */ + private static String pathName(final String name) { + return name.replace('.', '/'); + } + /** * Define the static fields common in all scripts. * @param strictMode Should we generate this method in strict mode @@ -295,7 +307,7 @@ public class ClassEmitter implements Emitter { * Ensure a get constant method is issued for the class. * @param cls Class of constant. */ - public void needGetConstantMethod(final Class cls) { + void needGetConstantMethod(final Class cls) { constantMethodNeeded.add(cls); } @@ -348,22 +360,15 @@ public class ClassEmitter implements Emitter { /** * Disassemble an array of byte code. - * - * @param context the context * @param bytecode byte array representing bytecode + * @return disassembly as human readable string */ - public static void disassemble(final Context context, final byte[] bytecode) { - new ClassReader(bytecode).accept(new TraceClassVisitor(context.getErr()), 0); - } - - /** - * Verify an array of byte code as a valid Java class - * - * @param context the context - * @param bytecode the bytecode array - */ - public static void verify(final Context context, final byte[] bytecode) { - context.verify(bytecode); + public static String disassemble(final byte[] bytecode) { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (final PrintWriter pw = new PrintWriter(baos)) { + new ClassReader(bytecode).accept(new TraceClassVisitor(pw), 0); + } + return new String(baos.toByteArray()); } /** @@ -459,7 +464,7 @@ public class ClassEmitter implements Emitter { final MethodVisitor mv = cw.visitMethod( ACC_PUBLIC | ACC_STATIC | (functionNode.isVarArg() ? ACC_VARARGS : 0), functionNode.getName(), - FunctionSignature.functionSignature(functionNode), + new FunctionSignature(functionNode).toString(), null, null); diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java index da7c72147c1..544d8c5ebb7 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -25,8 +25,10 @@ package jdk.nashorn.internal.codegen; +import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.HANDLE_STATIC; import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.PRIVATE; import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.STATIC; +import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE; import static jdk.nashorn.internal.codegen.CompilerConstants.GET_MAP; import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING; import static jdk.nashorn.internal.codegen.CompilerConstants.LEAF; @@ -35,6 +37,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.REGEX_PREFIX; import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_ARRAY_ARG; import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX; +import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup; import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; @@ -48,6 +51,7 @@ import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALL import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT; import java.io.PrintWriter; +import java.lang.invoke.MethodHandle; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; @@ -63,8 +67,8 @@ import jdk.nashorn.internal.codegen.MethodEmitter.Condition; import jdk.nashorn.internal.codegen.MethodEmitter.Label; import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode; import jdk.nashorn.internal.codegen.objects.FieldObjectCreator; -import jdk.nashorn.internal.codegen.objects.FunctionObjectCreator; import jdk.nashorn.internal.codegen.objects.MapCreator; +import jdk.nashorn.internal.codegen.objects.ObjectCreator; import jdk.nashorn.internal.codegen.objects.ObjectMapCreator; import jdk.nashorn.internal.codegen.types.ArrayType; import jdk.nashorn.internal.codegen.types.Type; @@ -111,11 +115,13 @@ import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.parser.Lexer.RegexToken; import jdk.nashorn.internal.parser.TokenType; +import jdk.nashorn.internal.runtime.CodeInstaller; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ECMAException; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.Scope; import jdk.nashorn.internal.runtime.ScriptFunction; +import jdk.nashorn.internal.runtime.ScriptFunctionData; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.Source; @@ -143,11 +149,17 @@ import jdk.nashorn.internal.runtime.linker.LinkerCallSite; */ public final class CodeGenerator extends NodeOperatorVisitor { - /** Current compiler */ - private final Compiler compiler; + /** Name of the Global object, cannot be referred to as .class, @see CodeGenerator */ + private static final String GLOBAL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "Global"; - /** Compiler context */ - private final Context context; + /** Name of the ScriptFunctionImpl, cannot be referred to as .class @see FunctionObjectCreator */ + private static final String SCRIPTFUNCTION_IMPL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "ScriptFunctionImpl"; + + private static final String SCRIPTFUNCTION_TRAMPOLINE_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "ScriptFunctionTrampolineImpl"; + + /** Constant data & installation. The only reason the compiler keeps this is because it is assigned + * by reflection in class installation */ + private final Compiler compiler; /** Call site flags given to the code generator to be used for all generated call sites */ private final int callSiteFlags; @@ -168,17 +180,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { */ CodeGenerator(final Compiler compiler) { this.compiler = compiler; - this.context = compiler.getContext(); - this.callSiteFlags = context._callsite_flags; - } - - /** - * Get the compiler - * - * @return the compiler used - */ - public Compiler getCompiler() { - return compiler; + this.callSiteFlags = compiler.getContext()._callsite_flags; } /** @@ -320,7 +322,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { */ final CodeGenerator codegen = this; - node.accept(new NodeVisitor(compileUnit, method) { + node.accept(new NodeVisitor(getCurrentCompileUnit(), method) { @Override public Node enter(final IdentNode identNode) { loadIdent(identNode); @@ -534,7 +536,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { final FunctionNode currentFunction = getCurrentFunctionNode(); final Block currentBlock = getCurrentBlock(); - function.accept(new NodeVisitor(compileUnit, method) { + function.accept(new NodeVisitor(getCurrentCompileUnit(), method) { private void sharedScopeCall(final IdentNode identNode, final int flags) { final Symbol symbol = identNode.getSymbol(); @@ -651,7 +653,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { final String signature = new FunctionSignature(true, callee.needsCallee(), callee.getReturnType(), isVarArg ? null : callee.getParameters()).toString(); if (callee.needsCallee()) { - new FunctionObjectCreator(CodeGenerator.this, callee).makeObject(method); + newFunctionObject(callee); } if (callee.isStrictMode()) { // self is undefined @@ -969,14 +971,18 @@ public final class CodeGenerator extends NodeOperatorVisitor { @Override public Node enter(final FunctionNode functionNode) { + if (functionNode.isLazy()) { + return null; + } + if (functionNode.testResolved()) { return null; } - compileUnit = functionNode.getCompileUnit(); - assert compileUnit != null; + setCurrentCompileUnit(functionNode.getCompileUnit()); + assert getCurrentCompileUnit() != null; - method = compileUnit.getClassEmitter().method(functionNode); + method = getCurrentCompileUnit().getClassEmitter().method(functionNode); functionNode.setMethodEmitter(method); // Mark end for variable tables. method.begin(); @@ -1100,18 +1106,18 @@ public final class CodeGenerator extends NodeOperatorVisitor { final Type elementType = arrayType.getElementType(); if (units != null) { - final CompileUnit savedCompileUnit = compileUnit; - final MethodEmitter savedMethod = method; + final CompileUnit savedCompileUnit = getCurrentCompileUnit(); + final MethodEmitter savedMethod = getCurrentMethodEmitter(); try { for (final ArrayUnit unit : units) { - compileUnit = unit.getCompileUnit(); + setCurrentCompileUnit(unit.getCompileUnit()); - final String className = compileUnit.getUnitClassName(); - final String name = compiler.uniqueName(SPLIT_PREFIX.tag()); + final String className = getCurrentCompileUnit().getUnitClassName(); + final String name = getCurrentFunctionNode().uniqueName(SPLIT_PREFIX.tag()); final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type); - method = compileUnit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature); + method = getCurrentCompileUnit().getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature); method.setFunctionNode(getCurrentFunctionNode()); method.begin(); @@ -1135,8 +1141,8 @@ public final class CodeGenerator extends NodeOperatorVisitor { savedMethod.invokeStatic(className, name, signature); } } finally { - compileUnit = savedCompileUnit; - method = savedMethod; + setCurrentCompileUnit(savedCompileUnit); + setCurrentMethodEmitter(savedMethod); } return method; @@ -1186,8 +1192,8 @@ public final class CodeGenerator extends NodeOperatorVisitor { * @param string string to load */ public void loadConstant(final String string) { - final String unitClassName = compileUnit.getUnitClassName(); - final ClassEmitter classEmitter = compileUnit.getClassEmitter(); + final String unitClassName = getCurrentCompileUnit().getUnitClassName(); + final ClassEmitter classEmitter = getCurrentCompileUnit().getClassEmitter(); final int index = compiler.getConstantData().add(string); method.load(index); @@ -1202,8 +1208,8 @@ public final class CodeGenerator extends NodeOperatorVisitor { * @param object object to load */ public void loadConstant(final Object object) { - final String unitClassName = compileUnit.getUnitClassName(); - final ClassEmitter classEmitter = compileUnit.getClassEmitter(); + final String unitClassName = getCurrentCompileUnit().getUnitClassName(); + final ClassEmitter classEmitter = getCurrentCompileUnit().getClassEmitter(); final int index = compiler.getConstantData().add(object); final Class cls = object.getClass(); @@ -1272,14 +1278,14 @@ public final class CodeGenerator extends NodeOperatorVisitor { return loadRegexToken(regexToken); } // emit field - final String regexName = compiler.uniqueName(REGEX_PREFIX.tag()); - final ClassEmitter classEmitter = compileUnit.getClassEmitter(); + final String regexName = getCurrentFunctionNode().uniqueName(REGEX_PREFIX.tag()); + final ClassEmitter classEmitter = getCurrentCompileUnit().getClassEmitter(); classEmitter.field(EnumSet.of(PRIVATE, STATIC), regexName, Object.class); regexFieldCount++; // get field, if null create new regex, finally clone regex object - method.getStatic(compileUnit.getUnitClassName(), regexName, typeDescriptor(Object.class)); + method.getStatic(getCurrentCompileUnit().getUnitClassName(), regexName, typeDescriptor(Object.class)); method.dup(); final Label cachedLabel = new Label("cached"); method.ifnonnull(cachedLabel); @@ -1287,7 +1293,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { method.pop(); loadRegexToken(regexToken); method.dup(); - method.putStatic(compileUnit.getUnitClassName(), regexName, typeDescriptor(Object.class)); + method.putStatic(getCurrentCompileUnit().getUnitClassName(), regexName, typeDescriptor(Object.class)); method.label(cachedLabel); globalRegExpCopy(); @@ -1409,7 +1415,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { return null; } - new FunctionObjectCreator(this, referenceNode.getReference()).makeObject(method); + newFunctionObject(referenceNode.getReference()); return null; } @@ -1551,6 +1557,10 @@ public final class CodeGenerator extends NodeOperatorVisitor { return true; } + private static boolean isReducible(final Request request) { + return Request.isComparison(request) || request == Request.ADD; + } + @Override public Node enter(final RuntimeNode runtimeNode) { if (runtimeNode.testResolved()) { @@ -1563,9 +1573,10 @@ public final class CodeGenerator extends NodeOperatorVisitor { * * TODO - remove this - Access Specializer will always know after Attr/Lower */ - if (runtimeNode.isPrimitive() && !runtimeNode.isFinal()) { + if (runtimeNode.isPrimitive() && !runtimeNode.isFinal() && isReducible(runtimeNode.getRequest())) { final Node lhs = runtimeNode.getArgs().get(0); - final Node rhs = runtimeNode.getArgs().size() > 1 ? runtimeNode.getArgs().get(1) : null; + assert runtimeNode.getArgs().size() > 1 : runtimeNode + " must have two args"; + final Node rhs = runtimeNode.getArgs().get(1); final Type type = runtimeNode.getType(); final Symbol symbol = runtimeNode.getSymbol(); @@ -1709,7 +1720,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { method.end(); } catch (final Throwable t) { Context.printStackTrace(t); - final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + compiler.getSource().getName()); + final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + getCurrentFunctionNode().getSource().getName()); e.initCause(t); throw e; } @@ -1898,7 +1909,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { method._new(ECMAException.class).dup(); final Node expression = throwNode.getExpression(); - final Source source = compiler.getSource(); + final Source source = throwNode.getSource(); final int position = throwNode.position(); final int line = source.getLine(position); final int column = source.getColumn(position); @@ -2928,7 +2939,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { if (scopeCalls.containsKey(scopeCall)) { return scopeCalls.get(scopeCall); } - scopeCall.setClassAndName(compileUnit, compiler); + scopeCall.setClassAndName(getCurrentCompileUnit(), getCurrentFunctionNode().uniqueName("scopeCall")); scopeCalls.put(scopeCall, scopeCall); return scopeCall; } @@ -2947,7 +2958,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { if (scopeCalls.containsKey(scopeCall)) { return scopeCalls.get(scopeCall); } - scopeCall.setClassAndName(compileUnit, compiler); + scopeCall.setClassAndName(getCurrentCompileUnit(), getCurrentFunctionNode().uniqueName("scopeCall")); scopeCalls.put(scopeCall, scopeCall); return scopeCall; } @@ -2959,12 +2970,12 @@ public final class CodeGenerator extends NodeOperatorVisitor { * @param ident identifier for block or function where applicable */ private void printSymbols(final Block block, final String ident) { - if (!context._print_symbols) { + if (!compiler.getContext()._print_symbols) { return; } @SuppressWarnings("resource") - final PrintWriter out = context.getErr(); + final PrintWriter out = compiler.getContext().getErr(); out.println("[BLOCK in '" + ident + "']"); if (!block.printSymbols(out)) { out.println(""); @@ -3057,7 +3068,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { * on the stack throughout the store and used at the end to execute it */ - target.accept(new NodeVisitor(compileUnit, method) { + target.accept(new NodeVisitor(getCurrentCompileUnit(), method) { @Override public Node enter(final IdentNode node) { if (targetSymbol.isScope()) { @@ -3124,7 +3135,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { * @return the quick symbol */ private Symbol quickSymbol(final Type type, final String prefix) { - final String name = compiler.uniqueName(prefix); + final String name = getCurrentFunctionNode().uniqueName(prefix); final Symbol symbol = new Symbol(name, IS_TEMP | IS_INTERNAL, null, null); symbol.setType(type); @@ -3166,7 +3177,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { */ method.convert(target.getType()); - target.accept(new NodeVisitor(compileUnit, method) { + target.accept(new NodeVisitor(getCurrentCompileUnit(), method) { @Override protected Node enterDefault(Node node) { throw new AssertionError("Unexpected node " + node + " in store epilogue"); @@ -3228,42 +3239,83 @@ public final class CodeGenerator extends NodeOperatorVisitor { } + private void newFunctionObject(final FunctionNode functionNode) { + final boolean isLazy = functionNode.isLazy(); + final Class[] cparams = new Class[] { ScriptFunctionData.class, ScriptObject.class, MethodHandle.class }; + + new ObjectCreator(this, new ArrayList(), new ArrayList(), false, false) { + @Override + public void makeObject(final MethodEmitter method) { + final String className = isLazy ? SCRIPTFUNCTION_TRAMPOLINE_OBJECT : SCRIPTFUNCTION_IMPL_OBJECT; + + method._new(className).dup(); + if (isLazy) { + loadConstant(compiler.getCodeInstaller()); + loadConstant(functionNode); + } else { + final String signature = new FunctionSignature(true, functionNode.needsCallee(), functionNode.getReturnType(), functionNode.isVarArg() ? null : functionNode.getParameters()).toString(); + method.loadHandle(functionNode.getCompileUnit().getUnitClassName(), functionNode.getName(), signature, EnumSet.of(HANDLE_STATIC)); // function + } + loadConstant(new ScriptFunctionData(functionNode, makeMap())); + + if (isLazy || functionNode.needsParentScope()) { + method.loadScope(); + } else { + method.loadNull(); + } + + method.loadHandle(getClassName(), ALLOCATE.tag(), methodDescriptor(ScriptObject.class, PropertyMap.class), EnumSet.of(HANDLE_STATIC)); + + final List> cparamList = new ArrayList<>(); + if (isLazy) { + cparamList.add(CodeInstaller.class); + cparamList.add(FunctionNode.class); + } else { + cparamList.add(MethodHandle.class); + } + cparamList.addAll(Arrays.asList(cparams)); + + method.invoke(constructorNoLookup(className, cparamList.toArray(new Class[cparamList.size()]))); + } + }.makeObject(method); + } + /* * Globals are special. We cannot refer to any Global (or NativeObject) class by .class, as they are different * for different contexts. As far as I can tell, the only NativeObject that we need to deal with like this * is from the code pipeline is Global */ private MethodEmitter globalInstance() { - return method.invokeStatic(Compiler.GLOBAL_OBJECT, "instance", "()L" + Compiler.GLOBAL_OBJECT + ';'); + return method.invokeStatic(GLOBAL_OBJECT, "instance", "()L" + GLOBAL_OBJECT + ';'); } private MethodEmitter globalObjectPrototype() { - return method.invokeStatic(Compiler.GLOBAL_OBJECT, "objectPrototype", methodDescriptor(ScriptObject.class)); + return method.invokeStatic(GLOBAL_OBJECT, "objectPrototype", methodDescriptor(ScriptObject.class)); } private MethodEmitter globalAllocateArguments() { - return method.invokeStatic(Compiler.GLOBAL_OBJECT, "allocateArguments", methodDescriptor(ScriptObject.class, Object[].class, Object.class, int.class)); + return method.invokeStatic(GLOBAL_OBJECT, "allocateArguments", methodDescriptor(ScriptObject.class, Object[].class, Object.class, int.class)); } private MethodEmitter globalNewRegExp() { - return method.invokeStatic(Compiler.GLOBAL_OBJECT, "newRegExp", methodDescriptor(Object.class, String.class, String.class)); + return method.invokeStatic(GLOBAL_OBJECT, "newRegExp", methodDescriptor(Object.class, String.class, String.class)); } private MethodEmitter globalRegExpCopy() { - return method.invokeStatic(Compiler.GLOBAL_OBJECT, "regExpCopy", methodDescriptor(Object.class, Object.class)); + return method.invokeStatic(GLOBAL_OBJECT, "regExpCopy", methodDescriptor(Object.class, Object.class)); } private MethodEmitter globalAllocateArray(final ArrayType type) { //make sure the native array is treated as an array type - return method.invokeStatic(Compiler.GLOBAL_OBJECT, "allocate", "(" + type.getDescriptor() + ")Ljdk/nashorn/internal/objects/NativeArray;"); + return method.invokeStatic(GLOBAL_OBJECT, "allocate", "(" + type.getDescriptor() + ")Ljdk/nashorn/internal/objects/NativeArray;"); } private MethodEmitter globalIsEval() { - return method.invokeStatic(Compiler.GLOBAL_OBJECT, "isEval", methodDescriptor(boolean.class, Object.class)); + return method.invokeStatic(GLOBAL_OBJECT, "isEval", methodDescriptor(boolean.class, Object.class)); } private MethodEmitter globalDirectEval() { - return method.invokeStatic(Compiler.GLOBAL_OBJECT, "directEval", + return method.invokeStatic(GLOBAL_OBJECT, "directEval", methodDescriptor(Object.class, Object.class, Object.class, Object.class, Object.class, Object.class)); } } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java b/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java new file mode 100644 index 00000000000..4d41e57ac8e --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java @@ -0,0 +1,366 @@ +package jdk.nashorn.internal.codegen; + +import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.ATTR; +import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.CONSTANT_FOLDED; +import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.EMITTED; +import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.FINALIZED; +import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.INITIALIZED; +import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.LOWERED; +import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.EnumSet; +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; +import jdk.nashorn.internal.ir.Node; +import jdk.nashorn.internal.ir.visitor.NodeVisitor; +import jdk.nashorn.internal.ir.debug.ASTWriter; +import jdk.nashorn.internal.ir.debug.PrintVisitor; +import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.ECMAErrors; + +/** + * A compilation phase is a step in the processes of turning a JavaScript FunctionNode + * into bytecode. It has an optional return value. + */ +enum CompilationPhase { + + /* + * Lazy initialization - tag all function nodes not the script as lazy as + * default policy. The will get trampolines and only be generated when + * called + */ + LAZY_INITIALIZATION_PHASE(EnumSet.of(FunctionNode.CompilationState.INITIALIZED)) { + @Override + boolean transform(final Compiler compiler, final FunctionNode fn) { + + /* + * For lazy compilation, we might be given a node previously marked as lazy + * to compile as the outermost function node in the compiler. Unmark it + * so it can be compiled and not cause recursion. Make sure the return type + * is unknown so it can be correctly deduced. Return types are always + * Objects in Lazy nodes as we haven't got a change to generate code for + * them and decude its parameter specialization + * + * TODO: in the future specializations from a callsite will be passed here + * so we can generate a better non-lazy version of a function from a trampoline + */ + //compute the signature from the callsite - todo - now just clone object params + final FunctionNode outermostFunctionNode = compiler.getFunctionNode(); + outermostFunctionNode.setIsLazy(false); + outermostFunctionNode.setReturnType(Type.UNKNOWN); + + outermostFunctionNode.accept(new NodeVisitor() { + @Override + public Node enter(final FunctionNode node) { + assert Compiler.LAZY_JIT; + node.setIsLazy(node != outermostFunctionNode); + return node; + } + }); + return true; + } + + @Override + public String toString() { + return "[Lazy JIT Initialization]"; + } + }, + + /* + * Constant folding pass + * Simple constant folding that will make elementary constructs go away + */ + CONSTANT_FOLDING_PHASE(EnumSet.of(INITIALIZED), CONSTANT_FOLDED) { + @Override + boolean transform(final Compiler compiler, final FunctionNode fn) { + final Context context = compiler.getContext(); + + if (context._print_ast) { + context.getErr().println(new ASTWriter(fn)); + } + + if (context._print_parse) { + context.getErr().println(new PrintVisitor(fn)); + } + + fn.accept(new FoldConstants()); + + return true; + } + + @Override + public String toString() { + return "[Constant Folding]"; + } + }, + + /* + * Lower (Control flow pass) + * Finalizes the control flow. Clones blocks for finally constructs and + * similar things. Establishes termination criteria for nodes + * Guarantee return instructions to method making sure control flow + * cannot fall off the end. Replacing high level nodes with lower such + * as runtime nodes where applicable. + * + */ + LOWERING_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED), LOWERED) { + @Override + boolean transform(final Compiler compiler, final FunctionNode fn) { + fn.accept(new Lower()); + return true; + } + + @Override + public String toString() { + return "[Control Flow Lowering]"; + } + }, + + /* + * Attribution + * Assign symbols and types to all nodes. + */ + ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED), ATTR) { + @Override + boolean transform(final Compiler compiler, final FunctionNode fn) { + final Context context = compiler.getContext(); + try { + fn.accept(new Attr(context)); + return true; + } finally { + if (context._print_lower_ast) { + context.getErr().println(new ASTWriter(fn)); + } + + if (context._print_lower_parse) { + context.getErr().println(new PrintVisitor(fn)); + } + } + } + + @Override + public String toString() { + return "[Type Attribution]"; + } + }, + + /* + * Splitter + * Split the AST into several compile units based on a size heuristic + * Splitter needs attributed AST for weight calculations (e.g. is + * a + b a ScriptRuntime.ADD with call overhead or a dadd with much + * less). Split IR can lead to scope information being changed. + */ + SPLITTING_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED, ATTR), SPLIT) { + @Override + boolean transform(final Compiler compiler, final FunctionNode fn) { + final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName()); + + new Splitter(compiler, fn, outermostCompileUnit).split(); + + assert fn.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + fn.getCompileUnit() + ") != " + outermostCompileUnit; + + if (fn.isStrictMode()) { + assert compiler.getStrictMode(); + compiler.setStrictMode(true); + } + return true; + } + + @Override + public String toString() { + return "[Code Splitting]"; + } + }, + + /* + * FinalizeTypes + * + * This pass finalizes the types for nodes. If Attr created wider types than + * known during the first pass, convert nodes are inserted or access nodes + * are specialized where scope accesses. + * + * Runtime nodes may be removed and primitivized or reintroduced depending + * on information that was established in Attr. + * + * Contract: all variables must have slot assignments and scope assignments + * before type finalization. + */ + TYPE_FINALIZATION_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT), FINALIZED) { + @Override + boolean transform(final Compiler compiler, final FunctionNode fn) { + fn.accept(new FinalizeTypes()); + return true; + } + + @Override + public String toString() { + return "[Type Finalization]"; + } + }, + + /* + * Bytecode generation: + * + * Generate the byte code class(es) resulting from the compiled FunctionNode + */ + BYTECODE_GENERATION_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT, FINALIZED), EMITTED) { + @Override + boolean transform(final Compiler compiler, final FunctionNode fn) { + final Context context = compiler.getContext(); + + try { + final CodeGenerator codegen = new CodeGenerator(compiler); + fn.accept(codegen); + codegen.generateScopeCalls(); + + } catch (final VerifyError e) { + if (context._verify_code || context._print_code) { + context.getErr().println(e.getClass().getSimpleName() + ": " + e.getMessage()); + if (context._dump_on_error) { + e.printStackTrace(context.getErr()); + } + } else { + throw e; + } + } + + for (final CompileUnit compileUnit : compiler.getCompileUnits()) { + final ClassEmitter classEmitter = compileUnit.getClassEmitter(); + classEmitter.end(); + + final byte[] bytecode = classEmitter.toByteArray(); + assert bytecode != null; + + final String className = compileUnit.getUnitClassName(); + + compiler.addClass(className, bytecode); + + //should could be printed to stderr for generate class? + if (context._print_code) { + final StringBuilder sb = new StringBuilder(); + sb.append("class: " + className). + append('\n'). + append(ClassEmitter.disassemble(bytecode)). + append("====="); + context.getErr().println(sb); + } + + //should we verify the generated code? + if (context._verify_code) { + context.verify(bytecode); + } + + //should code be dumped to disk - only valid in compile_only mode? + if (context._dest_dir != null && context._compile_only) { + final String fileName = className.replace('.', File.separatorChar) + ".class"; + final int index = fileName.lastIndexOf(File.separatorChar); + + if (index != -1) { + final File dir = new File(fileName.substring(0, index)); + try { + if (!dir.exists() && !dir.mkdirs()) { + throw new IOException(); + } + final File file = new File(context._dest_dir, fileName); + try (final FileOutputStream fos = new FileOutputStream(file)) { + fos.write(bytecode); + } + } catch (final IOException e) { + Compiler.LOG.warning("Skipping class dump for " + className + ": " + ECMAErrors.getMessage("io.error.cant.write", dir.toString())); + } + } + } + } + + return true; + } + + @Override + public String toString() { + return "[Bytecode Generation]"; + } + }; + + private final EnumSet pre; + private final CompilationState post; + private long startTime; + private long endTime; + private boolean isFinished; + + private static final long[] accumulatedTime = new long[CompilationPhase.values().length]; + + private CompilationPhase(final EnumSet pre) { + this(pre, null); + } + + private CompilationPhase(final EnumSet pre, final CompilationState post) { + this.pre = pre; + this.post = post; + } + + boolean isApplicable(final FunctionNode functionNode) { + return functionNode.hasState(pre); + } + + protected void begin(final FunctionNode functionNode) { + if (pre != null) { + //check that everything in pre is present + for (final CompilationState state : pre) { + assert functionNode.hasState(state); + } + //check that nothing else is present + for (final CompilationState state : CompilationState.values()) { + assert !(functionNode.hasState(state) && !pre.contains(state)); + } + } + + startTime = System.currentTimeMillis(); + } + + protected void end(final FunctionNode functionNode) { + endTime = System.currentTimeMillis(); + accumulatedTime[ordinal()] += (endTime - startTime); + + if (post != null) { + functionNode.setState(post); + } + + isFinished = true; + } + + boolean isFinished() { + return isFinished; + } + + long getStartTime() { + return startTime; + } + + long getEndTime() { + return endTime; + } + + public static long getAccumulatedTime(final CompilationPhase phase) { + return accumulatedTime[phase.ordinal()]; + } + + abstract boolean transform(final Compiler compiler, final FunctionNode functionNode); + + final boolean apply(final Compiler compiler, final FunctionNode functionNode) { + try { + if (!isApplicable(functionNode)) { + return false; + } + begin(functionNode); + transform(compiler, functionNode); + return true; + } finally { + end(functionNode); + } + } + +} diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CompileUnit.java b/nashorn/src/jdk/nashorn/internal/codegen/CompileUnit.java index 727d9e34eba..5e62116b9a1 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CompileUnit.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CompileUnit.java @@ -51,7 +51,7 @@ public class CompileUnit { * Add weight to this compile unit * @param w weight to add */ - public void addWeight(final long w) { + void addWeight(final long w) { this.weight += w; } @@ -59,7 +59,7 @@ public class CompileUnit { * Get the current weight of the compile unit. * @return the unit's weight */ - public long getWeight() { + long getWeight() { return weight; } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java index 3b21ab581a7..23f38749068 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java @@ -27,124 +27,377 @@ package jdk.nashorn.internal.codegen; import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS; import static jdk.nashorn.internal.codegen.CompilerConstants.DEFAULT_SCRIPT_NAME; -import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT; +import static jdk.nashorn.internal.codegen.CompilerConstants.LAZY; import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE; import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; - import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; +import java.util.Arrays; import java.util.EnumSet; +import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.TreeMap; import jdk.nashorn.internal.codegen.ClassEmitter.Flag; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.FunctionNode; -import jdk.nashorn.internal.ir.Node; -import jdk.nashorn.internal.ir.debug.ASTWriter; -import jdk.nashorn.internal.ir.debug.PrintVisitor; -import jdk.nashorn.internal.ir.visitor.NodeVisitor; -import jdk.nashorn.internal.parser.Parser; +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.runtime.CodeInstaller; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.DebugLogger; -import jdk.nashorn.internal.runtime.ECMAErrors; -import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.options.Options; import org.dynalang.dynalink.support.NameCodec; /** * Responsible for converting JavaScripts to java byte code. Main entry - * point for code generator + * point for code generator. The compiler may also install classes given some + * predefined Code installation policy, given to it at construction time. + * @see CodeInstaller */ public final class Compiler { - /** Compiler states available */ - public enum State { - /** compiler is ready */ - INITIALIZED, - /** method has been parsed */ - PARSED, - /** constant folding pass */ - CONSTANT_FOLDED, - /** method has been lowered */ - LOWERED, - /** method hass been attributed */ - ATTR, - /** method has been split */ - SPLIT, - /** method has had its types finalized */ - FINALIZED, - /** method has been emitted to bytecode */ - EMITTED - } - - /** Current context */ - private final Context context; - - /** Currently compiled source */ - private final Source source; - - /** Current error manager */ - private final ErrorManager errors; - - /** Names uniqueName for this compile. */ - private final Namespace namespace; - - /** Current function node, or null if compiling from source until parsed */ - private FunctionNode functionNode; - - /** Current compiler state */ - private final EnumSet state; - /** Name of the scripts package */ public static final String SCRIPTS_PACKAGE = "jdk/nashorn/internal/scripts"; /** Name of the objects package */ public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects"; - /** Name of the runtime package */ - public static final String RUNTIME_PACKAGE = "jdk/nashorn/internal/runtime"; + static final boolean LAZY_JIT = Options.getBooleanProperty("nashorn.compiler.lazy"); - /** Name of the Global object, cannot be referred to as .class, @see CodeGenerator */ - public static final String GLOBAL_OBJECT = OBJECTS_PACKAGE + '/' + "Global"; + static final boolean TIME_COMPILATION = Options.getBooleanProperty("nashorn.compiler.time"); - /** Name of the ScriptFunctionImpl, cannot be referred to as .class @see FunctionObjectCreator */ - public static final String SCRIPTFUNCTION_IMPL_OBJECT = OBJECTS_PACKAGE + '/' + "ScriptFunctionImpl"; + private final Map bytecode; - /** Name of the Trampoline, cannot be referred to as .class @see FunctionObjectCreator */ - public static final String TRAMPOLINE_OBJECT = OBJECTS_PACKAGE + '/' + "Trampoline"; - - /** Compile unit (class) table. */ private final Set compileUnits; - /** All the "complex" constants used in the code. */ private final ConstantData constantData; + private final FunctionNode functionNode; + + private final CompilationSequence sequence; + + private final Context context; + + private final String scriptName; + + private boolean strict; + + private CodeInstaller installer; + static final DebugLogger LOG = new DebugLogger("compiler"); - /** Script name */ - private String scriptName; + /** + * This array contains names that need to be reserved at the start + * of a compile, to avoid conflict with variable names later introduced. + * See {@link CompilerConstants} for special names used for structures + * during a compile. + */ + private static String[] RESERVED_NAMES = { + SCOPE.tag(), + THIS.tag() + }; - /** Should we dump classes to disk and compile only? */ - private final boolean dumpClass; + /** + * This class makes it possible to do your own compilation sequence + * from the code generation package. There are predefined compilation + * sequences already + */ + @SuppressWarnings("serial") + static class CompilationSequence extends LinkedList { - /** Code map class name -> byte code for all classes generated from this Source or FunctionNode */ - private Map code; + CompilationSequence(final CompilationPhase... phases) { + super(Arrays.asList(phases)); + } - /** Are we compiling in strict mode? */ - private boolean strict; + CompilationSequence(final CompilationSequence sequence) { + this(sequence.toArray(new CompilationPhase[sequence.size()])); + } - /** Is this a lazy compilation - i.e. not from source, but jitting a previously parsed FunctionNode? */ - private boolean isLazy; + CompilationSequence insertAfter(final CompilationPhase phase, final CompilationPhase newPhase) { + final CompilationSequence newSeq = new CompilationSequence(); + for (final CompilationPhase elem : this) { + newSeq.add(phase); + if (elem.equals(phase)) { + newSeq.add(newPhase); + } + } + assert newSeq.contains(newPhase); + return newSeq; + } - /** Lazy jitting is disabled by default */ - private static final boolean LAZY_JIT = false; + CompilationSequence insertBefore(final CompilationPhase phase, final CompilationPhase newPhase) { + final CompilationSequence newSeq = new CompilationSequence(); + for (final CompilationPhase elem : this) { + if (elem.equals(phase)) { + newSeq.add(newPhase); + } + newSeq.add(phase); + } + assert newSeq.contains(newPhase); + return newSeq; + } + + CompilationSequence insertFirst(final CompilationPhase phase) { + final CompilationSequence newSeq = new CompilationSequence(this); + newSeq.addFirst(phase); + return newSeq; + } + + CompilationSequence insertLast(final CompilationPhase phase) { + final CompilationSequence newSeq = new CompilationSequence(this); + newSeq.addLast(phase); + return newSeq; + } + } + + /** + * Standard (non-lazy) compilation, that basically will take an entire script + * and JIT it at once. This can lead to long startup time and fewer type + * specializations + */ + final static CompilationSequence SEQUENCE_NORMAL = new CompilationSequence( + CompilationPhase.CONSTANT_FOLDING_PHASE, + CompilationPhase.LOWERING_PHASE, + CompilationPhase.ATTRIBUTION_PHASE, + CompilationPhase.SPLITTING_PHASE, + CompilationPhase.TYPE_FINALIZATION_PHASE, + CompilationPhase.BYTECODE_GENERATION_PHASE); + + final static CompilationSequence SEQUENCE_LAZY = + SEQUENCE_NORMAL.insertFirst(CompilationPhase.LAZY_INITIALIZATION_PHASE); + + final static CompilationSequence SEQUENCE_DEFAULT = + LAZY_JIT ? + SEQUENCE_LAZY : + SEQUENCE_NORMAL; + + /** + * Constructor + * + * @param installer code installer from + * @param functionNode function node (in any available {@link CompilationState}) to compile + * @param sequence {@link Compiler#CompilationSequence} of {@link CompilationPhase}s to apply as this compilation + * @param strict should this compilation use strict mode semantics + */ + Compiler(final Context context, final CodeInstaller installer, final FunctionNode functionNode, final CompilationSequence sequence, final boolean strict) { + this.context = context; + this.functionNode = functionNode; + this.sequence = sequence; + this.installer = installer; + this.strict = strict || functionNode.isStrictMode(); + this.constantData = new ConstantData(); + this.compileUnits = new HashSet<>(); + this.bytecode = new HashMap<>(); + + final StringBuilder sb = new StringBuilder(); + sb.append(functionNode.uniqueName(DEFAULT_SCRIPT_NAME.tag())). + append('$'). + append(safeSourceName(functionNode.getSource())). + append(functionNode.isLazy() ? LAZY.tag() : ""); + + this.scriptName = sb.toString(); + + LOG.info("Initializing compiler for scriptName = " + scriptName + ", root function: '" + functionNode.getName() + "'"); + } + + /** + * Constructor + * + * @param installer code installer from context + * @param functionNode function node (in any available {@link CompilationState}) to compile + * @param strict should this compilation use strict mode semantics + */ + public Compiler(final CodeInstaller installer, final FunctionNode functionNode, final boolean strict) { + this(installer.getOwner(), installer, functionNode, SEQUENCE_DEFAULT, strict); + } + + /** + * Constructor - compilation will use the same strict semantics as context + * + * @param installer code installer from context + * @param functionNode function node (in any available {@link CompilationState}) to compile + */ + public Compiler(final CodeInstaller installer, final FunctionNode functionNode) { + this(installer.getOwner(), installer, functionNode, SEQUENCE_DEFAULT, installer.getOwner()._strict); + } + + /** + * Constructor - compilation needs no installer, but uses a context + * Used in "compile only" scenarios + * @param context a context + * @param functionNode functionNode to compile + */ + public Compiler(final Context context, final FunctionNode functionNode) { + this(context, null, functionNode, SEQUENCE_DEFAULT, context._strict); + } + + /** + * Execute the compilation this Compiler was created with + * @return true if compilation succeeds. + */ + public boolean compile() { + for (final String reservedName : RESERVED_NAMES) { + functionNode.uniqueName(reservedName); + } + + for (final CompilationPhase phase : sequence) { + LOG.info("Entering compile phase " + phase + " for function '" + functionNode.getName() + "'"); + if (phase.isApplicable(functionNode)) { + if (!phase.apply(this, functionNode)) { //TODO exceptions, error logging + return false; + } + } + } + return true; + } + + /** + * Install compiled classes into a given loader + * @return root script class - if there are several compile units they will also be installed + */ + public Class install() { + Class rootClass = null; + + for (final Entry entry : bytecode.entrySet()) { + final String className = entry.getKey(); + LOG.info("Installing class " + className); + + final byte[] code = entry.getValue(); + final Class clazz = installer.install(Compiler.binaryName(className), code); + + if (rootClass == null && firstCompileUnitName().equals(className)) { + rootClass = clazz; + } + + try { + //use reflection to write source and constants table to installed classes + clazz.getField(SOURCE.tag()).set(null, getSource()); + clazz.getField(CONSTANTS.tag()).set(null, getConstantData().toArray()); + } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + LOG.info("Root class: " + rootClass); + return rootClass; + } + + Set getCompileUnits() { + return compileUnits; + } + + boolean getStrictMode() { + return strict; + } + + void setStrictMode(final boolean strict) { + this.strict = strict; + } + + FunctionNode getFunctionNode() { + return functionNode; + } + + ConstantData getConstantData() { + return constantData; + } + + CodeInstaller getCodeInstaller() { + return installer; + } + + Source getSource() { + return functionNode.getSource(); + } + + void addClass(final String name, final byte[] code) { + bytecode.put(name, code); + } + + Context getContext() { + return this.context; + } + + private static String safeSourceName(final Source source) { + String baseName = new File(source.getName()).getName(); + + final int index = baseName.lastIndexOf(".js"); + if (index != -1) { + baseName = baseName.substring(0, index); + } + + baseName = baseName.replace('.', '_').replace('-', '_'); + final String mangled = NameCodec.encode(baseName); + + return mangled != null ? mangled : baseName; + } + + private int nextCompileUnitIndex() { + return compileUnits.size() + 1; + } + + String firstCompileUnitName() { + return SCRIPTS_PACKAGE + '/' + scriptName; + } + + private String nextCompileUnitName() { + return firstCompileUnitName() + '$' + nextCompileUnitIndex(); + } + + CompileUnit addCompileUnit(final long initialWeight) { + return addCompileUnit(nextCompileUnitName(), initialWeight); + } + + CompileUnit addCompileUnit(final String unitClassName) { + return addCompileUnit(unitClassName, 0L); + } + + private CompileUnit addCompileUnit(final String unitClassName, final long initialWeight) { + final CompileUnit compileUnit = initCompileUnit(unitClassName, initialWeight); + compileUnits.add(compileUnit); + LOG.info("Added compile unit " + compileUnit); + return compileUnit; + } + + private CompileUnit initCompileUnit(final String unitClassName, final long initialWeight) { + final ClassEmitter classEmitter = new ClassEmitter(context, functionNode.getSource().getName(), unitClassName, strict); + final CompileUnit compileUnit = new CompileUnit(unitClassName, classEmitter, initialWeight); + + classEmitter.begin(); + + final MethodEmitter initMethod = classEmitter.init(EnumSet.of(Flag.PRIVATE)); + initMethod.begin(); + initMethod.load(Type.OBJECT, 0); + initMethod.newInstance(jdk.nashorn.internal.scripts.JS$.class); + initMethod.returnVoid(); + initMethod.end(); + + return compileUnit; + } + + CompileUnit findUnit(final long weight) { + for (final CompileUnit unit : compileUnits) { + if (unit.canHold(weight)) { + unit.addWeight(weight); + return unit; + } + } + + return addCompileUnit(weight); + } + + /** + * Convert a package/class name to a binary name. + * + * @param name Package/class name. + * @return Binary name. + */ + public static String binaryName(final String name) { + return name.replace('/', '.'); + } /** * Should we use integers for arithmetic operations as well? @@ -164,573 +417,27 @@ public final class Compiler { static { USE_INT_ARITH = Options.getBooleanProperty("nashorn.compiler.intarithmetic"); - assert !USE_INT_ARITH : "Integer arithmetic is not enabled"; } - /** - * Factory method for compiler that should compile from source to bytecode - * - * @param source the source - * @param context context - * - * @return compiler instance - */ - public static Compiler compiler(final Source source, final Context context) { - return Compiler.compiler(source, context, context.getErrorManager(), context._strict); - } - - /** - * Factory method to get a compiler that goes from from source to bytecode - * - * @param source source code - * @param context context - * @param errors error manager - * @param strict compilation in strict mode? - * - * @return compiler instance - */ - public static Compiler compiler(final Source source, final Context context, final ErrorManager errors, final boolean strict) { - return new Compiler(source, context, errors, strict); - } - - /** - * Factory method to get a compiler that goes from FunctionNode (parsed) to bytecode - * Requires previous compiler for state - * - * @param compiler primordial compiler - * @param functionNode functionNode to compile - * - * @return compiler - */ - public static Compiler compiler(final Compiler compiler, final FunctionNode functionNode) { - assert false : "lazy jit - not implemented"; - final Compiler newCompiler = new Compiler(compiler); - newCompiler.state.add(State.PARSED); - newCompiler.functionNode = functionNode; - newCompiler.isLazy = true; - return compiler; - } - - private Compiler(final Compiler compiler) { - this(compiler.source, compiler.context, compiler.errors, compiler.strict); - } - - /** - * Constructor - * - * @param source the source to compile - * @param context context - * @param errors error manager - * @param strict compile in strict mode - */ - private Compiler(final Source source, final Context context, final ErrorManager errors, final boolean strict) { - this.source = source; - this.context = context; - this.errors = errors; - this.strict = strict; - this.namespace = new Namespace(context.getNamespace()); - this.compileUnits = new HashSet<>(); - this.constantData = new ConstantData(); - this.state = EnumSet.of(State.INITIALIZED); - this.dumpClass = context._compile_only && context._dest_dir != null; - } - - private String scriptsPackageName() { - return dumpClass ? "" : (SCRIPTS_PACKAGE + '/'); - } - - private int nextCompileUnitIndex() { - return compileUnits.size() + 1; - } - - private String firstCompileUnitName() { - return scriptsPackageName() + scriptName; - } - - private String nextCompileUnitName() { - return firstCompileUnitName() + '$' + nextCompileUnitIndex(); - } - - private CompileUnit addCompileUnit(final long initialWeight) { - return addCompileUnit(nextCompileUnitName(), initialWeight); - } - - private CompileUnit addCompileUnit(final String unitClassName, final long initialWeight) { - final CompileUnit compileUnit = initCompileUnit(unitClassName, initialWeight); - compileUnits.add(compileUnit); - LOG.info("Added compile unit " + compileUnit); - return compileUnit; - } - - private CompileUnit initCompileUnit(final String unitClassName, final long initialWeight) { - final ClassEmitter classEmitter = new ClassEmitter(this, unitClassName, strict); - final CompileUnit compileUnit = new CompileUnit(unitClassName, classEmitter, initialWeight); - - classEmitter.begin(); - - final MethodEmitter initMethod = classEmitter.init(EnumSet.of(Flag.PRIVATE)); - initMethod.begin(); - initMethod.load(Type.OBJECT, 0); - initMethod.newInstance(jdk.nashorn.internal.scripts.JS$.class); - initMethod.returnVoid(); - initMethod.end(); - - return compileUnit; - } - - /** - * Perform compilation - * - * @return true if successful, false otherwise - if false check the error manager - */ - public boolean compile() { - assert state.contains(State.INITIALIZED); - - /** do we need to parse source? */ - if (!state.contains(State.PARSED)) { - LOG.info("Parsing '" + source + "'"); - - assert this.functionNode == null; - this.functionNode = new Parser(this, strict).parse(RUN_SCRIPT.tag()); - - state.add(State.PARSED); - debugPrintParse(); - - if (errors.hasErrors() || context._parse_only) { - return false; - } - - assert !isLazy; - //tag lazy nodes for later code generation and trampolines - functionNode.accept(new NodeVisitor() { + static { + if (TIME_COMPILATION) { + Runtime.getRuntime().addShutdownHook(new Thread() { @Override - public Node enter(final FunctionNode node) { - if (LAZY_JIT) { - node.setIsLazy(!node.isScript()); + public void run() { + for (final CompilationPhase phase : CompilationPhase.values()) { + final StringBuilder sb = new StringBuilder(); + sb.append(phase); + while (sb.length() < 32) { + sb.append(' '); + } + sb.append(CompilationPhase.getAccumulatedTime(phase)); + sb.append(' '); + sb.append(" ms"); + System.err.println(sb.toString()); //Context err is gone by shutdown TODO } - return node; - } - }); - } else { - assert isLazy; - functionNode.accept(new NodeVisitor() { - @Override - public Node enter(final FunctionNode node) { - node.setIsLazy(false); - return null; //TODO do we want to do this recursively? then return "node" instead } }); } - - assert functionNode != null; - final boolean oldStrict = strict; - - try { - strict |= functionNode.isStrictMode(); - - /* - * These are the compile phases: - * - * Constant folding pass - * Simple constant folding that will make elementary constructs go away - * - * Lower (Control flow pass) - * Finalizes the control flow. Clones blocks for finally constructs and - * similar things. Establishes termination criteria for nodes - * Guarantee return instructions to method making sure control flow - * cannot fall off the end. Replacing high level nodes with lower such - * as runtime nodes where applicable. - * - * Attr - * Assign symbols and types to all nodes. - * - * Splitter - * Split the AST into several compile units based on a size heuristic - * Splitter needs attributed AST for weight calculations (e.g. is - * a + b a ScriptRuntime.ADD with call overhead or a dadd with much - * less). Split IR can lead to scope information being changed. - * - * Contract: all variables must have slot assignments and scope assignments - * before lowering. - * - * FinalizeTypes - * This pass finalizes the types for nodes. If Attr created wider types than - * known during the first pass, convert nodes are inserted or access nodes - * are specialized where scope accesses. - * - * Runtime nodes may be removed and primitivized or reintroduced depending - * on information that was established in Attr. - * - * CodeGeneration - * Emit bytecode - * - */ - - debugPrintAST(); - - if (!state.contains(State.FINALIZED)) { - LOG.info("Folding constants in '" + functionNode.getName() + "'"); - functionNode.accept(new FoldConstants()); - state.add(State.CONSTANT_FOLDED); - - LOG.info("Lowering '" + functionNode.getName() + "'"); - functionNode.accept(new Lower(this)); - state.add(State.LOWERED); - debugPrintAST(); - - LOG.info("Attributing types '" + functionNode.getName() + "'"); - functionNode.accept(new Attr(this)); - state.add(State.ATTR); - - this.scriptName = computeNames(); - - // Main script code always goes to this compile unit. Note that since we start this with zero weight - // and add script code last this class may end up slightly larger than others, but reserving one class - // just for the main script seems wasteful. - final CompileUnit scriptCompileUnit = addCompileUnit(firstCompileUnitName(), 0L); - LOG.info("Splitting '" + functionNode.getName() + "'"); - new Splitter(this, functionNode, scriptCompileUnit).split(); - state.add(State.SPLIT); - assert functionNode.getCompileUnit() == scriptCompileUnit; - - assert strict == functionNode.isStrictMode() : "strict == " + strict + " but functionNode == " + functionNode.isStrictMode(); - if (functionNode.isStrictMode()) { - strict = true; - } - - LOG.info("Finalizing types for '" + functionNode.getName() + "'"); - functionNode.accept(new FinalizeTypes(this)); - state.add(State.FINALIZED); - - // print ast and parse if --print-lower-ast and/or --print-lower-parse are selected - debugPrintAST(); - debugPrintParse(); - - if (errors.hasErrors()) { - return false; - } - } - - try { - LOG.info("Emitting bytecode for '" + functionNode.getName() + "'"); - final CodeGenerator codegen = new CodeGenerator(this); - functionNode.accept(codegen); - codegen.generateScopeCalls(); - } catch (final VerifyError e) { - if (context._verify_code || context._print_code) { - context.getErr().println(e.getClass().getSimpleName() + ": " + e.getMessage()); - if (context._dump_on_error) { - e.printStackTrace(context.getErr()); - } - } else { - throw e; - } - } - - state.add(State.EMITTED); - - code = new TreeMap<>(); - for (final CompileUnit compileUnit : compileUnits) { - final ClassEmitter classEmitter = compileUnit.getClassEmitter(); - classEmitter.end(); - - if (!errors.hasErrors()) { - final byte[] bytecode = classEmitter.toByteArray(); - if (bytecode != null) { - code.put(compileUnit.getUnitClassName(), bytecode); - debugDisassemble(); - debugVerify(); - } - } - } - - if (code.isEmpty()) { - return false; - } - - try { - dumpClassFiles(); - } catch (final IOException e) { - throw new RuntimeException(e); - } - - return true; - } finally { - strict = oldStrict; - LOG.info("Done with '" + functionNode.getName() + "'"); - } } - - /** - * Install compiled classes into a given loader - * @param installer that takes the generated classes and puts them in the system - * @return root script class - if there are several compile units they will also be installed - */ - public Class install(final CodeInstaller installer) { - assert state.contains(State.EMITTED); - assert scriptName != null; - - Class rootClass = null; - - for (final Entry entry : code.entrySet()) { - final String className = entry.getKey(); - LOG.info("Installing class " + className); - - final byte[] bytecode = entry.getValue(); - final Class clazz = installer.install(Compiler.binaryName(className), bytecode); - - if (rootClass == null && firstCompileUnitName().equals(className)) { - rootClass = clazz; - } - - try { - //use reflection to write source and constants table to installed classes - clazz.getField(SOURCE.tag()).set(null, source); - clazz.getField(CONSTANTS.tag()).set(null, constantData.toArray()); - } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - LOG.info("Root class: " + rootClass); - - return rootClass; - } - - /** - * Find a unit that will hold a node of the specified weight. - * - * @param weight Weight of a node - * @return Unit to hold node. - */ - CompileUnit findUnit(final long weight) { - for (final CompileUnit unit : compileUnits) { - if (unit.canHold(weight)) { - unit.addWeight(weight); - return unit; - } - } - - return addCompileUnit(weight); - } - - /** - * Generate a uniqueName name. Public as {@link Parser} is using this to - * create symbols in a different package - * - * @param name to base unique name on - * @return unique name - */ - public String uniqueName(final String name) { - return namespace.uniqueName(name); - } - - /** - * Internal function to compute reserved names and base names for class to - * be generated - * - * @return scriptName - */ - private String computeNames() { - // Reserve internally used names. - addReservedNames(); - - if (dumpClass) { - // get source file name and remove ".js" - final String baseName = getSource().getName(); - final int index = baseName.lastIndexOf(".js"); - if (index != -1) { - return baseName.substring(0, index); - } - return baseName; - } - - return namespace.getParent().uniqueName( - DEFAULT_SCRIPT_NAME.tag() + - '$' + - safeSourceName(source) + - (isLazy ? CompilerConstants.LAZY.tag() : "") - ); - } - - private static String safeSourceName(final Source source) { - String baseName = new File(source.getName()).getName(); - final int index = baseName.lastIndexOf(".js"); - if (index != -1) { - baseName = baseName.substring(0, index); - } - - baseName = baseName.replace('.', '_').replace('-', '_'); - final String mangled = NameCodec.encode(baseName); - - baseName = mangled != null ? mangled : baseName; - return baseName; - } - - static void verify(final Context context, final byte[] code) { - context.verify(code); - } - - /** - * Fill in the namespace with internally reserved names. - */ - private void addReservedNames() { - namespace.uniqueName(SCOPE.tag()); - namespace.uniqueName(THIS.tag()); - } - - /** - * Get the constant data for this Compiler - * - * @return the constant data - */ - public ConstantData getConstantData() { - return constantData; - } - - /** - * Get the Context used for Compilation - * @see Context - * @return the context - */ - public Context getContext() { - return context; - } - - /** - * Get the Source being compiled - * @see Source - * @return the source - */ - public Source getSource() { - return source; - } - - /** - * Get the error manager used for this compiler - * @return the error manager - */ - public ErrorManager getErrors() { - return errors; - } - - /** - * Get the namespace used for this Compiler - * @see Namespace - * @return the namespace - */ - public Namespace getNamespace() { - return namespace; - } - - /* - * Debugging - */ - - /** - * Print the AST before or after lowering, see --print-ast, --print-lower-ast - */ - private void debugPrintAST() { - assert functionNode != null; - if (context._print_lower_ast && state.contains(State.LOWERED) || - context._print_ast && !state.contains(State.LOWERED)) { - context.getErr().println(new ASTWriter(functionNode)); - } - } - - /** - * Print the parsed code before or after lowering, see --print-parse, --print-lower-parse - */ - private boolean debugPrintParse() { - if (errors.hasErrors()) { - return false; - } - - assert functionNode != null; - - if (context._print_lower_parse && state.contains(State.LOWERED) || - context._print_parse && !state.contains(State.LOWERED)) { - final PrintVisitor pv = new PrintVisitor(); - functionNode.accept(pv); - context.getErr().print(pv); - context.getErr().flush(); - } - - return true; - } - - private void debugDisassemble() { - assert code != null; - if (context._print_code) { - for (final Map.Entry entry : code.entrySet()) { - context.getErr().println("CLASS: " + entry.getKey()); - context.getErr().println(); - ClassEmitter.disassemble(context, entry.getValue()); - context.getErr().println("======"); - } - } - } - - private void debugVerify() { - if (context._verify_code) { - for (final Map.Entry entry : code.entrySet()) { - Compiler.verify(context, entry.getValue()); - } - } - } - - /** - * Implements the "-d" option - dump class files from script to specified output directory - * - * @throws IOException if classes cannot be written - */ - private void dumpClassFiles() throws IOException { - if (context._dest_dir == null) { - return; - } - - assert code != null; - - for (final Entry entry : code.entrySet()) { - final String className = entry.getKey(); - final String fileName = className.replace('.', File.separatorChar) + ".class"; - final int index = fileName.lastIndexOf(File.separatorChar); - - if (index != -1) { - final File dir = new File(fileName.substring(0, index)); - if (!dir.exists() && !dir.mkdirs()) { - throw new IOException(ECMAErrors.getMessage("io.error.cant.write", dir.toString())); - } - } - - final byte[] bytecode = entry.getValue(); - final File outFile = new File(context._dest_dir, fileName); - try (final FileOutputStream fos = new FileOutputStream(outFile)) { - fos.write(bytecode); - } - } - } - - /** - * Convert a package/class name to a binary name. - * - * @param name Package/class name. - * @return Binary name. - */ - public static String binaryName(final String name) { - return name.replace('/', '.'); - } - - /** - * Convert a binary name to a package/class name. - * - * @param name Binary name. - * @return Package/class name. - */ - public static String pathName(final String name) { - return name.replace('.', '/'); - } - - } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ConstantData.java b/nashorn/src/jdk/nashorn/internal/codegen/ConstantData.java index 0862f1efc8a..631cdb3e3ea 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/ConstantData.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/ConstantData.java @@ -35,7 +35,7 @@ import java.util.Map; * Manages constants needed by code generation. Objects are maintained in an * interning maps to remove duplicates. */ -public class ConstantData { +class ConstantData { /** Constant table. */ final List constants; diff --git a/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java b/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java index b9deb64eae7..ffa4a55bcd3 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java @@ -66,7 +66,6 @@ import jdk.nashorn.internal.parser.TokenType; import jdk.nashorn.internal.runtime.Debug; import jdk.nashorn.internal.runtime.DebugLogger; import jdk.nashorn.internal.runtime.JSType; -import jdk.nashorn.internal.runtime.Source; /** * Lower to more primitive operations. After lowering, an AST has symbols and @@ -83,18 +82,9 @@ import jdk.nashorn.internal.runtime.Source; final class FinalizeTypes extends NodeOperatorVisitor { - /** Current source. */ - private final Source source; - private static final DebugLogger LOG = new DebugLogger("finalize"); - /** - * Constructor. - * - * @param compiler the compiler - */ - FinalizeTypes(final Compiler compiler) { - this.source = compiler.getSource(); + FinalizeTypes() { } @Override @@ -424,16 +414,20 @@ final class FinalizeTypes extends NodeOperatorVisitor { @Override public Node enter(final FunctionNode functionNode) { + if (functionNode.isLazy()) { + return null; + } + // If the function doesn't need a callee, we ensure its __callee__ symbol doesn't get a slot. We can't do // this earlier, as access to scoped variables, self symbol, etc. in previous phases can all trigger the // need for the callee. - if(!functionNode.needsCallee()) { + if (!functionNode.needsCallee()) { functionNode.getCalleeNode().getSymbol().setNeedsSlot(false); } // Similar reasoning applies to __scope__ symbol: if the function doesn't need either parent scope or its // own scope, we ensure it doesn't get a slot, but we can't determine whether it needs a scope earlier than // this phase. - if(!(functionNode.needsScope() || functionNode.needsParentScope())) { + if (!(functionNode.needsScope() || functionNode.needsParentScope())) { functionNode.getScopeNode().getSymbol().setNeedsSlot(false); } @@ -443,8 +437,7 @@ final class FinalizeTypes extends NodeOperatorVisitor { @Override public Node leave(final IfNode ifNode) { - final Node test = convert(ifNode.getTest(), Type.BOOLEAN); - ifNode.setTest(test); + ifNode.setTest(convert(ifNode.getTest(), Type.BOOLEAN)); return ifNode; } @@ -518,6 +511,7 @@ final class FinalizeTypes extends NodeOperatorVisitor { @Override public Node leave(final VarNode varNode) { + final Node rhs = varNode.getInit(); if (rhs != null) { Type destType = specialize(varNode); @@ -823,7 +817,7 @@ final class FinalizeTypes extends NodeOperatorVisitor { setTypeOverride(node, to); return resultNode; } - resultNode = new UnaryNode(source, Token.recast(node.getToken(), TokenType.CONVERT), node); + resultNode = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.CONVERT), node); } LOG.info("CONVERT('" + node + "', " + to + ") => '" + resultNode + "'"); @@ -836,11 +830,11 @@ final class FinalizeTypes extends NodeOperatorVisitor { return resultNode; } - private Node discard(final Node node) { + private static Node discard(final Node node) { node.setDiscard(true); if (node.getSymbol() != null) { - final Node discard = new UnaryNode(source, Token.recast(node.getToken(), TokenType.DISCARD), node); + final Node discard = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.DISCARD), node); //discard never has a symbol in the discard node - then it would be a nop discard.copyTerminalFlags(node); return discard; diff --git a/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java b/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java index a7e7aa2d3b7..4ea53a04351 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java @@ -44,10 +44,13 @@ import jdk.nashorn.internal.runtime.Source; /** * Simple constant folding pass, executed before IR is starting to be lowered. */ -public class FoldConstants extends NodeVisitor { +final class FoldConstants extends NodeVisitor { private static final DebugLogger LOG = new DebugLogger("fold"); + FoldConstants() { + } + @Override public Node leave(final UnaryNode unaryNode) { final LiteralNode literalNode = new UnaryNodeConstantEvaluator(unaryNode).eval(); diff --git a/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java b/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java index 7bb7747e547..26d040cdb62 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java @@ -25,6 +25,8 @@ package jdk.nashorn.internal.codegen; +import java.lang.invoke.MethodType; +import java.util.ArrayList; import java.util.List; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.FunctionNode; @@ -32,6 +34,8 @@ import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.linker.LinkerCallSite; +import static jdk.nashorn.internal.runtime.linker.Lookup.MH; + /** * Class that generates function signatures for dynamic calls */ @@ -46,6 +50,9 @@ public final class FunctionSignature { /** valid Java descriptor string for function */ private final String descriptor; + /** {@link MethodType} for function */ + private final MethodType methodType; + /** * Constructor * @@ -126,8 +133,31 @@ public final class FunctionSignature { assert false : "isVarArgs cannot be false when argTypes are null"; } - returnType = retType; - descriptor = Type.getMethodDescriptor(returnType, paramTypes); + this.returnType = retType; + this.descriptor = Type.getMethodDescriptor(returnType, paramTypes); + + final List> paramTypeList = new ArrayList<>(); + for (final Type paramType : paramTypes) { + paramTypeList.add(paramType.getTypeClass()); + } + + this.methodType = MH.type(returnType.getTypeClass(), paramTypeList.toArray(new Class[paramTypes.length])); + } + + /** + * Create a function signature given a function node, using as much + * type information for parameters and return types that is availabe + * + * @param functionNode the function node + */ + public FunctionSignature(final FunctionNode functionNode) { + this( + true, + functionNode.needsCallee(), + functionNode.getReturnType(), + (functionNode.isVarArg() && !functionNode.isScript()) ? + null : + functionNode.getParameters()); } /** @@ -165,21 +195,14 @@ public final class FunctionSignature { } /** - * Returns the generic signature of the function being compiled. - * - * @param functionNode function being compiled. - * @return function signature. + * Return the {@link MethodType} for this function signature + * @return the method type */ - public static String functionSignature(final FunctionNode functionNode) { - return new FunctionSignature( - true, - functionNode.needsCallee(), - functionNode.getReturnType(), - (functionNode.isVarArg() && !functionNode.isScript()) ? - null : - functionNode.getParameters()).toString(); + public MethodType getMethodType() { + return methodType; } + private static Type[] objectArgs(final int nArgs) { final Type[] array = new Type[nArgs]; for (int i = 0; i < nArgs; i++) { diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java index 712e076329e..5f0026893c9 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java @@ -89,10 +89,6 @@ import jdk.nashorn.internal.runtime.Source; final class Lower extends NodeOperatorVisitor { - private final Compiler compiler; - - private final Source source; - /** * Nesting level stack. Currently just used for loops to avoid the problem * with terminal bodies that end with throw/return but still do continues to @@ -111,9 +107,7 @@ final class Lower extends NodeOperatorVisitor { * * @param compiler the compiler */ - Lower(final Compiler compiler) { - this.compiler = compiler; - this.source = compiler.getSource(); + Lower() { this.nesting = new ArrayDeque<>(); this.statements = new ArrayList<>(); } @@ -204,7 +198,7 @@ final class Lower extends NodeOperatorVisitor { if (getCurrentFunctionNode().isScript()) { if (!(expr instanceof Block)) { if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) { - executeNode.setExpression(new BinaryNode(source, Token.recast(executeNode.getToken(), TokenType.ASSIGN), + executeNode.setExpression(new BinaryNode(executeNode.getSource(), Token.recast(executeNode.getToken(), TokenType.ASSIGN), getCurrentFunctionNode().getResultNode(), expr)); } @@ -254,6 +248,11 @@ final class Lower extends NodeOperatorVisitor { public Node enter(final FunctionNode functionNode) { LOG.info("START FunctionNode: " + functionNode.getName()); + if (functionNode.isLazy()) { + LOG.info("LAZY: " + functionNode.getName()); + return null; + } + initFunctionNode(functionNode); Node initialEvalResult = LiteralNode.newInstance(functionNode, ScriptRuntime.UNDEFINED); @@ -299,7 +298,7 @@ final class Lower extends NodeOperatorVisitor { } if (functionNode.isScript()) { - new ExecuteNode(source, functionNode.getFirstToken(), functionNode.getFinish(), initialEvalResult).accept(this); + new ExecuteNode(functionNode.getSource(), functionNode.getFirstToken(), functionNode.getFinish(), initialEvalResult).accept(this); } //do the statements - this fills the block with code @@ -379,6 +378,8 @@ final class Lower extends NodeOperatorVisitor { if (tryNode != null) { //we are inside a try block - we don't necessarily have a result node yet. attr will do that. if (expr != null) { + final Source source = getCurrentFunctionNode().getSource(); + //we need to evaluate the result of the return in case it is complex while //still in the try block, store it in a result value and return it afterwards final long token = returnNode.getToken(); @@ -518,6 +519,7 @@ final class Lower extends NodeOperatorVisitor { * finally_body_inlined marked (*) will fix it before rethrowing * whatever problem there was for identical semantic. */ + final Source source = getCurrentFunctionNode().getSource(); // if try node does not contain a catch we can skip creation of a new // try node and just append our synthetic catch to the existing try node. @@ -559,7 +561,7 @@ final class Lower extends NodeOperatorVisitor { final CatchNode catchAllNode; final IdentNode exception; - exception = new IdentNode(source, token, finish, compiler.uniqueName("catch_all")); + exception = new IdentNode(source, token, finish, getCurrentFunctionNode().uniqueName("catch_all")); catchAllNode = new CatchNode(source, token, finish, new IdentNode(exception), null, catchBody); catchAllNode.setIsSyntheticRethrow(); @@ -632,7 +634,7 @@ final class Lower extends NodeOperatorVisitor { if (whileNode instanceof DoWhileNode) { setTerminal(whileNode, true); } else if (conservativeAlwaysTrue(test)) { - node = new ForNode(source, whileNode.getToken(), whileNode.getFinish()); + node = new ForNode(whileNode.getSource(), whileNode.getToken(), whileNode.getFinish()); ((ForNode)node).setBody(body); ((ForNode)node).accept(this); setTerminal(node, !escapes); @@ -799,7 +801,7 @@ final class Lower extends NodeOperatorVisitor { } //create a return statement - final Node returnNode = new ReturnNode(source, functionNode.getLastToken(), functionNode.getFinish(), resultNode, null); + final Node returnNode = new ReturnNode(functionNode.getSource(), functionNode.getLastToken(), functionNode.getFinish(), resultNode, null); returnNode.accept(this); } @@ -897,7 +899,7 @@ final class Lower extends NodeOperatorVisitor { finallyBody = (Block)finallyBody.clone(); final boolean hasTerminalFlags = finallyBody.hasTerminalFlags(); - new ExecuteNode(source, finallyBody.getToken(), finallyBody.getFinish(), finallyBody).accept(this); + new ExecuteNode(finallyBody.getSource(), finallyBody.getToken(), finallyBody.getFinish(), finallyBody).accept(this); if (hasTerminalFlags) { getCurrentBlock().copyTerminalFlags(finallyBody); @@ -951,17 +953,18 @@ final class Lower extends NodeOperatorVisitor { * TODO : only create those that are needed. * TODO : make sure slot numbering is not hardcoded in {@link CompilerConstants} - now creation order is significant */ - private void initFunctionNode(final FunctionNode functionNode) { - final long token = functionNode.getToken(); - final int finish = functionNode.getFinish(); + private static void initFunctionNode(final FunctionNode functionNode) { + final Source source = functionNode.getSource(); + final long token = functionNode.getToken(); + final int finish = functionNode.getFinish(); functionNode.setThisNode(new IdentNode(source, token, finish, THIS.tag())); functionNode.setScopeNode(new IdentNode(source, token, finish, SCOPE.tag())); functionNode.setResultNode(new IdentNode(source, token, finish, SCRIPT_RETURN.tag())); functionNode.setCalleeNode(new IdentNode(source, token, finish, CALLEE.tag())); - if(functionNode.isVarArg()) { + if (functionNode.isVarArg()) { functionNode.setVarArgsNode(new IdentNode(source, token, finish, VARARGS.tag())); - if(functionNode.needsArguments()) { + if (functionNode.needsArguments()) { functionNode.setArgumentsNode(new IdentNode(source, token, finish, ARGUMENTS.tag())); } } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java b/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java index 70be10876c3..f8e26996298 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java @@ -106,11 +106,11 @@ public class SharedScopeCall { /** * Set the compile unit and method name. * @param compileUnit the compile unit - * @param compiler the compiler to generate a unique method name + * @param methodName the method name */ - protected void setClassAndName(final CompileUnit compileUnit, final Compiler compiler) { + protected void setClassAndName(final CompileUnit compileUnit, final String methodName) { this.compileUnit = compileUnit; - this.methodName = compiler.uniqueName("scopeCall"); + this.methodName = methodName; } /** diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java index abaab42b0fb..d95fd4b6c37 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java @@ -49,13 +49,14 @@ import jdk.nashorn.internal.ir.SplitNode; import jdk.nashorn.internal.ir.SwitchNode; import jdk.nashorn.internal.ir.WhileNode; import jdk.nashorn.internal.ir.visitor.NodeVisitor; +import jdk.nashorn.internal.runtime.DebugLogger; import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.options.Options; /** * Split the IR into smaller compile units. */ -public class Splitter extends NodeVisitor { +final class Splitter extends NodeVisitor { /** Current compiler. */ private final Compiler compiler; @@ -63,7 +64,7 @@ public class Splitter extends NodeVisitor { private final FunctionNode functionNode; /** Compile unit for the main script. */ - private final CompileUnit scriptCompileUnit; + private final CompileUnit outermostCompileUnit; /** Cache for calculated block weights. */ private final Map weightCache = new HashMap<>(); @@ -71,27 +72,35 @@ public class Splitter extends NodeVisitor { /** Weight threshold for when to start a split. */ public static final long SPLIT_THRESHOLD = Options.getIntProperty("nashorn.compiler.splitter.threshold", 32 * 1024); + private static final DebugLogger LOG = Compiler.LOG; + /** * Constructor. * - * @param compiler the compiler - * @param functionNode function node to split - * @param scriptCompileUnit script compile unit + * @param compiler the compiler + * @param functionNode function node to split + * @param outermostCompileUnit compile unit for outermost function, if non-lazy this is the script's compile unit */ - public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit scriptCompileUnit) { - this.compiler = compiler; - this.functionNode = functionNode; - this.scriptCompileUnit = scriptCompileUnit; + public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) { + this.compiler = compiler; + this.functionNode = functionNode; + this.outermostCompileUnit = outermostCompileUnit; } /** * Execute the split */ void split() { + if (functionNode.isLazy()) { + LOG.info("Postponing split of '" + functionNode.getName() + "' as it's lazy"); + return; + } + LOG.info("Initiating split of '" + functionNode.getName() + "'"); + long weight = WeighNodes.weigh(functionNode); if (weight >= SPLIT_THRESHOLD) { - Compiler.LOG.info("Splitting '" + functionNode.getName() + "' as its weight " + weight + " exceeds split threshold " + SPLIT_THRESHOLD); + LOG.info("Splitting '" + functionNode.getName() + "' as its weight " + weight + " exceeds split threshold " + SPLIT_THRESHOLD); functionNode.accept(this); @@ -111,20 +120,18 @@ public class Splitter extends NodeVisitor { assert functionNode.getCompileUnit() == null : "compile unit already set"; - if (functionNode.isScript()) { - assert scriptCompileUnit != null : "script compile unit is null"; + if (compiler.getFunctionNode() == functionNode) { //functionNode.isScript()) { + assert outermostCompileUnit != null : "outermost compile unit is null"; - functionNode.setCompileUnit(scriptCompileUnit); - scriptCompileUnit.addWeight(weight + WeighNodes.FUNCTION_WEIGHT); + functionNode.setCompileUnit(outermostCompileUnit); + outermostCompileUnit.addWeight(weight + WeighNodes.FUNCTION_WEIGHT); } else { functionNode.setCompileUnit(findUnit(weight)); } // Recursively split nested functions - final List functions = functionNode.getFunctions(); - - for (final FunctionNode function : functions) { - new Splitter(compiler, function, scriptCompileUnit).split(); + for (final FunctionNode function : functionNode.getFunctions()) { + new Splitter(compiler, function, outermostCompileUnit).split(); } } @@ -192,7 +199,7 @@ public class Splitter extends NodeVisitor { final Source source = parent.getSource(); final long token = parent.getToken(); final int finish = parent.getFinish(); - final String name = compiler.uniqueName(SPLIT_PREFIX.tag()); + final String name = parent.getFunction().uniqueName(SPLIT_PREFIX.tag()); final Block newBlock = new Block(source, token, finish, parent, functionNode); newBlock.setFrame(new Frame(parent.getFrame())); @@ -284,6 +291,10 @@ public class Splitter extends NodeVisitor { @Override public Node enter(final FunctionNode node) { + if (node.isLazy()) { + return null; + } + final List statements = node.getStatements(); for (final Node statement : statements) { diff --git a/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java b/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java index 76bf61936c9..006f1e27e6e 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java @@ -66,7 +66,7 @@ import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; * Computes the "byte code" weight of an AST segment. This is used * for Splitting too large class files */ -public class WeighNodes extends NodeOperatorVisitor { +final class WeighNodes extends NodeOperatorVisitor { /* * Weight constants. */ diff --git a/nashorn/src/jdk/nashorn/internal/codegen/objects/FunctionObjectCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/objects/FunctionObjectCreator.java deleted file mode 100644 index 72ed43b1710..00000000000 --- a/nashorn/src/jdk/nashorn/internal/codegen/objects/FunctionObjectCreator.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 jdk.nashorn.internal.codegen.objects; - -import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.HANDLE_STATIC; -import static jdk.nashorn.internal.codegen.Compiler.SCRIPTFUNCTION_IMPL_OBJECT; -import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE; -import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; -import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; - -import java.lang.invoke.MethodHandle; -import java.util.ArrayList; -import java.util.EnumSet; - -import jdk.nashorn.internal.codegen.CodeGenerator; -import jdk.nashorn.internal.codegen.FunctionSignature; -import jdk.nashorn.internal.codegen.MethodEmitter; -import jdk.nashorn.internal.ir.FunctionNode; -import jdk.nashorn.internal.ir.Symbol; -import jdk.nashorn.internal.runtime.PropertyMap; -import jdk.nashorn.internal.runtime.ScriptFunctionData; -import jdk.nashorn.internal.runtime.ScriptObject; - -/** - * Analyze a function object's characteristics for appropriate code - * generation. This generates code for the instantiation of ScriptFunctions. - */ -public class FunctionObjectCreator extends ObjectCreator { - - private final FunctionNode functionNode; - - /** - * Constructor - * - * @param codegen the code generator - * @param functionNode the function node to turn into a ScriptFunction implementation - */ - public FunctionObjectCreator(final CodeGenerator codegen, final FunctionNode functionNode) { - super(codegen, new ArrayList(), new ArrayList(), false, false); - this.functionNode = functionNode; - } - - private void loadHandle(final MethodEmitter method, final String signature) { - method.loadHandle(functionNode.getCompileUnit().getUnitClassName(), functionNode.getName(), signature, EnumSet.of(HANDLE_STATIC)); // function - } - - /** - * Emit code for creating the object - * - * @param method the method emitter - */ - @Override - public void makeObject(final MethodEmitter method) { - - final PropertyMap map = makeMap(); - final String signature = new FunctionSignature(true, functionNode.needsCallee(), functionNode.getReturnType(), functionNode.isVarArg() ? null : functionNode.getParameters()).toString(); - final ScriptFunctionData scriptFunctionData = new ScriptFunctionData(functionNode, map); - - /* - * Instantiate the function object - */ - method._new(SCRIPTFUNCTION_IMPL_OBJECT).dup(); - codegen.loadConstant(scriptFunctionData); - loadHandle(method, signature); - if(functionNode.needsParentScope()) { - method.loadScope(); - } else { - method.loadNull(); - } - method.loadHandle(getClassName(), ALLOCATE.tag(), methodDescriptor(ScriptObject.class, PropertyMap.class), EnumSet.of(HANDLE_STATIC)); - - /* - * Invoke the constructor - */ - method.invoke(constructorNoLookup(SCRIPTFUNCTION_IMPL_OBJECT, ScriptFunctionData.class, MethodHandle.class, ScriptObject.class, MethodHandle.class)); - - } -} diff --git a/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectClassGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectClassGenerator.java index 3c69687ae4d..72f9181845d 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectClassGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectClassGenerator.java @@ -472,11 +472,11 @@ public final class ObjectClassGenerator { final byte[] code = classEmitter.toByteArray(); if (context != null && context._print_code) { - ClassEmitter.disassemble(context, code); + Context.getCurrentErr().println(ClassEmitter.disassemble(code)); } if (context != null && context._verify_code) { - ClassEmitter.verify(context, code); + context.verify(code); } return code; diff --git a/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java b/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java index 6d2b3a16e1d..958f7b757fc 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java +++ b/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java @@ -32,15 +32,16 @@ import static jdk.nashorn.internal.ir.Symbol.IS_TEMP; import java.util.ArrayList; import java.util.Collections; +import java.util.EnumSet; import java.util.LinkedList; import java.util.List; import java.util.Stack; + import jdk.nashorn.internal.codegen.CompileUnit; import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.codegen.Frame; import jdk.nashorn.internal.codegen.MethodEmitter; import jdk.nashorn.internal.codegen.Namespace; -import jdk.nashorn.internal.codegen.Splitter; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.annotations.Ignore; import jdk.nashorn.internal.ir.visitor.NodeVisitor; @@ -67,6 +68,28 @@ public class FunctionNode extends Block { SETTER } + /** Compilation states available */ + public enum CompilationState { + /** compiler is ready */ + INITIALIZED, + /** method has been parsed */ + PARSED, + /** method has been parsed */ + PARSE_ERROR, + /** constant folding pass */ + CONSTANT_FOLDED, + /** method has been lowered */ + LOWERED, + /** method hass been attributed */ + ATTR, + /** method has been split */ + SPLIT, + /** method has had its types finalized */ + FINALIZED, + /** method has been emitted to bytecode */ + EMITTED + } + /** External function identifier. */ @Ignore private IdentNode ident; @@ -147,6 +170,10 @@ public class FunctionNode extends Block { @Ignore private Node selfSymbolInit; + /** Current compilation state */ + @Ignore + private final EnumSet compilationState; + /** Function flags. */ private int flags; @@ -200,16 +227,16 @@ public class FunctionNode extends Block { /** * Constructor * - * @param source the source - * @param token token - * @param finish finish - * @param compiler the compiler - * @param parent the parent block - * @param ident the identifier - * @param name the name of the function + * @param source the source + * @param token token + * @param finish finish + * @param namespace the namespace + * @param parent the parent block + * @param ident the identifier + * @param name the name of the function */ @SuppressWarnings("LeakingThisInConstructor") - public FunctionNode(final Source source, final long token, final int finish, final Compiler compiler, final Block parent, final IdentNode ident, final String name) { + public FunctionNode(final Source source, final long token, final int finish, final Namespace namespace, final Block parent, final IdentNode ident, final String name) { super(source, token, finish, parent, null); this.ident = ident; @@ -219,7 +246,7 @@ public class FunctionNode extends Block { this.functions = new ArrayList<>(); this.firstToken = token; this.lastToken = token; - this.namespace = new Namespace(compiler.getNamespace().getParent()); + this.namespace = namespace; this.labelStack = new Stack<>(); this.controlStack = new Stack<>(); this.declarations = new ArrayList<>(); @@ -227,6 +254,7 @@ public class FunctionNode extends Block { // it as such a leak - this is a false positive as we're setting this into a field of the object being // constructed, so it can't be seen from other threads. this.function = this; + this.compilationState = EnumSet.of(CompilationState.INITIALIZED); } @SuppressWarnings("LeakingThisInConstructor") @@ -269,6 +297,8 @@ public class FunctionNode extends Block { // it as such a leak - this is a false positive as we're setting this into a field of the object being // constructed, so it can't be seen from other threads. this.function = this; + + this.compilationState = EnumSet.copyOf(functionNode.compilationState); } @Override @@ -344,6 +374,41 @@ public class FunctionNode extends Block { return super.needsScope() || isScript(); } + /** + * Check whether this FunctionNode has reached a give CompilationState. + * + * @param state the state to check for + * @return true of the node is in the given state + */ + public boolean hasState(final EnumSet state) { + return compilationState.equals(state); + } + + /** + * Check whether the state of this FunctionNode contains a given compilation + * state. + * + * A node can be in many states at once, e.g. both lowered and initialized. + * To check for an exact state, use {FunctionNode{@link #hasState(EnumSet)} + * + * @param state state to check for + * @return true if state is present in the total compilation state of this FunctionNode + */ + public boolean hasState(final CompilationState state) { + return compilationState.contains(state); + } + + /** + * Add a state to the total CompilationState of this node, e.g. if + * FunctionNode has been lowered, the compiler will add + * {@code CompilationState#LOWERED} to the state vector + * + * @param state {@link CompilationState} to add + */ + public void setState(final CompilationState state) { + compilationState.add(state); + } + /* * Frame management. */ @@ -365,17 +430,6 @@ public class FunctionNode extends Block { frames = frames.getPrevious(); } - /** - * return a unique name in the scope of the function. - * - * @param base Base string. - * - * @return Unique name. - */ - public String uniqueName(final String base) { - return namespace.uniqueName(base); - } - /** * Create a temporary variable to the current frame. * @@ -407,6 +461,15 @@ public class FunctionNode extends Block { return symbol; } + /** + * Create a unique name in the namespace of this FunctionNode + * @param base prefix for name + * @return base if no collision exists, otherwise a name prefix with base + */ + public String uniqueName(final String base) { + return namespace.uniqueName(base); + } + /** * Add a new temporary variable to the current frame * @@ -428,11 +491,11 @@ public class FunctionNode extends Block { */ public Symbol newLiteral(final LiteralNode literalNode) { final String uname = uniqueName(LITERAL_PREFIX.tag()); - final Symbol sym = new Symbol(uname, IS_CONSTANT, literalNode.getType()); - sym.setNode(literalNode); - literalNode.setSymbol(sym); + final Symbol symbol = new Symbol(uname, IS_CONSTANT, literalNode.getType()); + symbol.setNode(literalNode); + literalNode.setSymbol(symbol); - return sym; + return symbol; } @Override @@ -806,7 +869,6 @@ public class FunctionNode extends Block { /** * Checks if this function is a sub-function generated by splitting a larger one - * @see Splitter * * @return true if this function is split from a larger one */ @@ -816,7 +878,6 @@ public class FunctionNode extends Block { /** * Flag this function node as being a sub-function generated by the splitter - * @see Splitter */ public void setIsSplit() { this.flags |= IS_SPLIT; @@ -1149,7 +1210,6 @@ public class FunctionNode extends Block { /** * Get the compile unit used to compile this function * @see Compiler - * @see Splitter * @return the compile unit */ public CompileUnit getCompileUnit() { @@ -1159,7 +1219,6 @@ public class FunctionNode extends Block { /** * Reset the compile unit used to compile this function * @see Compiler - * @see Splitter * @param compileUnit the compile unit */ public void setCompileUnit(final CompileUnit compileUnit) { diff --git a/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java b/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java index 103670d024a..79d93499161 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java +++ b/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java @@ -25,11 +25,8 @@ package jdk.nashorn.internal.ir.debug; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.Arrays; import java.util.List; -import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.ir.AccessNode; import jdk.nashorn.internal.ir.BinaryNode; @@ -87,8 +84,7 @@ public final class JSONWriter extends NodeVisitor { * @return JSON string representation of AST of the supplied code */ public static String parse(final Context context, final String code, final String name, final boolean includeLoc) { - final Compiler compiler = Compiler.compiler(new Source(name, code), context, new Context.ThrowErrorManager(), context._strict); - final Parser parser = new Parser(compiler, context._strict); + final Parser parser = new Parser(context, new Source(name, code), new Context.ThrowErrorManager(), context._strict); final JSONWriter jsonWriter = new JSONWriter(includeLoc); try { final FunctionNode functionNode = parser.parse(CompilerConstants.RUN_SCRIPT.tag()); diff --git a/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java index 63cb5bd9e00..9ce6fd02b3e 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java +++ b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java @@ -70,7 +70,7 @@ public abstract class NodeVisitor { private FunctionNode currentFunctionNode; /** Current compile unit used for class generation. */ - protected CompileUnit compileUnit; + private CompileUnit compileUnit; /** * Current method visitor used for method generation. diff --git a/nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java b/nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java index 2b8691946b0..1e9e9d187b7 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java +++ b/nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java @@ -32,7 +32,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; /** * A {@code ScriptFunctionImpl} subclass for functions created using {@code Function.prototype.bind}. Such functions - * must track their {@code [[TargetFunction]] property for purposes of correctly implementing {@code [[HasInstance]]}; + * must track their {@code [[TargetFunction]]} property for purposes of correctly implementing {@code [[HasInstance]]}; * see {@link ScriptFunction#isInstance(ScriptObject)}. */ class BoundScriptFunctionImpl extends ScriptFunctionImpl { diff --git a/nashorn/src/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk/nashorn/internal/objects/Global.java index f1993f7f542..66316d1dca4 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java @@ -351,6 +351,8 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { /** * Constructor + * + * @param context the context */ public Global(final Context context) { this.context = context; diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java index 5fa845d5141..b63e2f5b843 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java @@ -385,6 +385,7 @@ public final class NativeJava { public static Object extend(final Object self, final Object... types) { if(types == null || types.length == 0) { typeError("extend.expects.at.least.one.argument"); + throw new AssertionError(); //circumvent warning for types == null below } final Class[] stypes = new Class[types.length]; try { diff --git a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java index 3ca57ee8062..5f559fb0f6d 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java +++ b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java @@ -28,7 +28,7 @@ package jdk.nashorn.internal.objects; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import java.lang.invoke.MethodHandle; -import jdk.nashorn.internal.codegen.objects.FunctionObjectCreator; + import jdk.nashorn.internal.runtime.GlobalFunctions; import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.PropertyMap; @@ -94,14 +94,14 @@ public class ScriptFunctionImpl extends ScriptFunction { /** * Constructor called by (compiler) generated code for {@link ScriptObject}s. - * Code is generated by {@link FunctionObjectCreator} + * Code is generated by {@link jdk.nashorn.internal.codegen.CodeGenerator#newFunctionObject} * * @param data static function data * @param methodHandle handle for invocation * @param scope scope object * @param allocator instance constructor for function */ - public ScriptFunctionImpl(final ScriptFunctionData data, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle allocator) { + public ScriptFunctionImpl(final MethodHandle methodHandle, final ScriptFunctionData data, final ScriptObject scope, final MethodHandle allocator) { super(data, getMap(data.isStrict()), scope); // Set method handles in script data data.setMethodHandles(methodHandle, allocator); diff --git a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionTrampolineImpl.java b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionTrampolineImpl.java new file mode 100644 index 00000000000..22dd74a0149 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionTrampolineImpl.java @@ -0,0 +1,122 @@ +package jdk.nashorn.internal.objects; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + + +import static jdk.nashorn.internal.runtime.linker.Lookup.MH; + +import jdk.nashorn.internal.codegen.Compiler; +import jdk.nashorn.internal.codegen.FunctionSignature; +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.runtime.CodeInstaller; +import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.ScriptFunction; +import jdk.nashorn.internal.runtime.ScriptFunctionData; +import jdk.nashorn.internal.runtime.ScriptObject; + +/** + * A trampoline is a promise to compile a {@link ScriptFunction} later. It just looks like + * the call to the script function, but when invoked it will compile the script function + * (in a new compile unit) and invoke it + */ +public final class ScriptFunctionTrampolineImpl extends ScriptFunctionImpl { + + private CodeInstaller installer; + + /** Function node to lazily recompile when trampoline is hit */ + private FunctionNode functionNode; + + /** + * Constructor + * + * @param installer opaque code installer from context + * @param functionNode function node to lazily compile when trampoline is hit + * @param data {@link ScriptFunctionData} for function + * @param scope scope + * @param allocator allocator + */ + public ScriptFunctionTrampolineImpl(final CodeInstaller installer, final FunctionNode functionNode, final ScriptFunctionData data, final ScriptObject scope, final MethodHandle allocator) { + super(null, data, scope, allocator); + + this.installer = installer; + this.functionNode = functionNode; + + data.setMethodHandles(makeTrampoline(), allocator); + } + + private final MethodHandle makeTrampoline() { + final MethodType mt = + new FunctionSignature( + true, + functionNode.needsCallee(), + Type.OBJECT, + functionNode.getParameters().size()). + getMethodType(); + + return + MH.bindTo( + MH.asCollector( + findOwnMH( + "trampoline", + Object.class, + Object[].class), + Object[].class, + mt.parameterCount()), + this); + } + + private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { + return MH.findVirtual(MethodHandles.lookup(), ScriptFunctionTrampolineImpl.class, name, MH.type(rtype, types)); + } + + @Override + protected ScriptFunction makeBoundFunction(final ScriptFunctionData data) { + //prevent trampoline recompilation cycle if a function is bound before use + compile(); + return super.makeBoundFunction(data); + } + + private MethodHandle compile() { + final Compiler compiler = new Compiler(installer, functionNode); + if (!compiler.compile()) { + assert false : "compilation error in trampoline for " + functionNode.getName(); + return null; + } + + final Class clazz = compiler.install(); + /* compute function signature for lazy method. this can be done first after compilation, as only then do we know + * the final state about callees, scopes and specialized parameter types */ + final FunctionSignature signature = new FunctionSignature(true, functionNode.needsCallee(), Type.OBJECT, functionNode.getParameters().size()); + final MethodType mt = signature.getMethodType(); + + MethodHandle mh = MH.findStatic(MethodHandles.publicLookup(), clazz, functionNode.getName(), mt); + mh = MH.bindTo(mh, this); + + // now the invoker method looks like the one our superclass is expecting + resetInvoker(mh); + + return mh; + } + + @SuppressWarnings("unused") + private Object trampoline(final Object... args) { + /** Create a new compiler for the lazy node, using the same installation policy as the old one */ + + MethodHandle mh = compile(); + + // spread the array to invididual args of the correct type + mh = MH.asSpreader(mh, Object[].class, mh.type().parameterCount()); + + try { + //invoke the real method the trampoline points to. this only happens once + return mh.invoke(args); + } catch (final RuntimeException | Error e) { + throw e; + } catch (final Throwable t) { + throw new RuntimeException(t); + } + } +} diff --git a/nashorn/src/jdk/nashorn/internal/parser/Lexer.java b/nashorn/src/jdk/nashorn/internal/parser/Lexer.java index 5b890b350d5..2ae029730a9 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/Lexer.java +++ b/nashorn/src/jdk/nashorn/internal/parser/Lexer.java @@ -289,6 +289,11 @@ public class Lexer extends Scanner { add(type, start, position); } + /** + * Return the String of valid whitespace characters for regular + * expressions in JavaScript + * @return regexp whitespace string + */ public static String getWhitespaceRegExp() { return JAVASCRIPT_WHITESPACE_IN_REGEXP; } @@ -959,6 +964,8 @@ public class Lexer extends Scanner { // Add string token without editing. add(type, stringState.position, stringState.limit); break; + default: + break; } } else { /// Add string token without editing. diff --git a/nashorn/src/jdk/nashorn/internal/parser/Parser.java b/nashorn/src/jdk/nashorn/internal/parser/Parser.java index 4837c9a6554..1875ee02915 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java +++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java @@ -39,7 +39,6 @@ import static jdk.nashorn.internal.parser.TokenType.DECPREFIX; import static jdk.nashorn.internal.parser.TokenType.ELSE; import static jdk.nashorn.internal.parser.TokenType.EOF; import static jdk.nashorn.internal.parser.TokenType.EOL; -import static jdk.nashorn.internal.parser.TokenType.EXECSTRING; import static jdk.nashorn.internal.parser.TokenType.FINALLY; import static jdk.nashorn.internal.parser.TokenType.FUNCTION; import static jdk.nashorn.internal.parser.TokenType.IDENT; @@ -60,7 +59,9 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Stack; -import jdk.nashorn.internal.codegen.Compiler; + +import jdk.nashorn.internal.codegen.CompilerConstants; +import jdk.nashorn.internal.codegen.Namespace; import jdk.nashorn.internal.ir.AccessNode; import jdk.nashorn.internal.ir.BinaryNode; import jdk.nashorn.internal.ir.Block; @@ -97,8 +98,10 @@ import jdk.nashorn.internal.ir.VarNode; import jdk.nashorn.internal.ir.WhileNode; import jdk.nashorn.internal.ir.WithNode; import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.JSErrorType; import jdk.nashorn.internal.runtime.ParserException; +import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.ScriptingFunctions; /** @@ -106,49 +109,72 @@ import jdk.nashorn.internal.runtime.ScriptingFunctions; * */ public class Parser extends AbstractParser { - /** Code generator. */ - private final Compiler compiler; - /** Current context. */ private final Context context; /** Is scripting mode. */ private final boolean scripting; - /** Top level script being compiled. */ + /** Top level script being parsed. */ private FunctionNode script; - /** Current function being compiled. */ + /** Current function being parsed. */ private FunctionNode function; /** Current parsing block. */ private Block block; + /** Namespace for function names where not explicitly given */ + private final Namespace namespace; + /** - * Construct a parser. - * @param compiler Compiler state used to parse. + * Constructor + * + * @param context parser context + * @param source source to parse + * @param errors error manager */ - public Parser(final Compiler compiler) { - this(compiler, compiler.getContext()._strict); + public Parser(final Context context, final Source source, final ErrorManager errors) { + this(context, source, errors, context._strict); } /** * Construct a parser. - * @param compiler Compiler state used to parse. - * @param strict parser created with strict mode enabled. + * + * @param context parser context + * @param source source to parse + * @param errors error manager + * @param strict parser created with strict mode enabled. */ - public Parser(final Compiler compiler, final boolean strict) { - super(compiler.getSource(), compiler.getErrors(), strict); - - this.compiler = compiler; - this.context = compiler.getContext(); - this.scripting = this.context._scripting; + public Parser(final Context context, final Source source, final ErrorManager errors, final boolean strict) { + super(source, errors, strict); + this.context = context; + this.namespace = new Namespace(context.getNamespace()); + this.scripting = context._scripting; } /** - * Parse source content. - * @param scriptName file name for script - * @return Top level function (script). + * Execute parse and return the resulting function node. + * Errors will be thrown and the error manager will contain information + * if parsing should fail + * + * This is the default parse call, which will name the function node + * "runScript" {@link CompilerConstants#RUN_SCRIPT} + * + * @return function node resulting from successful parse + */ + public FunctionNode parse() { + return parse(RUN_SCRIPT.tag()); + } + + /** + * Execute parse and return the resulting function node. + * Errors will be thrown and the error manager will contain information + * if parsing should fail + * + * @param scriptName name for the script, given to the parsed FunctionNode + * + * @return function node resulting from successful parse */ public FunctionNode parse(final String scriptName) { try { @@ -257,11 +283,11 @@ loop: } sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.tag()); - final String name = compiler.uniqueName(sb.toString()); + final String name = namespace.uniqueName(sb.toString()); assert function != null || name.equals(RUN_SCRIPT.tag()) : "name = " + name;// must not rename runScript(). // Start new block. - final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), compiler, block, ident, name); + final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, block, ident, name); block = function = functionBlock; function.setStrictMode(isStrictMode); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java b/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java index 789eb2ce520..3ec272a8eb9 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java @@ -34,14 +34,21 @@ package jdk.nashorn.internal.runtime; * The compiler still retains most of the state around code emission * and management internally, so this is to avoid passing around any * logic that isn't directly related to installing a class + * @param owner class type for this code installer * */ -public interface CodeInstaller { +public interface CodeInstaller { + /** + * Return the owner for the CodeInstaller, e.g. a {@link Context} + * @return owner + */ + public T getOwner(); + /** * Install a class * @param className name of the class with / separation - * @param bytecode bytecode - * @return the installed class + * @param bytecode bytecode + * @return the installed class */ public Class install(final String className, final byte[] bytecode); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index d220e29948c..8a7507fd5e8 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -45,12 +45,16 @@ import java.security.CodeSource; import java.security.PrivilegedAction; import java.util.Locale; import java.util.TimeZone; + import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.util.CheckClassAdapter; import jdk.nashorn.internal.codegen.ClassEmitter; import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.codegen.Namespace; import jdk.nashorn.internal.codegen.objects.ObjectClassGenerator; +import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.debug.PrintVisitor; +import jdk.nashorn.internal.parser.Parser; import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; import jdk.nashorn.internal.runtime.options.KeyValueOption; @@ -63,6 +67,36 @@ import sun.reflect.Reflection; */ public final class Context { + /** + * ContextCodeInstaller that has the privilege of installing classes in the Context. + * Can only be instantiated from inside the context and is opaque to other classes + */ + public static class ContextCodeInstaller implements CodeInstaller { + private final Context context; + private final ScriptLoader loader; + private final CodeSource codeSource; + + private ContextCodeInstaller(final Context context, final ScriptLoader loader, final CodeSource codeSource) { + this.context = context; + this.loader = loader; + this.codeSource = codeSource; + } + + /** + * Return the context for this installer + * @return context + */ + @Override + public Context getOwner() { + return context; + } + + @Override + public Class install(final String className, final byte[] bytecode) { + return loader.installClass(className, bytecode, codeSource); + } + } + /** Is Context global debug mode enabled ? */ public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug"); @@ -751,6 +785,7 @@ public final class Context { /** * Initialize given global scope object. * + * @param global the global * @return the initialized global scope object. */ public ScriptObject initGlobal(final ScriptObject global) { @@ -877,22 +912,24 @@ public final class Context { } } - final Compiler compiler = Compiler.compiler(source, this, errMan, strict); - - if (!compiler.compile()) { + final FunctionNode functionNode = new Parser(this, source, errMan, strict).parse(); + if (errors.hasErrors() || _parse_only) { return null; } - final URL url = source.getURL(); + if (_print_lower_parse) { + getErr().println(new PrintVisitor(functionNode)); + } + + final URL url = source.getURL(); final ScriptLoader loader = _loader_per_compile ? createNewLoader() : scriptLoader; final CodeSource cs = url == null ? null : new CodeSource(url, (CodeSigner[])null); + final CodeInstaller installer = new ContextCodeInstaller(this, loader, cs); - script = compiler.install(new CodeInstaller() { - @Override - public Class install(final String className, final byte[] bytecode) { - return loader.installClass(className, bytecode, cs); - } - }); + final Compiler compiler = new Compiler(installer, functionNode, strict); + + compiler.compile(); + script = compiler.install(); if (global != null) { global.cacheClass(source, script); @@ -917,15 +954,14 @@ public final class Context { private ScriptObject newGlobalTrusted() { try { final Class clazz = Class.forName("jdk.nashorn.internal.objects.Global", true, scriptLoader); - final Constructor cstr = clazz.getConstructor(Context.class); + final Constructor cstr = clazz.getConstructor(Context.class); return (ScriptObject) cstr.newInstance(this); } catch (final Exception e) { printStackTrace(e); if (e instanceof RuntimeException) { throw (RuntimeException)e; - } else { - throw new RuntimeException(e); } + throw new RuntimeException(e); } } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java b/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java index dbbaeef6f2a..aa7f05d4dfe 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java @@ -73,8 +73,11 @@ public final class DebugLogger { * Get the output writer for the logger. Loggers always default to * stderr for output as they are used mainly to output debug info * + * Can be inherited so this should not be static. + * * @return print writer for log output. */ + @SuppressWarnings("static-method") public PrintWriter getOutputStream() { return Context.getCurrentErr(); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java index 7089d1f6872..2df165a153d 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java @@ -36,7 +36,7 @@ import jdk.nashorn.internal.codegen.objects.ObjectClassGenerator; public final class FindProperty { /** Object where search began. */ private final ScriptObject self; - ; + /** Object where search finish. */ private final ScriptObject prototype; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java index d0b24b2c80e..48525058a72 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java @@ -78,12 +78,14 @@ public abstract class ScriptFunction extends ScriptObject { /** * Constructor * - * @param name function name - * @param methodHandle method handle to function (if specializations are present, assumed to be most generic) - * @param map property map - * @param scope scope - * @param specs specialized version of this function - other method handles - * + * @param name function name + * @param methodHandle method handle to function (if specializations are present, assumed to be most generic) + * @param map property map + * @param scope scope + * @param specs specialized version of this function - other method handles + * @param strict is this a strict mode function? + * @param builtin is this a built in function? + * @param isConstructor is this a constructor? */ protected ScriptFunction( final String name, @@ -240,10 +242,17 @@ public abstract class ScriptFunction extends ScriptObject { * @param args additional arguments to bind to this function. Can be null or empty to not bind additional arguments. * @return a function with the specified self and parameters bound. */ - protected ScriptFunction makeBoundFunction(Object self, Object[] args) { + protected ScriptFunction makeBoundFunction(final Object self, final Object[] args) { return makeBoundFunction(data.makeBoundFunctionData(this, self, args)); } + /** + * Create a version of this function as in {@link ScriptFunction#makeBoundFunction(Object, Object[])}, + * but using a {@link ScriptFunctionData} for the bound data. + * + * @param boundData ScriptFuntionData for the bound function + * @return a function with the bindings performed according to the given data + */ protected abstract ScriptFunction makeBoundFunction(ScriptFunctionData boundData); @Override @@ -349,6 +358,15 @@ public abstract class ScriptFunction extends ScriptObject { return scope; } + /** + * Reset the invoker handle. This is used by trampolines for + * lazy code generation + * @param invoker new invoker + */ + protected void resetInvoker(final MethodHandle invoker) { + data.resetInvoker(invoker); + } + /** * Prototype getter for this ScriptFunction - follows the naming convention * used by Nasgen and the code generator diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java index 3366993cdf1..37e0246f486 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java @@ -101,11 +101,13 @@ public final class ScriptFunctionData { /** * Constructor + * * @param name the function name * @param methodHandle the method handle * @param specs array of specialized method handles * @param strict strict flag * @param builtin builtin flag + * @param isConstructor constructor flags */ public ScriptFunctionData(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict, final boolean builtin, final boolean isConstructor) { this(name, null, 0L, methodHandle, specs, strict, builtin, isConstructor); @@ -432,7 +434,7 @@ public final class ScriptFunctionData { * @param invoker the invoker handle * @param allocator the allocator handle */ - public void setMethodHandles(MethodHandle invoker, MethodHandle allocator) { + public void setMethodHandles(final MethodHandle invoker, final MethodHandle allocator) { // We can't make method handle fields final because they're not available during codegen // and they're set when first called, so we enforce set-once here. if (this.invoker == null) { @@ -442,6 +444,16 @@ public final class ScriptFunctionData { } } + /** + * Used by the trampoline. Must not be any wider than package + * private + * @param invoker new invoker + */ + void resetInvoker(final MethodHandle invoker) { + this.invoker = invoker; + this.constructor = null; //delay constructor composition + } + /** * Allocates an object using this function's allocator. * @return the object allocated using this function's allocator, or null if the function doesn't have an allocator. diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java index 523179ad820..2925c8da6b5 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java @@ -54,14 +54,21 @@ public final class ScriptingFunctions { /** Handle to implementation of {@link ScriptingFunctions#exec} - Nashorn extension */ public static final MethodHandle EXEC = findOwnMH("exec", Object.class, Object.class, Object.class, Object.class); - /** Names of special properties used by $EXEC API. */ - public static final String EXEC_NAME = "$EXEC"; - public static final String OUT_NAME = "$OUT"; - public static final String ERR_NAME = "$ERR"; - public static final String EXIT_NAME = "$EXIT"; + /** EXEC name - special property used by $EXEC API. */ + public static final String EXEC_NAME = "$EXEC"; + + /** OUT name - special property used by $EXEC API. */ + public static final String OUT_NAME = "$OUT"; + + /** ERR name - special property used by $EXEC API. */ + public static final String ERR_NAME = "$ERR"; + + /** EXIT name - special property used by $EXEC API. */ + public static final String EXIT_NAME = "$EXIT"; /** Names of special properties used by $ENV API. */ public static final String ENV_NAME = "$ENV"; + private static final String PWD_NAME = "PWD"; private ScriptingFunctions() { @@ -114,8 +121,11 @@ public final class ScriptingFunctions { * * @param self self reference * @param string string to execute + * @param input * * @return output string from the request + * @throws IOException + * @throws InterruptedException */ public static Object exec(final Object self, final Object string, final Object input) throws IOException, InterruptedException { // Current global is need to fetch additional inputs and for additional results. diff --git a/nashorn/src/jdk/nashorn/tools/Shell.java b/nashorn/src/jdk/nashorn/tools/Shell.java index 124e83c70c4..d353c5f969e 100644 --- a/nashorn/src/jdk/nashorn/tools/Shell.java +++ b/nashorn/src/jdk/nashorn/tools/Shell.java @@ -41,6 +41,8 @@ import java.util.Locale; import java.util.ResourceBundle; import jdk.nashorn.api.scripting.NashornException; import jdk.nashorn.internal.codegen.Compiler; +import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.parser.Parser; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.ScriptFunction; @@ -241,13 +243,14 @@ public class Shell { // For each file on the command line. for (final String fileName : files) { - final File file = new File(fileName); - final Source source = new Source(fileName, file); - final Compiler compiler = Compiler.compiler(source, context); - compiler.compile(); + final FunctionNode functionNode = new Parser(context, new Source(fileName, new File(fileName)), errors).parse(); + if (errors.getNumberOfErrors() != 0) { return COMPILATION_ERROR; } + + //null - pass no code installer - this is compile only + new Compiler(context, functionNode).compile(); } } finally { context.getOut().flush(); @@ -282,7 +285,7 @@ public class Shell { // For each file on the command line. for (final String fileName : files) { final File file = new File(fileName); - ScriptFunction script = context.compileScript(new Source(fileName, file.toURI().toURL()), global); + final ScriptFunction script = context.compileScript(new Source(fileName, file.toURI().toURL()), global); if (script == null || errors.getNumberOfErrors() != 0) { return COMPILATION_ERROR; } diff --git a/nashorn/test/script/trusted/JDK-8006529.js b/nashorn/test/script/trusted/JDK-8006529.js index f748649f727..0ad1db31795 100644 --- a/nashorn/test/script/trusted/JDK-8006529.js +++ b/nashorn/test/script/trusted/JDK-8006529.js @@ -39,17 +39,15 @@ * and FunctionNode because of package-access check and so reflective calls. */ +var Parser = Java.type("jdk.nashorn.internal.parser.Parser") var Compiler = Java.type("jdk.nashorn.internal.codegen.Compiler") var Context = Java.type("jdk.nashorn.internal.runtime.Context") var Source = Java.type("jdk.nashorn.internal.runtime.Source") var FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode") // Compiler class methods and fields - -// Compiler.compile(Source, Context) -var compilerMethod = Compiler.class.getMethod("compiler", Source.class, Context.class); -// Compiler.compile() -var compileMethod = Compiler.class.getMethod("compile"); +var parseMethod = Parser.class.getMethod("parse"); +var compileMethod = Compiler.class.getMethod("compile"); // NOTE: private field. But this is a trusted test! // Compiler.functionNode @@ -90,10 +88,14 @@ function getFirstFunction(functionNode) { // source code, returns a jdk.nashorn.internal.ir.FunctionNode object // representing it. function compile(source) { - var compiler = compilerMethod.invoke(null, - new Source("", source), Context.getContext()) - compileMethod.invoke(compiler); - return getScriptNode(compiler) + var source = new Source("", source); + var parser = new Parser(Context.getContext(), source, null); + var func = parseMethod.invoke(parser); + var compiler = new Compiler(Context.getContext(), func); + + compileMethod.invoke(compiler); + + return getScriptNode(compiler); }; var allAssertions = (function() { diff --git a/nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java b/nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java index 27a637ea78a..08e20df3aa1 100644 --- a/nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java +++ b/nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java @@ -156,10 +156,7 @@ public class ParserTest { Context.setGlobal(global); } final Source source = new Source(file.getAbsolutePath(), buffer); - final Compiler compiler = Compiler.compiler(source, context, errors, context._strict); - - final Parser parser = new Parser(compiler); - parser.parse(CompilerConstants.RUN_SCRIPT.tag()); + new Parser(context, source, errors).parse(); if (errors.getNumberOfErrors() > 0) { log("Parse failed: " + file.getAbsolutePath()); failed++; diff --git a/nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java b/nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java index 58557374e91..4ea77ac44a0 100644 --- a/nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java +++ b/nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java @@ -126,6 +126,7 @@ public final class SharedContextEvaluator implements ScriptEvaluator { } final File file = new File(fileName); ScriptFunction script = context.compileScript(new Source(fileName, file.toURI().toURL()), global); + if (script == null || errors.getNumberOfErrors() != 0) { return COMPILATION_ERROR; } From 82f8cef55c565ed46dc5de964478f4c0405692d1 Mon Sep 17 00:00:00 2001 From: Attila Szegedi Date: Thu, 14 Feb 2013 13:22:26 +0100 Subject: [PATCH 147/311] 8008085: Integrate Dynalink source code into Nashorn codebase Reviewed-by: jlaskey, lagergren, sundar --- nashorn/THIRD_PARTY_README | 31 + nashorn/make/build.xml | 39 +- nashorn/make/nbproject/project.xml | 1 - nashorn/make/project.properties | 15 +- .../internal/dynalink/CallSiteDescriptor.java | 175 +++++ .../internal/dynalink/ChainedCallSite.java | 212 ++++++ .../dynalink/DefaultBootstrapper.java | 144 ++++ .../jdk/internal/dynalink/DynamicLinker.java | 281 +++++++ .../dynalink/DynamicLinkerFactory.java | 311 ++++++++ .../dynalink/MonomorphicCallSite.java | 116 +++ .../NoSuchDynamicMethodException.java | 103 +++ .../internal/dynalink/RelinkableCallSite.java | 148 ++++ .../dynalink/beans/AbstractJavaLinker.java | 690 ++++++++++++++++++ .../beans/AccessibleMembersLookup.java | 262 +++++++ .../beans/ApplicableOverloadedMethods.java | 221 ++++++ .../dynalink/beans/BeanIntrospector.java | 104 +++ .../internal/dynalink/beans/BeanLinker.java | 493 +++++++++++++ .../internal/dynalink/beans/BeansLinker.java | 180 +++++ .../beans/CheckRestrictedPackage.java | 109 +++ .../beans/CheckRestrictedPackageInternal.java | 252 +++++++ .../internal/dynalink/beans/ClassLinker.java | 110 +++ .../internal/dynalink/beans/ClassString.java | 209 ++++++ .../dynalink/beans/DynamicMethod.java | 169 +++++ .../dynalink/beans/DynamicMethodLinker.java | 130 ++++ .../dynalink/beans/FacetIntrospector.java | 188 +++++ .../beans/GuardedInvocationComponent.java | 251 +++++++ .../dynalink/beans/MaximallySpecific.java | 211 ++++++ .../beans/OverloadedDynamicMethod.java | 313 ++++++++ .../dynalink/beans/OverloadedMethod.java | 266 +++++++ .../beans/RestrictedPackageTester.java | 113 +++ .../dynalink/beans/SimpleDynamicMethod.java | 241 ++++++ .../internal/dynalink/beans/StaticClass.java | 138 ++++ .../beans/StaticClassIntrospector.java | 117 +++ .../dynalink/beans/StaticClassLinker.java | 204 ++++++ .../dynalink/beans/messages.properties | 25 + .../jdk/internal/dynalink/beans/package.html | 86 +++ .../dynalink/linker/ConversionComparator.java | 114 +++ .../dynalink/linker/GuardedInvocation.java | 315 ++++++++ .../linker/GuardingDynamicLinker.java | 112 +++ .../linker/GuardingTypeConverterFactory.java | 114 +++ .../internal/dynalink/linker/LinkRequest.java | 149 ++++ .../dynalink/linker/LinkerServices.java | 165 +++++ .../TypeBasedGuardingDynamicLinker.java | 102 +++ .../jdk/internal/dynalink/linker/package.html | 87 +++ .../src/jdk/internal/dynalink/package.html | 93 +++ .../support/AbstractCallSiteDescriptor.java | 186 +++++ .../support/AbstractRelinkableCallSite.java | 118 +++ .../dynalink/support/AutoDiscovery.java | 134 ++++ .../internal/dynalink/support/Backport.java | 99 +++ .../support/BottomGuardingDynamicLinker.java | 116 +++ .../support/CallSiteDescriptorFactory.java | 265 +++++++ .../internal/dynalink/support/ClassMap.java | 177 +++++ .../CompositeGuardingDynamicLinker.java | 132 ++++ ...mpositeTypeBasedGuardingDynamicLinker.java | 226 ++++++ .../support/DefaultCallSiteDescriptor.java | 135 ++++ .../jdk/internal/dynalink/support/Guards.java | 360 +++++++++ .../dynalink/support/LinkRequestImpl.java | 143 ++++ .../dynalink/support/LinkerServicesImpl.java | 141 ++++ .../jdk/internal/dynalink/support/Lookup.java | 361 +++++++++ .../support/LookupCallSiteDescriptor.java | 118 +++ .../internal/dynalink/support/NameCodec.java | 218 ++++++ .../support/NamedDynCallSiteDescriptor.java | 118 +++ .../RuntimeContextLinkRequestImpl.java | 142 ++++ .../support/TypeConverterFactory.java | 320 ++++++++ .../dynalink/support/TypeUtilities.java | 442 +++++++++++ .../support/UnnamedDynCallSiteDescriptor.java | 127 ++++ .../dynalink/support/messages.properties | 86 +++ .../internal/dynalink/support/package.html | 89 +++ .../nashorn/internal/codegen/Compiler.java | 3 +- .../internal/codegen/MethodEmitter.java | 2 +- .../nashorn/internal/codegen/WeighNodes.java | 1 - .../src/jdk/nashorn/internal/ir/Block.java | 1 - .../src/jdk/nashorn/internal/ir/CallNode.java | 1 - nashorn/src/jdk/nashorn/internal/ir/Node.java | 1 - .../src/jdk/nashorn/internal/ir/Symbol.java | 1 - .../jdk/nashorn/internal/objects/Global.java | 4 +- .../internal/objects/NativeBoolean.java | 4 +- .../internal/objects/NativeJSAdapter.java | 6 +- .../nashorn/internal/objects/NativeJava.java | 4 +- .../internal/objects/NativeJavaImporter.java | 8 +- .../internal/objects/NativeNumber.java | 4 +- .../internal/objects/NativeString.java | 6 +- .../jdk/nashorn/internal/parser/Lexer.java | 2 +- .../internal/runtime/GlobalObject.java | 4 +- .../jdk/nashorn/internal/runtime/JSType.java | 2 +- .../internal/runtime/NativeJavaPackage.java | 8 +- .../internal/runtime/ScriptFunction.java | 6 +- .../internal/runtime/ScriptLoader.java | 6 + .../internal/runtime/ScriptObject.java | 8 +- .../internal/runtime/ScriptRuntime.java | 2 +- .../internal/runtime/SetMethodCreator.java | 7 +- .../internal/runtime/StructureLoader.java | 2 - .../nashorn/internal/runtime/Undefined.java | 8 +- .../nashorn/internal/runtime/WithObject.java | 8 +- .../internal/runtime/linker/Bootstrap.java | 12 +- .../runtime/linker/JSObjectLinker.java | 12 +- .../runtime/linker/JavaAdapterFactory.java | 4 +- .../linker/JavaArgumentConverters.java | 2 +- .../runtime/linker/LinkerCallSite.java | 6 +- .../runtime/linker/NashornBottomLinker.java | 12 +- .../linker/NashornCallSiteDescriptor.java | 6 +- .../runtime/linker/NashornLinker.java | 19 +- .../linker/NashornPrimitiveLinker.java | 16 +- .../linker/NashornStaticClassLinker.java | 18 +- .../runtime/linker/PrimitiveLookup.java | 10 +- .../internal/runtime/options/Options.java | 1 - .../test/script/sandbox/nashorninternals.js | 4 + .../api/scripting/ScriptEngineTest.java | 2 +- .../nashorn/internal/runtime/ContextTest.java | 1 - .../nashorn/internal/runtime/JSTypeTest.java | 2 +- 110 files changed, 12230 insertions(+), 168 deletions(-) create mode 100644 nashorn/src/jdk/internal/dynalink/CallSiteDescriptor.java create mode 100644 nashorn/src/jdk/internal/dynalink/ChainedCallSite.java create mode 100644 nashorn/src/jdk/internal/dynalink/DefaultBootstrapper.java create mode 100644 nashorn/src/jdk/internal/dynalink/DynamicLinker.java create mode 100644 nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java create mode 100644 nashorn/src/jdk/internal/dynalink/MonomorphicCallSite.java create mode 100644 nashorn/src/jdk/internal/dynalink/NoSuchDynamicMethodException.java create mode 100644 nashorn/src/jdk/internal/dynalink/RelinkableCallSite.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/AccessibleMembersLookup.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/BeanIntrospector.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/CheckRestrictedPackage.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/CheckRestrictedPackageInternal.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/ClassLinker.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/ClassString.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/DynamicMethod.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/GuardedInvocationComponent.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/MaximallySpecific.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/RestrictedPackageTester.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/StaticClass.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java create mode 100644 nashorn/src/jdk/internal/dynalink/beans/messages.properties create mode 100644 nashorn/src/jdk/internal/dynalink/beans/package.html create mode 100644 nashorn/src/jdk/internal/dynalink/linker/ConversionComparator.java create mode 100644 nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java create mode 100644 nashorn/src/jdk/internal/dynalink/linker/GuardingDynamicLinker.java create mode 100644 nashorn/src/jdk/internal/dynalink/linker/GuardingTypeConverterFactory.java create mode 100644 nashorn/src/jdk/internal/dynalink/linker/LinkRequest.java create mode 100644 nashorn/src/jdk/internal/dynalink/linker/LinkerServices.java create mode 100644 nashorn/src/jdk/internal/dynalink/linker/TypeBasedGuardingDynamicLinker.java create mode 100644 nashorn/src/jdk/internal/dynalink/linker/package.html create mode 100644 nashorn/src/jdk/internal/dynalink/package.html create mode 100644 nashorn/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/AbstractRelinkableCallSite.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/AutoDiscovery.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/Backport.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/BottomGuardingDynamicLinker.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/CallSiteDescriptorFactory.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/ClassMap.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/CompositeGuardingDynamicLinker.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/CompositeTypeBasedGuardingDynamicLinker.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/DefaultCallSiteDescriptor.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/Guards.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/LinkRequestImpl.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/LinkerServicesImpl.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/Lookup.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/LookupCallSiteDescriptor.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/NameCodec.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/NamedDynCallSiteDescriptor.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/RuntimeContextLinkRequestImpl.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/TypeUtilities.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/UnnamedDynCallSiteDescriptor.java create mode 100644 nashorn/src/jdk/internal/dynalink/support/messages.properties create mode 100644 nashorn/src/jdk/internal/dynalink/support/package.html diff --git a/nashorn/THIRD_PARTY_README b/nashorn/THIRD_PARTY_README index 44318349aed..546280f129c 100644 --- a/nashorn/THIRD_PARTY_README +++ b/nashorn/THIRD_PARTY_README @@ -67,3 +67,34 @@ 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. --- end of LICENSE --- + +%% This notice is provided with respect to Dynalink library which is included +with the Nashorn technology. + +--- begin of LICENSE --- +Copyright (c) 2009-2013, Attila Szegedi + +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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER +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. +--- end of LICENSE --- diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml index d5264cc70be..3043b1890e7 100644 --- a/nashorn/make/build.xml +++ b/nashorn/make/build.xml @@ -54,19 +54,11 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + ${line.separator} @@ -134,7 +106,6 @@ - @@ -152,12 +123,10 @@ - - diff --git a/nashorn/make/nbproject/project.xml b/nashorn/make/nbproject/project.xml index bde88f6d66c..828dc29d16b 100644 --- a/nashorn/make/nbproject/project.xml +++ b/nashorn/make/nbproject/project.xml @@ -164,7 +164,6 @@ ../src - ../build/dynalink/dynalink.jar 1.7 diff --git a/nashorn/make/project.properties b/nashorn/make/project.properties index 544b1e91388..3e1bbd266d4 100644 --- a/nashorn/make/project.properties +++ b/nashorn/make/project.properties @@ -87,23 +87,10 @@ testng.listeners=\ org.testng.reporters.EmailableReporter, \ jdk.nashorn.internal.test.framework.JSJUnitReportReporter -# Define the version of Dynalink that is used. Version types are either -# 'snapshot' or 'release'. When it is 'snapshot', the version must have -# "-SNAPSHOT" suffix and the jar version will have a timestamp in it. When -# it's 'release', the version has no suffix, and the jar version is -# identical to version - fun with Maven central. -dynalink.version=0.5-SNAPSHOT -dynalink.version.type=snapshot -dynalink.jar.version=0.5-20130109.113843-12 -dynalink.dir.name=dynalink -dynalink.dir=build/${dynalink.dir.name} -dynalink.jar=${dynalink.dir}/dynalink.jar - javac.debug=true javac.encoding=ascii javac.classpath=\ - ${build.classes.dir}:\ - ${dynalink.jar} + ${build.classes.dir} javac.test.classpath=\ ${build.classes.dir}:\ ${build.test.classes.dir}:\ diff --git a/nashorn/src/jdk/internal/dynalink/CallSiteDescriptor.java b/nashorn/src/jdk/internal/dynalink/CallSiteDescriptor.java new file mode 100644 index 00000000000..bb2a09f273c --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/CallSiteDescriptor.java @@ -0,0 +1,175 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink; + +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; + + +/** + * An immutable descriptor of a call site. It is an immutable object that contains all the information about a call + * site: the class performing the lookups, the name of the method being invoked, and the method signature. The library + * has a default {@link CallSiteDescriptorFactory} for descriptors that you can use, or you can create your own + * descriptor classes, especially if you need to add further information (values passed in additional parameters to the + * bootstrap method) to them. Call site descriptors are used in this library in place of passing a real call site to + * guarding linkers so they aren't tempted to directly manipulate the call sites. The constructors of built-in + * {@link RelinkableCallSite} implementations all need a call site descriptor. Even if you create your own call site + * descriptors consider using {@link CallSiteDescriptorFactory#tokenizeName(String)} in your implementation. + * + * @author Attila Szegedi + */ +public interface CallSiteDescriptor { + /** + * The index of the name token that will carry the operation scheme prefix (usually, "dyn"). + */ + public static final int SCHEME = 0; + /** + * The index of the name token that will usually carry the operation name. + */ + + public static final int OPERATOR=1; + /** + * The index of the name token that will usually carry a name of an operand (of a property, method, etc.) + */ + + public static final int NAME_OPERAND=2; + + /** + * Character used to delimit tokens in an call site name. + */ + public static final String TOKEN_DELIMITER = ":"; + + /** + * Character used to delimit operation names in a composite operation specification. + */ + public static final String OPERATOR_DELIMITER = "|"; + + /** + * Returns the number of tokens in the name of the method at the call site. Method names are tokenized with the + * colon ":" character, i.e. "dyn:getProp:color" would be the name used to describe a method that retrieves the + * property named "color" on the object it is invoked on. + * @return the number of tokens in the name of the method at the call site. + */ + public int getNameTokenCount(); + + /** + * Returns the ith token in the method name at the call site. Method names are tokenized with the + * colon ":" character. + * @param i the index of the token. Must be between 0 (inclusive) and {@link #getNameTokenCount()} (exclusive) + * @throws IllegalArgumentException if the index is outside the allowed range. + * @return the ith token in the method name at the call site. The returned strings are interned. + */ + public String getNameToken(int i); + + /** + * Returns the name of the method at the call site. Note that the object internally only stores the tokenized name, + * and has to reconstruct the full name from tokens on each invocation. + * @return the name of the method at the call site. + */ + public String getName(); + + /** + * The type of the method at the call site. + * + * @return type of the method at the call site. + */ + public MethodType getMethodType(); + + /** + * Returns the lookup passed to the bootstrap method. + * @return the lookup passed to the bootstrap method. + */ + public Lookup getLookup(); + + /** + * Creates a new call site descriptor from this descriptor, which is identical to this, except it changes the method + * type. + * + * @param newMethodType the new method type + * @return a new call site descriptor, with the method type changed. + */ + public CallSiteDescriptor changeMethodType(MethodType newMethodType); + +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java b/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java new file mode 100644 index 00000000000..feb03e28bae --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java @@ -0,0 +1,212 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.concurrent.atomic.AtomicReference; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.support.AbstractRelinkableCallSite; + + +/** + * A relinkable call site that maintains a chain of linked method handles. In the default implementation, up to 8 method + * handles can be chained, cascading from one to the other through + * {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}. When this call site has to link a new + * method handle and the length of the chain is already at the maximum, it will throw away the oldest method handle. + * Switchpoint-invalidated handles in the chain are removed eagerly (on each linking request, and whenever a + * switchpoint-invalidated method handle is traversed during invocation). There is currently no profiling + * attached to the handles in the chain, so they are never reordered based on usage; the most recently linked method + * handle is always at the start of the chain. + */ +public class ChainedCallSite extends AbstractRelinkableCallSite { + private final AtomicReference> invocations = new AtomicReference<>(); + + /** + * Creates a new chained call site. + * @param descriptor the descriptor for the call site. + */ + public ChainedCallSite(CallSiteDescriptor descriptor) { + super(descriptor); + } + + /** + * The maximum number of method handles in the chain. Defaults to 8. You can override it in a subclass if you need + * to change the value. If your override returns a value less than 1, the code will break. + * @return the maximum number of method handles in the chain. + */ + @SuppressWarnings("static-method") + protected int getMaxChainLength() { + return 8; + } + + @Override + public void relink(GuardedInvocation guardedInvocation, MethodHandle fallback) { + relinkInternal(guardedInvocation, fallback, false); + } + + @Override + public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle fallback) { + relinkInternal(guardedInvocation, fallback, true); + } + + private MethodHandle relinkInternal(GuardedInvocation invocation, MethodHandle relink, boolean reset) { + final LinkedList currentInvocations = invocations.get(); + @SuppressWarnings({ "unchecked", "rawtypes" }) + final LinkedList newInvocations = + currentInvocations == null || reset ? new LinkedList<>() : (LinkedList)currentInvocations.clone(); + + // First, prune the chain of invalidated switchpoints. + for(Iterator it = newInvocations.iterator(); it.hasNext();) { + if(it.next().hasBeenInvalidated()) { + it.remove(); + } + } + + // prune() is allowed to invoke this method with invocation == null meaning we're just pruning the chain and not + // adding any new invocations to it. + if(invocation != null) { + // Remove oldest entry if we're at max length + if(newInvocations.size() == getMaxChainLength()) { + newInvocations.removeFirst(); + } + newInvocations.addLast(invocation); + } + + // prune-and-invoke is used as the fallback for invalidated switchpoints. If a switchpoint gets invalidated, we + // rebuild the chain and get rid of all invalidated switchpoints instead of letting them linger. + final MethodHandle pruneAndInvoke = makePruneAndInvokeMethod(relink); + + // Fold the new chain + MethodHandle target = relink; + for(GuardedInvocation inv: newInvocations) { + target = inv.compose(pruneAndInvoke, target); + } + + // If nobody else updated the call site while we were rebuilding the chain, set the target to our chain. In case + // we lost the race for multithreaded update, just do nothing. Either the other thread installed the same thing + // we wanted to install, or otherwise, we'll be asked to relink again. + if(invocations.compareAndSet(currentInvocations, newInvocations)) { + setTarget(target); + } + return target; + } + + /** + * Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that + * chain. + * @param relink the ultimate fallback for the chain (the {@code DynamicLinker}'s relink). + * @return a method handle for prune-and-invoke + */ + private MethodHandle makePruneAndInvokeMethod(MethodHandle relink) { + // Bind prune to (this, relink) + final MethodHandle boundPrune = MethodHandles.insertArguments(PRUNE, 0, this, relink); + // Make it ignore all incoming arguments + final MethodHandle ignoreArgsPrune = MethodHandles.dropArguments(boundPrune, 0, type().parameterList()); + // Invoke prune, then invoke the call site target with original arguments + return MethodHandles.foldArguments(MethodHandles.exactInvoker(type()), ignoreArgsPrune); + } + + @SuppressWarnings("unused") + private MethodHandle prune(MethodHandle relink) { + return relinkInternal(null, relink, false); + } + + private static final MethodHandle PRUNE; + static { + try { + PRUNE = MethodHandles.lookup().findSpecial(ChainedCallSite.class, "prune", MethodType.methodType( + MethodHandle.class, MethodHandle.class), ChainedCallSite.class); + // NOTE: using two catch blocks so we don't introduce a reference to 1.7 ReflectiveOperationException, allowing + // Dynalink to be used on 1.6 JVMs with Remi's backport library. + } catch(IllegalAccessException e) { + throw new AssertionError(e.getMessage(), e); // Can not happen + } catch(NoSuchMethodException e) { + throw new AssertionError(e.getMessage(), e); // Can not happen + } + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/DefaultBootstrapper.java b/nashorn/src/jdk/internal/dynalink/DefaultBootstrapper.java new file mode 100644 index 00000000000..d5be13478ab --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/DefaultBootstrapper.java @@ -0,0 +1,144 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink; + +import java.lang.invoke.CallSite; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; + + +/** + * A convenience default bootstrapper that exposes static bootstrap methods which language runtimes that need the very + * default behavior can use with minimal setup. When first referenced, it will create a dynamic linker with default + * settings for the {@link DynamicLinkerFactory}, and its bootstrap methods will create {@link MonomorphicCallSite} for + * all call sites. It has two bootstrap methods: one creates call sites that use the + * {@link MethodHandles#publicLookup()} as the lookup for all call sites and disregard the one passed in as the caller, + * and one that just uses the passed caller as the lookup scope. Using the public lookup one is advised if your language + * runtime has no concept of interacting with Java visibility scopes, as it results in a more lightweight runtime + * information. + * + * @author Attila Szegedi + */ +public class DefaultBootstrapper { + private static final DynamicLinker dynamicLinker = new DynamicLinkerFactory().createLinker(); + + private DefaultBootstrapper() { + } + + /** + * Use this method as your bootstrap method (see the documentation of the java.lang.invoke package for how to do + * this). In case your language runtime doesn't have a concept of interaction with Java access scopes, you might + * want to consider using + * {@link #publicBootstrap(java.lang.invoke.MethodHandles.Lookup, String, MethodType)} instead. + * + * @param caller the caller's lookup + * @param name the name of the method at the call site + * @param type the method signature at the call site + * @return a new {@link MonomorphicCallSite} linked with the default dynamic linker. + */ + public static CallSite bootstrap(MethodHandles.Lookup caller, String name, MethodType type) { + return bootstrapInternal(caller, name, type); + } + + /** + * Use this method as your bootstrap method (see the documentation of the java.lang.invoke package for how to do + * this) when your language runtime doesn't have a concept of interaction with Java access scopes. If you need to + * preserve the different caller Lookup objects in the call sites, use + * {@link #bootstrap(java.lang.invoke.MethodHandles.Lookup, String, MethodType)} instead + * + * @param caller the caller's lookup. It is ignored as the call sites will be created with + * {@link MethodHandles#publicLookup()} instead. + * @param name the name of the method at the call site + * @param type the method signature at the call site + * @return a new {@link MonomorphicCallSite} linked with the default dynamic linker. + */ + public static CallSite publicBootstrap(@SuppressWarnings("unused") MethodHandles.Lookup caller, String name, MethodType type) { + return bootstrapInternal(MethodHandles.publicLookup(), name, type); + } + + private static CallSite bootstrapInternal(MethodHandles.Lookup caller, String name, MethodType type) { + return dynamicLinker.link(new MonomorphicCallSite(CallSiteDescriptorFactory.create(caller, name, type))); + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/DynamicLinker.java b/nashorn/src/jdk/internal/dynalink/DynamicLinker.java new file mode 100644 index 00000000000..ccdfa4fb9e2 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/DynamicLinker.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. 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.MutableCallSite; +import java.util.List; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; +import jdk.internal.dynalink.support.LinkRequestImpl; +import jdk.internal.dynalink.support.Lookup; +import jdk.internal.dynalink.support.RuntimeContextLinkRequestImpl; + + +/** + * The linker for {@link RelinkableCallSite} objects. Users of it (scripting frameworks and language runtimes) have to + * create a linker using the {@link DynamicLinkerFactory} and invoke its link method from the invokedynamic bootstrap + * methods to set the target of all the call sites in the code they generate. Usual usage would be to create one class + * per language runtime to contain one linker instance as: + * + *
      + * class MyLanguageRuntime {
      + *     private static final GuardingDynamicLinker myLanguageLinker = new MyLanguageLinker();
      + *     private static final DynamicLinker dynamicLinker = createDynamicLinker();
      + *
      + *     private static DynamicLinker createDynamicLinker() {
      + *         final DynamicLinkerFactory factory = new DynamicLinkerFactory();
      + *         factory.setPrioritizedLinker(myLanguageLinker);
      + *         return factory.createLinker();
      + *     }
      + *
      + *     public static CallSite bootstrap(MethodHandles.Lookup caller, String name, MethodType type) {
      + *         return dynamicLinker.link(new MonomorphicCallSite(CallSiteDescriptorFactory.create(lookup, name, type)));
      + *     }
      + * }
      + * 
      + * + * Note how there are three components you will need to provide here: + *
        + *
      • You're expected to provide a {@link GuardingDynamicLinker} for your own language. If your runtime doesn't + * have its own language and/or object model (i.e. it's a generic scripting shell), you don't need to implement a + * dynamic linker; you would simply not invoke the {@code setPrioritizedLinker} method on the factory, or even better, + * simply use {@link DefaultBootstrapper}.
      • + *
      • The performance of the programs can depend on your choice of the class to represent call sites. The above + * example used {@link MonomorphicCallSite}, but you might want to use {@link ChainedCallSite} instead. You'll need to + * experiment and decide what fits your language runtime the best. You can subclass either of these or roll your own if + * you need to.
      • + *
      • You also need to provide {@link CallSiteDescriptor}s to your call sites. They are immutable objects that contain + * all the information about the call site: the class performing the lookups, the name of the method being invoked, and + * the method signature. The library has a default {@link CallSiteDescriptorFactory} for descriptors that you can use, + * or you can create your own descriptor classes, especially if you need to add further information (values passed in + * additional parameters to the bootstrap method) to them.
      • + *
      + * + * @author Attila Szegedi + */ +public class DynamicLinker { + + private static final String CLASS_NAME = DynamicLinker.class.getName(); + private static final String RELINK_METHOD_NAME = "relink"; + + private final LinkerServices linkerServices; + private final int runtimeContextArgCount; + private final boolean syncOnRelink; + private final int unstableRelinkThreshold; + + /** + * Creates a new dynamic linker. + * + * @param linkerServices the linkerServices used by the linker, created by the factory. + * @param runtimeContextArgCount see {@link DynamicLinkerFactory#setRuntimeContextArgCount(int)} + */ + DynamicLinker(LinkerServices linkerServices, int runtimeContextArgCount, boolean syncOnRelink, + int unstableRelinkThreshold) { + if(runtimeContextArgCount < 0) { + throw new IllegalArgumentException("runtimeContextArgCount < 0"); + } + if(unstableRelinkThreshold < 0) { + throw new IllegalArgumentException("unstableRelinkThreshold < 0"); + } + this.runtimeContextArgCount = runtimeContextArgCount; + this.linkerServices = linkerServices; + this.syncOnRelink = syncOnRelink; + this.unstableRelinkThreshold = unstableRelinkThreshold; + } + + /** + * Links an invokedynamic call site. It will install a method handle into the call site that invokes the relinking + * mechanism of this linker. Next time the call site is invoked, it will be linked for the actual arguments it was + * invoked with. + * + * @param callSite the call site to link. + * @return the callSite, for easy call chaining. + */ + public T link(final T callSite) { + callSite.initialize(createRelinkAndInvokeMethod(callSite, 0)); + return callSite; + } + + /** + * Returns the object representing the lower level linker services of this class that are normally exposed to + * individual language-specific linkers. While as a user of this class you normally only care about the + * {@link #link(RelinkableCallSite)} method, in certain circumstances you might want to use the lower level services + * directly; either to lookup specific method handles, to access the type converters, and so on. + * @return the object representing the linker services of this class. + */ + public LinkerServices getLinkerServices() { + return linkerServices; + } + + private static final MethodHandle RELINK = Lookup.findOwnSpecial(MethodHandles.lookup(), RELINK_METHOD_NAME, + MethodHandle.class, RelinkableCallSite.class, int.class, Object[].class); + + private MethodHandle createRelinkAndInvokeMethod(final RelinkableCallSite callSite, int relinkCount) { + // Make a bound MH of invoke() for this linker and call site + final MethodHandle boundRelinker = MethodHandles.insertArguments(RELINK, 0, this, callSite, Integer.valueOf( + relinkCount)); + // Make a MH that gathers all arguments to the invocation into an Object[] + final MethodType type = callSite.getDescriptor().getMethodType(); + final MethodHandle collectingRelinker = boundRelinker.asCollector(Object[].class, type.parameterCount()); + return MethodHandles.foldArguments(MethodHandles.exactInvoker(type), collectingRelinker.asType( + type.changeReturnType(MethodHandle.class))); + } + + /** + * Relinks a call site conforming to the invocation arguments. + * + * @param callSite the call site itself + * @param arguments arguments to the invocation + * @return return the method handle for the invocation + * @throws Exception rethrows any exception thrown by the linkers + */ + @SuppressWarnings("unused") + private MethodHandle relink(RelinkableCallSite callSite, int relinkCount, Object... arguments) throws Exception { + final CallSiteDescriptor callSiteDescriptor = callSite.getDescriptor(); + final boolean unstableDetectionEnabled = unstableRelinkThreshold > 0; + final boolean callSiteUnstable = unstableDetectionEnabled && relinkCount >= unstableRelinkThreshold; + final LinkRequest linkRequest = + runtimeContextArgCount == 0 ? new LinkRequestImpl(callSiteDescriptor, callSiteUnstable, arguments) + : new RuntimeContextLinkRequestImpl(callSiteDescriptor, callSiteUnstable, arguments, + runtimeContextArgCount); + + // Find a suitable method handle with a guard + GuardedInvocation guardedInvocation = linkerServices.getGuardedInvocation(linkRequest); + + // None found - throw an exception + if(guardedInvocation == null) { + throw new NoSuchDynamicMethodException(callSiteDescriptor.toString()); + } + + // If our call sites have a runtime context, and the linker produced a context-stripped invocation, adapt the + // produced invocation into contextual invocation (by dropping the context...) + if(runtimeContextArgCount > 0) { + final MethodType origType = callSiteDescriptor.getMethodType(); + final MethodHandle invocation = guardedInvocation.getInvocation(); + if(invocation.type().parameterCount() == origType.parameterCount() - runtimeContextArgCount) { + final List> prefix = origType.parameterList().subList(1, runtimeContextArgCount + 1); + final MethodHandle guard = guardedInvocation.getGuard(); + guardedInvocation = guardedInvocation.dropArguments(1, prefix); + } + } + + if(unstableDetectionEnabled && relinkCount <= unstableRelinkThreshold && relinkCount++ == unstableRelinkThreshold) { + // Note that we'll increase the relinkCount until threshold+1 and not increase it beyond that. Threshold+1 + // is treated as a special value to signal that resetAndRelink has already executed once for the unstable + // call site; we only want the call site to throw away its current linkage once, when it transitions to + // unstable. + callSite.resetAndRelink(guardedInvocation, createRelinkAndInvokeMethod(callSite, relinkCount)); + } else { + callSite.relink(guardedInvocation, createRelinkAndInvokeMethod(callSite, relinkCount)); + } + if(syncOnRelink) { + MutableCallSite.syncAll(new MutableCallSite[] { (MutableCallSite)callSite }); + } + return guardedInvocation.getInvocation(); + } + + /** + * Returns a stack trace element describing the location of the call site currently being relinked on the current + * thread. The operation internally creates a Throwable object and inspects its stack trace, so it's potentially + * expensive. The recommended usage for it is in writing diagnostics code. + * @return a stack trace element describing the location of the call site currently being relinked, or null if it is + * not invoked while a call site is being relinked. + */ + public static StackTraceElement getRelinkedCallSiteLocation() { + final StackTraceElement[] trace = new Throwable().getStackTrace(); + for(int i = 0; i < trace.length - 1; ++i) { + final StackTraceElement frame = trace[i]; + if(RELINK_METHOD_NAME.equals(frame.getMethodName()) && CLASS_NAME.equals(frame.getClassName())) { + return trace[i + 1]; + } + } + return null; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java b/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java new file mode 100644 index 00000000000..49e821ef489 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java @@ -0,0 +1,311 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink; + +import java.lang.invoke.MutableCallSite; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import jdk.internal.dynalink.beans.BeansLinker; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.support.AutoDiscovery; +import jdk.internal.dynalink.support.BottomGuardingDynamicLinker; +import jdk.internal.dynalink.support.CompositeGuardingDynamicLinker; +import jdk.internal.dynalink.support.CompositeTypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.LinkerServicesImpl; +import jdk.internal.dynalink.support.TypeConverterFactory; + + +/** + * A factory class for creating {@link DynamicLinker}s. The most usual dynamic linker is a linker that is a composition + * of all {@link GuardingDynamicLinker}s known and pre-created by the caller as well as any + * {@link AutoDiscovery automatically discovered} guarding linkers and the standard fallback {@link BeansLinker}. See + * {@link DynamicLinker} documentation for tips on how to use this class. + * + * @author Attila Szegedi + */ +public class DynamicLinkerFactory { + + /** + * Default value for {@link #setUnstableRelinkThreshold(int) unstable relink threshold}. + */ + public static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8; + + private ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + private List prioritizedLinkers; + private List fallbackLinkers; + private int runtimeContextArgCount = 0; + private boolean syncOnRelink = false; + private int unstableRelinkThreshold = DEFAULT_UNSTABLE_RELINK_THRESHOLD; + + /** + * Sets the class loader for automatic discovery of available linkers. If not set explicitly, then the thread + * context class loader at the time of the constructor invocation will be used. + * + * @param classLoader the class loader used for the autodiscovery of available linkers. + */ + public void setClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + /** + * Sets the prioritized linkers. Language runtimes using this framework will usually precreate at least the linker + * for their own language. These linkers will be consulted first in the resulting dynamic linker, before any + * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the prioritized + * linkers, it will be ignored and the explicit prioritized instance will be used. + * + * @param prioritizedLinkers the list of prioritized linkers. Null can be passed to indicate no prioritized linkers + * (this is also the default value). + */ + public void setPrioritizedLinkers(List prioritizedLinkers) { + this.prioritizedLinkers = + prioritizedLinkers == null ? null : new ArrayList<>(prioritizedLinkers); + } + + /** + * Sets the prioritized linkers. Language runtimes using this framework will usually precreate at least the linker + * for their own language. These linkers will be consulted first in the resulting dynamic linker, before any + * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the prioritized + * linkers, it will be ignored and the explicit prioritized instance will be used. + * + * @param prioritizedLinkers a list of prioritized linkers. + */ + public void setPrioritizedLinkers(GuardingDynamicLinker... prioritizedLinkers) { + setPrioritizedLinkers(Arrays.asList(prioritizedLinkers)); + } + + /** + * Sets a single prioritized linker. Identical to calling {@link #setPrioritizedLinkers(List)} with a single-element + * list. + * + * @param prioritizedLinker the single prioritized linker. Must not be null. + * @throws IllegalArgumentException if null is passed. + */ + public void setPrioritizedLinker(GuardingDynamicLinker prioritizedLinker) { + if(prioritizedLinker == null) { + throw new IllegalArgumentException("prioritizedLinker == null"); + } + this.prioritizedLinkers = Collections.singletonList(prioritizedLinker); + } + + /** + * Sets the fallback linkers. These linkers will be consulted last in the resulting composite linker, after any + * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the fallback + * linkers, it will be ignored and the explicit fallback instance will be used. + * + * @param fallbackLinkers the list of fallback linkers. Can be empty to indicate the caller wishes to set no + * fallback linkers. + */ + public void setFallbackLinkers(List fallbackLinkers) { + this.fallbackLinkers = fallbackLinkers == null ? null : new ArrayList<>(fallbackLinkers); + } + + /** + * Sets the fallback linkers. These linkers will be consulted last in the resulting composite linker, after any + * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the fallback + * linkers, it will be ignored and the explicit fallback instance will be used. + * + * @param fallbackLinkers the list of fallback linkers. Can be empty to indicate the caller wishes to set no + * fallback linkers. If it is left as null, the standard fallback {@link BeansLinker} will be used. + */ + public void setFallbackLinkers(GuardingDynamicLinker... fallbackLinkers) { + setFallbackLinkers(Arrays.asList(fallbackLinkers)); + } + + /** + * Sets the number of arguments in the call sites that represent the stack context of the language runtime creating + * the linker. If the language runtime uses no context information passed on stack, then it should be zero + * (the default value). If it is set to nonzero value, then every dynamic call site emitted by this runtime must + * have the argument list of the form: {@code (this, contextArg1[, contextArg2[, ...]], normalArgs)}. It is + * advisable to only pass one context-specific argument, though, of an easily recognizable, runtime specific type + * encapsulating the runtime thread local state. + * + * @param runtimeContextArgCount the number of language runtime context arguments in call sites. + */ + public void setRuntimeContextArgCount(int runtimeContextArgCount) { + if(runtimeContextArgCount < 0) { + throw new IllegalArgumentException("runtimeContextArgCount < 0"); + } + this.runtimeContextArgCount = runtimeContextArgCount; + } + + /** + * Sets whether the linker created by this factory will invoke {@link MutableCallSite#syncAll(MutableCallSite[])} + * after a call site is relinked. Defaults to false. You probably want to set it to true if your runtime supports + * multithreaded execution of dynamically linked code. + * @param syncOnRelink true for invoking sync on relink, false otherwise. + */ + public void setSyncOnRelink(boolean syncOnRelink) { + this.syncOnRelink = syncOnRelink; + } + + /** + * Sets the unstable relink threshold; the number of times a call site is relinked after which it will be + * considered unstable, and subsequent link requests for it will indicate this. + * @param unstableRelinkThreshold the new threshold. Must not be less than zero. The value of zero means that + * call sites will never be considered unstable. + * @see LinkRequest#isCallSiteUnstable() + */ + public void setUnstableRelinkThreshold(int unstableRelinkThreshold) { + if(unstableRelinkThreshold < 0) { + throw new IllegalArgumentException("unstableRelinkThreshold < 0"); + } + this.unstableRelinkThreshold = unstableRelinkThreshold; + } + + /** + * Creates a new dynamic linker consisting of all the prioritized, autodiscovered, and fallback linkers. + * + * @return the new dynamic Linker + */ + public DynamicLinker createLinker() { + // Treat nulls appropriately + if(prioritizedLinkers == null) { + prioritizedLinkers = Collections.emptyList(); + } + if(fallbackLinkers == null) { + fallbackLinkers = Collections.singletonList(new BeansLinker()); + } + + // Gather classes of all precreated (prioritized and fallback) linkers. + // We'll filter out any discovered linkers of the same class. + final Set> knownLinkerClasses = new HashSet<>(); + addClasses(knownLinkerClasses, prioritizedLinkers); + addClasses(knownLinkerClasses, fallbackLinkers); + + final List discovered = AutoDiscovery.loadLinkers(classLoader); + // Now, concatenate ... + final List linkers = new ArrayList<>(prioritizedLinkers.size() + discovered.size() + + fallbackLinkers.size()); + // ... prioritized linkers, ... + linkers.addAll(prioritizedLinkers); + // ... filtered discovered linkers, ... + for(GuardingDynamicLinker linker: discovered) { + if(!knownLinkerClasses.contains(linker.getClass())) { + linkers.add(linker); + } + } + // ... and finally fallback linkers. + linkers.addAll(fallbackLinkers); + final List optimized = CompositeTypeBasedGuardingDynamicLinker.optimize(linkers); + final GuardingDynamicLinker composite; + switch(linkers.size()) { + case 0: { + composite = BottomGuardingDynamicLinker.INSTANCE; + break; + } + case 1: { + composite = optimized.get(0); + break; + } + default: { + composite = new CompositeGuardingDynamicLinker(optimized); + break; + } + } + + final List typeConverters = new LinkedList<>(); + for(GuardingDynamicLinker linker: linkers) { + if(linker instanceof GuardingTypeConverterFactory) { + typeConverters.add((GuardingTypeConverterFactory)linker); + } + } + + return new DynamicLinker(new LinkerServicesImpl(new TypeConverterFactory(typeConverters), composite), + runtimeContextArgCount, syncOnRelink, unstableRelinkThreshold); + } + + private static void addClasses(Set> knownLinkerClasses, + List linkers) { + for(GuardingDynamicLinker linker: linkers) { + knownLinkerClasses.add(linker.getClass()); + } + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/MonomorphicCallSite.java b/nashorn/src/jdk/internal/dynalink/MonomorphicCallSite.java new file mode 100644 index 00000000000..96784f0ec43 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/MonomorphicCallSite.java @@ -0,0 +1,116 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink; + +import java.lang.invoke.MethodHandle; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.support.AbstractRelinkableCallSite; + + +/** + * A relinkable call site that implements monomorphic inline caching strategy. After it linked a method, it will keep it + * until either its guard evaluates to false, or its switchpoint is invalidated, at which time it will throw away the + * previous linkage, and trigger relinking with its associated {@link DynamicLinker}. + * + * @author Attila Szegedi + */ +public class MonomorphicCallSite extends AbstractRelinkableCallSite { + /** + * Creates a new call site with monomorphic inline caching strategy. + * @param descriptor the descriptor for this call site + */ + public MonomorphicCallSite(CallSiteDescriptor descriptor) { + super(descriptor); + } + + @Override + public void relink(GuardedInvocation guardedInvocation, MethodHandle relink) { + setTarget(guardedInvocation.compose(relink)); + } + + @Override + public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle relink) { + relink(guardedInvocation, relink); + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/NoSuchDynamicMethodException.java b/nashorn/src/jdk/internal/dynalink/NoSuchDynamicMethodException.java new file mode 100644 index 00000000000..af956037890 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/NoSuchDynamicMethodException.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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink; + +import jdk.internal.dynalink.linker.GuardingDynamicLinker; + +/** + * Thrown at the invocation if the call site can not be linked by any available {@link GuardingDynamicLinker}. + * + * @author Attila Szegedi + */ +public class NoSuchDynamicMethodException extends RuntimeException { + private static final long serialVersionUID = 1L; + + /** + * Creates a new NoSuchDynamicMethodException + * @param message the message of the exception. + */ + public NoSuchDynamicMethodException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/RelinkableCallSite.java b/nashorn/src/jdk/internal/dynalink/RelinkableCallSite.java new file mode 100644 index 00000000000..f9407cb0b3f --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/RelinkableCallSite.java @@ -0,0 +1,148 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink; + +import java.lang.invoke.CallSite; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MutableCallSite; +import java.lang.invoke.VolatileCallSite; +import jdk.internal.dynalink.linker.GuardedInvocation; + + +/** + * Interface for relinkable call sites. Language runtimes wishing to use this framework must use subclasses of + * {@link CallSite} that also implement this interface as their call sites. There is a readily usable + * {@link MonomorphicCallSite} subclass that implements monomorphic inline caching strategy as well as a + * {@link ChainedCallSite} that retains a chain of already linked method handles. The reason this is defined as an + * interface instead of a concrete, albeit abstract class is that it allows independent implementations to choose + * between {@link MutableCallSite} and {@link VolatileCallSite} as they see fit. + * + * @author Attila Szegedi + */ +public interface RelinkableCallSite { + /** + * Initializes the relinkable call site by setting a relink-and-invoke method handle. The call site implementation + * is supposed to set this method handle as its target. + * @param relinkAndInvoke a relink-and-invoke method handle supplied by the {@link DynamicLinker}. + */ + public void initialize(MethodHandle relinkAndInvoke); + + /** + * Returns the descriptor for this call site. + * + * @return the descriptor for this call site. + */ + public CallSiteDescriptor getDescriptor(); + + /** + * This method will be called by the dynamic linker every time the call site is normally relinked. It will be passed + * a {@code GuardedInvocation} that the call site should incorporate into its target method handle. When this method + * is called, the call site is allowed to keep other non-invalidated invocations around for implementation of + * polymorphic inline caches and compose them with this invocation to form its final target. + * + * @param guardedInvocation the guarded invocation that the call site should incorporate into its target method + * handle. + * @param fallback the fallback method. This is a method matching the method type of the call site that is supplied + * by the {@link DynamicLinker} to be used by this call site as a fallback when it can't invoke its target with the + * passed arguments. The fallback method is such that when it's invoked, it'll try to discover the adequate target + * for the invocation, subsequently invoke {@link #relink(GuardedInvocation, MethodHandle)} or + * {@link #resetAndRelink(GuardedInvocation, MethodHandle)}, and finally invoke the target. + */ + public void relink(GuardedInvocation guardedInvocation, MethodHandle fallback); + + /** + * This method will be called by the dynamic linker every time the call site is relinked and the linker wishes the + * call site to throw away any prior linkage state. It will be passed a {@code GuardedInvocation} that the call site + * should use to build its target method handle. When this method is called, the call site is discouraged from + * keeping previous state around, and is supposed to only link the current invocation. + * + * @param guardedInvocation the guarded invocation that the call site should use to build its target method handle. + * @param fallback the fallback method. This is a method matching the method type of the call site that is supplied + * by the {@link DynamicLinker} to be used by this call site as a fallback when it can't invoke its target with the + * passed arguments. The fallback method is such that when it's invoked, it'll try to discover the adequate target + * for the invocation, subsequently invoke {@link #relink(GuardedInvocation, MethodHandle)} or + * {@link #resetAndRelink(GuardedInvocation, MethodHandle)}, and finally invoke the target. + */ + public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle fallback); +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java b/nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java new file mode 100644 index 00000000000..d9e1cecd283 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java @@ -0,0 +1,690 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.beans.Introspector; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; +import jdk.internal.dynalink.support.Guards; +import jdk.internal.dynalink.support.Lookup; + + +/** + * A base class for both {@link StaticClassLinker} and {@link BeanLinker}. Deals with common aspects of property + * exposure and method calls for both static and instance facets of a class. + * + * @author Attila Szegedi + */ +abstract class AbstractJavaLinker implements GuardingDynamicLinker { + final Class clazz; + private final MethodHandle classGuard; + private final MethodHandle assignableGuard; + private final Map propertyGetters = new HashMap<>(); + private final Map propertySetters = new HashMap<>(); + private final Map methods = new HashMap<>(); + + AbstractJavaLinker(Class clazz, MethodHandle classGuard) { + this(clazz, classGuard, classGuard); + } + + AbstractJavaLinker(Class clazz, MethodHandle classGuard, MethodHandle assignableGuard) { + this.clazz = clazz; + this.classGuard = classGuard; + this.assignableGuard = assignableGuard; + + final FacetIntrospector introspector = createFacetIntrospector(); + try { + // Add methods and properties + for(Method method: introspector.getMethods()) { + final String name = method.getName(); + final MethodHandle methodHandle = introspector.unreflect(method); + // Add method + addMember(name, methodHandle, methods); + // Add the method as a property getter and/or setter + if(name.startsWith("get") && name.length() > 3 && method.getParameterTypes().length == 0) { + // Property getter + setPropertyGetter(Introspector.decapitalize(name.substring(3)), introspector.unreflect( + getMostGenericGetter(method)), ValidationType.INSTANCE_OF); + } else if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0 && + method.getReturnType() == boolean.class) { + // Boolean property getter + setPropertyGetter(Introspector.decapitalize(name.substring(2)), introspector.unreflect( + getMostGenericGetter(method)), ValidationType.INSTANCE_OF); + } else if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) { + // Property setter + addMember(Introspector.decapitalize(name.substring(3)), methodHandle, propertySetters); + } + } + + // Add field getter/setters as property getters/setters. + for(Field field: introspector.getFields()) { + final String name = field.getName(); + // Only add a property getter when one is not defined already as a getXxx()/isXxx() method. + if(!propertyGetters.containsKey(name)) { + setPropertyGetter(name, introspector.unreflectGetter(field), ValidationType.EXACT_CLASS); + } + if(!(Modifier.isFinal(field.getModifiers()) || propertySetters.containsKey(name))) { + addMember(name, introspector.unreflectSetter(field), propertySetters); + } + } + + // Add inner classes, but only those for which we don't hide a property with it + for(Map.Entry innerClassSpec: introspector.getInnerClassGetters().entrySet()) { + final String name = innerClassSpec.getKey(); + if(!propertyGetters.containsKey(name)) { + setPropertyGetter(name, innerClassSpec.getValue(), ValidationType.EXACT_CLASS); + } + } + } finally { + introspector.close(); + } + } + + abstract FacetIntrospector createFacetIntrospector(); + + void setPropertyGetter(String name, MethodHandle handle, ValidationType validationType) { + propertyGetters.put(name, new AnnotatedMethodHandle(handle, validationType)); + } + + private void addMember(String name, MethodHandle mh, Map methodMap) { + final DynamicMethod existingMethod = methodMap.get(name); + final DynamicMethod newMethod = addMember(mh, existingMethod, clazz, name); + if(newMethod != existingMethod) { + methodMap.put(name, newMethod); + } + } + + static DynamicMethod createDynamicMethod(Iterable methodHandles, Class clazz, String name) { + DynamicMethod dynMethod = null; + for(MethodHandle methodHandle: methodHandles) { + dynMethod = addMember(methodHandle, dynMethod, clazz, name); + } + return dynMethod; + } + + private static DynamicMethod addMember(MethodHandle mh, DynamicMethod existing, Class clazz, String name) { + if(existing == null) { + return new SimpleDynamicMethod(mh, clazz, name); + } else if(existing.contains(mh)) { + return existing; + } else if(existing instanceof SimpleDynamicMethod) { + final OverloadedDynamicMethod odm = new OverloadedDynamicMethod(clazz, name); + odm.addMethod(((SimpleDynamicMethod)existing)); + odm.addMethod(mh); + return odm; + } else if(existing instanceof OverloadedDynamicMethod) { + ((OverloadedDynamicMethod)existing).addMethod(mh); + return existing; + } + throw new AssertionError(); + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest request, final LinkerServices linkerServices) + throws Exception { + final LinkRequest ncrequest = request.withoutRuntimeContext(); + // BeansLinker already checked that the name is at least 2 elements long and the first element is "dyn". + final CallSiteDescriptor callSiteDescriptor = ncrequest.getCallSiteDescriptor(); + final String op = callSiteDescriptor.getNameToken(CallSiteDescriptor.OPERATOR); + // Either dyn:callMethod:name(this[,args]) or dyn:callMethod(this,name[,args]). + if("callMethod" == op) { + return getCallPropWithThis(callSiteDescriptor, linkerServices); + } + List operations = CallSiteDescriptorFactory.tokenizeOperators(callSiteDescriptor); + while(!operations.isEmpty()) { + final GuardedInvocationComponent gic = getGuardedInvocationComponent(callSiteDescriptor, linkerServices, + operations); + if(gic != null) { + return gic.getGuardedInvocation(); + } + operations = pop(operations); + } + return null; + } + + protected GuardedInvocationComponent getGuardedInvocationComponent(CallSiteDescriptor callSiteDescriptor, + LinkerServices linkerServices, List operations) throws Exception { + if(operations.isEmpty()) { + return null; + } + final String op = operations.get(0); + // Either dyn:getProp:name(this) or dyn:getProp(this, name) + if("getProp".equals(op)) { + return getPropertyGetter(callSiteDescriptor, linkerServices, pop(operations)); + } + // Either dyn:setProp:name(this, value) or dyn:setProp(this, name, value) + if("setProp".equals(op)) { + return getPropertySetter(callSiteDescriptor, linkerServices, pop(operations)); + } + // Either dyn:getMethod:name(this), or dyn:getMethod(this, name) + if("getMethod".equals(op)) { + return getMethodGetter(callSiteDescriptor, linkerServices, pop(operations)); + } + return null; + } + + static final List pop(List l) { + return l.subList(1, l.size()); + } + + MethodHandle getClassGuard(CallSiteDescriptor desc) { + return getClassGuard(desc.getMethodType()); + } + + MethodHandle getClassGuard(MethodType type) { + return Guards.asType(classGuard, type); + } + + GuardedInvocationComponent getClassGuardedInvocationComponent(MethodHandle invocation, MethodType type) { + return new GuardedInvocationComponent(invocation, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); + } + + private MethodHandle getAssignableGuard(MethodType type) { + return Guards.asType(assignableGuard, type); + } + + private GuardedInvocation getCallPropWithThis(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) { + switch(callSiteDescriptor.getNameTokenCount()) { + case 3: { + return createGuardedDynamicMethodInvocation(callSiteDescriptor.getMethodType(), linkerServices, + callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), methods); + } + default: { + return null; + } + } + } + + private GuardedInvocation createGuardedDynamicMethodInvocation(MethodType callSiteType, + LinkerServices linkerServices, String methodName, Map methodMap){ + final MethodHandle inv = getDynamicMethodInvocation(callSiteType, linkerServices, methodName, methodMap); + return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteType)); + } + + private static MethodHandle getDynamicMethodInvocation(MethodType callSiteType, LinkerServices linkerServices, + String methodName, Map methodMap) { + final DynamicMethod dynaMethod = getDynamicMethod(methodName, methodMap); + return dynaMethod != null ? dynaMethod.getInvocation(callSiteType, linkerServices) : null; + } + + private static DynamicMethod getDynamicMethod(String methodName, Map methodMap) { + final DynamicMethod dynaMethod = methodMap.get(methodName); + return dynaMethod != null ? dynaMethod : getExplicitSignatureDynamicMethod(methodName, methodMap); + } + + private static SimpleDynamicMethod getExplicitSignatureDynamicMethod(String methodName, + Map methodsMap) { + // What's below is meant to support the "name(type, type, ...)" syntax that programmers can use in a method name + // to manually pin down an exact overloaded variant. This is not usually required, as the overloaded method + // resolution works correctly in almost every situation. However, in presence of many language-specific + // conversions with a radically dynamic language, most overloaded methods will end up being constantly selected + // at invocation time, so a programmer knowledgable of the situation might choose to pin down an exact overload + // for performance reasons. + + // Is the method name lexically of the form "name(types)"? + final int lastChar = methodName.length() - 1; + if(methodName.charAt(lastChar) != ')') { + return null; + } + final int openBrace = methodName.indexOf('('); + if(openBrace == -1) { + return null; + } + + // Find an existing method for the "name" part + final DynamicMethod simpleNamedMethod = methodsMap.get(methodName.substring(0, openBrace)); + if(simpleNamedMethod == null) { + return null; + } + + // Try to get a narrowed dynamic method for the explicit parameter types. + return simpleNamedMethod.getMethodForExactParamTypes(methodName.substring(openBrace + 1, lastChar)); + } + + private static final MethodHandle IS_METHOD_HANDLE_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType( + boolean.class, MethodHandle.class)); + private static final MethodHandle CONSTANT_NULL_DROP_METHOD_HANDLE = MethodHandles.dropArguments( + MethodHandles.constant(Object.class, null), 0, MethodHandle.class); + + private GuardedInvocationComponent getPropertySetter(CallSiteDescriptor callSiteDescriptor, + LinkerServices linkerServices, List operations) throws Exception { + final MethodType type = callSiteDescriptor.getMethodType(); + switch(callSiteDescriptor.getNameTokenCount()) { + case 2: { + // Must have three arguments: target object, property name, and property value. + assertParameterCount(callSiteDescriptor, 3); + + // What's below is basically: + // foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation), + // get_setter_handle(type, linkerServices)) + // only with a bunch of method signature adjustments. Basically, retrieve method setter + // MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next + // component's invocation. + + // Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll + // abbreviate to R(O, N, V) going forward. + // We want setters that conform to "R(O, V)" + final MethodType setterType = type.dropParameterTypes(1, 2); + // Bind property setter handle to the expected setter type and linker services. Type is + // MethodHandle(Object, String, Object) + final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0, setterType, + linkerServices); + + // Cast getter to MethodHandle(O, N, V) + final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType( + MethodHandle.class)); + + // Handle to invoke the setter R(MethodHandle, O, V) + final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType); + // Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V) + final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType( + 1)); + final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, + linkerServices, operations); + + final MethodHandle fallbackFolded; + if(nextComponent == null) { + // Object(MethodHandle)->R(MethodHandle, O, N, V); returns constant null + fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1, + type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class)); + } else { + // R(O, N, V)->R(MethodHandle, O, N, V); adapts the next component's invocation to drop the + // extra argument resulting from fold + fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(), + 0, MethodHandle.class); + } + + // fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V)) + final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( + IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); + if(nextComponent == null) { + return getClassGuardedInvocationComponent(compositeSetter, type); + } else { + return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, + ValidationType.EXACT_CLASS); + } + } + case 3: { + // Must have two arguments: target object and property value + assertParameterCount(callSiteDescriptor, 2); + final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor.getMethodType(), + linkerServices, callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), + propertySetters); + // If we have a property setter with this name, this composite operation will always stop here + if(gi != null) { + return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS); + } + // If we don't have a property setter with this name, always fall back to the next operation in the + // composite (if any) + return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations); + } + default: { + // More than two name components; don't know what to do with it. + return null; + } + } + } + + private static final Lookup privateLookup = new Lookup(MethodHandles.lookup()); + + private static final MethodHandle IS_ANNOTATED_HANDLE_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType( + boolean.class, AnnotatedMethodHandle.class)); + private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_HANDLE = MethodHandles.dropArguments( + MethodHandles.constant(Object.class, null), 0, AnnotatedMethodHandle.class); + private static final MethodHandle GET_ANNOTATED_HANDLE = privateLookup.findGetter(AnnotatedMethodHandle.class, + "handle", MethodHandle.class); + private static final MethodHandle GENERIC_PROPERTY_GETTER_HANDLER_INVOKER = MethodHandles.filterArguments( + MethodHandles.invoker(MethodType.methodType(Object.class, Object.class)), 0, GET_ANNOTATED_HANDLE); + + private GuardedInvocationComponent getPropertyGetter(CallSiteDescriptor callSiteDescriptor, + LinkerServices linkerServices, List ops) throws Exception { + final MethodType type = callSiteDescriptor.getMethodType(); + switch(callSiteDescriptor.getNameTokenCount()) { + case 2: { + // Must have exactly two arguments: receiver and name + assertParameterCount(callSiteDescriptor, 2); + + // What's below is basically: + // foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle) + // only with a bunch of method signature adjustments. Basically, retrieve method getter + // AnnotatedMethodHandle; if it is non-null, invoke its "handle" field, otherwise either return null, + // or delegate to next component's invocation. + + final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType( + AnnotatedMethodHandle.class)); + // Object(AnnotatedMethodHandle, Object)->R(AnnotatedMethodHandle, T0) + final MethodHandle invokeHandleTyped = linkerServices.asType(GENERIC_PROPERTY_GETTER_HANDLER_INVOKER, + MethodType.methodType(type.returnType(), AnnotatedMethodHandle.class, type.parameterType(0))); + // Since it's in the target of a fold, drop the unnecessary second argument + // R(AnnotatedMethodHandle, T0)->R(AnnotatedMethodHandle, T0, T1) + final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2, + type.parameterType(1)); + final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, + linkerServices, ops); + + final MethodHandle fallbackFolded; + if(nextComponent == null) { + // Object(AnnotatedMethodHandle)->R(AnnotatedMethodHandle, T0, T1); returns constant null + fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_HANDLE, 1, + type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedMethodHandle.class)); + } else { + // R(T0, T1)->R(AnnotatedMethodHAndle, T0, T1); adapts the next component's invocation to drop the + // extra argument resulting from fold + fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(), + 0, AnnotatedMethodHandle.class); + } + + // fold(R(AnnotatedMethodHandle, T0, T1), AnnotatedMethodHandle(T0, T1)) + final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( + IS_ANNOTATED_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); + if(nextComponent == null) { + return getClassGuardedInvocationComponent(compositeGetter, type); + } else { + return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, + ValidationType.EXACT_CLASS); + } + } + case 3: { + // Must have exactly one argument: receiver + assertParameterCount(callSiteDescriptor, 1); + // Fixed name + final AnnotatedMethodHandle annGetter = propertyGetters.get(callSiteDescriptor.getNameToken( + CallSiteDescriptor.NAME_OPERAND)); + if(annGetter == null) { + // We have no such property, always delegate to the next component operation + return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops); + } + final MethodHandle getter = annGetter.handle; + // NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being + // overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the + // method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If + // we're linking against a field getter, don't make the assumption. + // NOTE: No delegation to the next component operation if we have a property with this name, even if its + // value is null. + final ValidationType validationType = annGetter.validationType; + return new GuardedInvocationComponent(linkerServices.asType(getter, type), getGuard(validationType, + type), clazz, validationType); + } + default: { + // Can't do anything with more than 3 name components + return null; + } + } + } + + private MethodHandle getGuard(ValidationType validationType, MethodType methodType) { + switch(validationType) { + case EXACT_CLASS: { + return getClassGuard(methodType); + } + case INSTANCE_OF: { + return getAssignableGuard(methodType); + } + case IS_ARRAY: { + return Guards.isArray(0, methodType); + } + case NONE: { + return null; + } + } + throw new AssertionError(); + } + + private static final MethodHandle IS_DYNAMIC_METHOD_NOT_NULL = Guards.asType(Guards.isNotNull(), + MethodType.methodType(boolean.class, DynamicMethod.class)); + private static final MethodHandle DYNAMIC_METHOD_IDENTITY = MethodHandles.identity(DynamicMethod.class); + + private GuardedInvocationComponent getMethodGetter(CallSiteDescriptor callSiteDescriptor, + LinkerServices linkerServices, List ops) throws Exception { + final MethodType type = callSiteDescriptor.getMethodType(); + switch(callSiteDescriptor.getNameTokenCount()) { + case 2: { + // Must have exactly two arguments: receiver and name + assertParameterCount(callSiteDescriptor, 2); + final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, + linkerServices, ops); + if(nextComponent == null) { + // No next component operation; just return a component for this operation. + return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type); + } else { + // What's below is basically: + // foldArguments(guardWithTest(isNotNull, identity, nextComponent.invocation), getter) + // only with a bunch of method signature adjustments. Basically, execute method getter; if + // it returns a non-null DynamicMethod, use identity to return it, otherwise delegate to + // nextComponent's invocation. + + final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type.changeReturnType( + DynamicMethod.class)); + // Since it is part of the foldArgument() target, it will have extra args that we need to drop. + final MethodHandle returnMethodHandle = linkerServices.asType(MethodHandles.dropArguments( + DYNAMIC_METHOD_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0, + DynamicMethod.class)); + final MethodHandle nextComponentInvocation = nextComponent.getGuardedInvocation().getInvocation(); + // The assumption is that getGuardedInvocationComponent() already asType()'d it correctly + assert nextComponentInvocation.type().equals(type); + // Since it is part of the foldArgument() target, we have to drop an extra arg it receives. + final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0, + DynamicMethod.class); + // Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get) + final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( + IS_DYNAMIC_METHOD_NOT_NULL, returnMethodHandle, nextCombinedInvocation), typedGetter); + + return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, + ValidationType.EXACT_CLASS); + } + } + case 3: { + // Must have exactly one argument: receiver + assertParameterCount(callSiteDescriptor, 1); + final DynamicMethod method = getDynamicMethod(callSiteDescriptor.getNameToken( + CallSiteDescriptor.NAME_OPERAND)); + if(method == null) { + // We have no such method, always delegate to the next component + return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops); + } + // No delegation to the next component of the composite operation; if we have a method with that name, + // we'll always return it at this point. + return getClassGuardedInvocationComponent(linkerServices.asType(MethodHandles.dropArguments( + MethodHandles.constant(DynamicMethod.class, method), 0, type.parameterType(0)), type), type); + } + default: { + // Can't do anything with more than 3 name components + return null; + } + } + } + + private static void assertParameterCount(CallSiteDescriptor descriptor, int paramCount) { + if(descriptor.getMethodType().parameterCount() != paramCount) { + throw new BootstrapMethodError(descriptor.getName() + " must have exactly " + paramCount + " parameters."); + } + } + + private static MethodHandle GET_PROPERTY_GETTER_HANDLE = MethodHandles.dropArguments(privateLookup.findOwnSpecial( + "getPropertyGetterHandle", Object.class, Object.class), 1, Object.class); + private final MethodHandle getPropertyGetterHandle = GET_PROPERTY_GETTER_HANDLE.bindTo(this); + + /** + * @param id the property ID + * @return the method handle for retrieving the property, or null if the property does not exist + */ + @SuppressWarnings("unused") + private Object getPropertyGetterHandle(Object id) { + return propertyGetters.get(id); + } + + // Type is MethodHandle(BeanLinker, MethodType, LinkerServices, Object, String, Object), of which the two "Object" + // args are dropped; this makes handles with first three args conform to "Object, String, Object" though, which is + // a typical property setter with variable name signature (target, name, value). + private static final MethodHandle GET_PROPERTY_SETTER_HANDLE = MethodHandles.dropArguments(MethodHandles.dropArguments( + privateLookup.findOwnSpecial("getPropertySetterHandle", MethodHandle.class, MethodType.class, + LinkerServices.class, Object.class), 3, Object.class), 5, Object.class); + // Type is MethodHandle(MethodType, LinkerServices, Object, String, Object) + private final MethodHandle getPropertySetterHandle = GET_PROPERTY_SETTER_HANDLE.bindTo(this); + + @SuppressWarnings("unused") + private MethodHandle getPropertySetterHandle(MethodType setterType, LinkerServices linkerServices, Object id) { + return getDynamicMethodInvocation(setterType, linkerServices, String.valueOf(id), propertySetters); + } + + private static MethodHandle GET_DYNAMIC_METHOD = MethodHandles.dropArguments(privateLookup.findOwnSpecial( + "getDynamicMethod", DynamicMethod.class, Object.class), 1, Object.class); + private final MethodHandle getDynamicMethod = GET_DYNAMIC_METHOD.bindTo(this); + + @SuppressWarnings("unused") + private DynamicMethod getDynamicMethod(Object name) { + return getDynamicMethod(String.valueOf(name), methods); + } + + /** + * Returns a dynamic method of the specified name. + * + * @param name name of the method + * @return the dynamic method (either {@link SimpleDynamicMethod} or {@link OverloadedDynamicMethod}, or null if the + * method with the specified name does not exist. + */ + public DynamicMethod getDynamicMethod(String name) { + return getDynamicMethod(name, methods); + } + + /** + * Find the most generic superclass that declares this getter. Since getters have zero args (aside from the + * receiver), they can't be overloaded, so we're free to link with an instanceof guard for the most generic one, + * creating more stable call sites. + * @param getter the getter + * @return getter with same name, declared on the most generic superclass/interface of the declaring class + */ + private static Method getMostGenericGetter(Method getter) { + return getMostGenericGetter(getter.getName(), getter.getReturnType(), getter.getDeclaringClass()); + } + + private static Method getMostGenericGetter(String name, Class returnType, Class declaringClass) { + if(declaringClass == null) { + return null; + } + // Prefer interfaces + for(Class itf: declaringClass.getInterfaces()) { + final Method itfGetter = getMostGenericGetter(name, returnType, itf); + if(itfGetter != null) { + return itfGetter; + } + } + final Method superGetter = getMostGenericGetter(name, returnType, declaringClass.getSuperclass()); + if(superGetter != null) { + return superGetter; + } + if(!CheckRestrictedPackage.isRestrictedClass(declaringClass)) { + try { + return declaringClass.getMethod(name); + } catch(NoSuchMethodException e) { + // Intentionally ignored, meant to fall through + } + } + return null; + } + + private static final class AnnotatedMethodHandle { + final MethodHandle handle; + /*private*/ final ValidationType validationType; + + AnnotatedMethodHandle(MethodHandle handle, ValidationType validationType) { + this.handle = handle; + this.validationType = validationType; + } + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/beans/AccessibleMembersLookup.java b/nashorn/src/jdk/internal/dynalink/beans/AccessibleMembersLookup.java new file mode 100644 index 00000000000..c82e334acde --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/AccessibleMembersLookup.java @@ -0,0 +1,262 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +/** + * Utility class for discovering accessible methods and inner classes. Normally, a public member declared on a class is + * accessible (that is, it can be invoked from anywhere). However, this is not the case if the class itself is not + * public, or belongs to a restricted-access package. In that case, it is required to lookup a member in a publicly + * accessible superclass or implemented interface of the class, and use it instead of the member discovered on the + * class. + * + * @author Attila Szegedi + */ +class AccessibleMembersLookup { + private final Map methods; + private final Set> innerClasses; + private boolean instance; + + /** + * Creates a mapping for all accessible methods and inner classes on a class. + * + * @param clazz the inspected class + * @param instance true to inspect instance methods, false to inspect static methods. + */ + AccessibleMembersLookup(final Class clazz, boolean instance) { + this.methods = new HashMap<>(); + this.innerClasses = new LinkedHashSet<>(); + this.instance = instance; + lookupAccessibleMembers(clazz); + } + + /** + * Returns an accessible method equivalent of a method. + * + * @param m the method whose accessible equivalent is requested. + * @return the accessible equivalent for the method (can be the same as the passed in method), or null if there is + * no accessible method equivalent. + */ + Method getAccessibleMethod(final Method m) { + return m == null ? null : methods.get(new MethodSignature(m)); + } + + Collection getMethods() { + return methods.values(); + } + + Class[] getInnerClasses() { + return innerClasses.toArray(new Class[innerClasses.size()]); + } + + /** + * A helper class that represents a method signature - name and argument types. + * + * @author Attila Szegedi + */ + static final class MethodSignature { + private final String name; + private final Class[] args; + + /** + * Creates a new method signature from arbitrary data. + * + * @param name the name of the method this signature represents. + * @param args the argument types of the method. + */ + MethodSignature(String name, Class[] args) { + this.name = name; + this.args = args; + } + + /** + * Creates a signature for the given method. + * + * @param method the method for which a signature is created. + */ + MethodSignature(final Method method) { + this(method.getName(), method.getParameterTypes()); + } + + /** + * Compares this object to another object + * + * @param o the other object + * @return true if the other object is also a method signature with the same name, same number of arguments, and + * same types of arguments. + */ + @Override + public boolean equals(final Object o) { + if(o instanceof MethodSignature) { + final MethodSignature ms = (MethodSignature)o; + return ms.name.equals(name) && Arrays.equals(args, ms.args); + } + return false; + } + + /** + * Returns a hash code, consistent with the overridden {@link #equals(Object)}. + */ + @Override + public int hashCode() { + return name.hashCode() ^ Arrays.hashCode(args); + } + + @Override + public String toString() { + final StringBuilder b = new StringBuilder(); + b.append("[MethodSignature ").append(name).append('('); + if(args.length > 0) { + b.append(args[0].getCanonicalName()); + for(int i = 1; i < args.length; ++i) { + b.append(", ").append(args[i].getCanonicalName()); + } + } + return b.append(")]").toString(); + } + } + + private void lookupAccessibleMembers(final Class clazz) { + boolean searchSuperTypes; + + if(!CheckRestrictedPackage.isRestrictedClass(clazz)) { + searchSuperTypes = false; + for(Method method: clazz.getMethods()) { + if(instance != Modifier.isStatic(method.getModifiers())) { + final MethodSignature sig = new MethodSignature(method); + if(!methods.containsKey(sig)) { + final Class declaringClass = method.getDeclaringClass(); + if(declaringClass != clazz && CheckRestrictedPackage.isRestrictedClass(declaringClass)) { + //Sometimes, the declaring class of a method (Method.getDeclaringClass()) + //retrieved through Class.getMethods() for a public class will be a + //non-public superclass. For such a method, we need to find a method with + //the same name and signature in a public superclass or implemented + //interface. + //This typically doesn't happen with classes emitted by a reasonably modern + //javac, as it'll create synthetic delegator methods in all public + //immediate subclasses of the non-public class. We have, however, observed + //this in the wild with class files compiled with older javac that doesn't + //generate the said synthetic delegators. + searchSuperTypes = true; + } else { + methods.put(sig, method); + } + } + } + } + for(Class innerClass: clazz.getClasses()) { + // Add both static and non-static classes, regardless of instance flag. StaticClassLinker will just + // expose non-static classes with explicit constructor outer class argument. + // NOTE: getting inner class objects through getClasses() does not resolve them, so if those classes + // were not yet loaded, they'll only get loaded in a non-resolved state; no static initializers for + // them will trigger just by doing this. + innerClasses.add(innerClass); + } + } else { + searchSuperTypes = true; + } + + if(searchSuperTypes) { + // If we reach here, the class is either not public, or it is in a restricted package. Alternatively, it is + // public, but some of its methods claim that their declaring class is non-public. We'll try superclasses + // and implemented interfaces then looking for public ones. + final Class[] interfaces = clazz.getInterfaces(); + for(int i = 0; i < interfaces.length; i++) { + lookupAccessibleMembers(interfaces[i]); + } + final Class superclass = clazz.getSuperclass(); + if(superclass != null) { + lookupAccessibleMembers(superclass); + } + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java b/nashorn/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java new file mode 100644 index 00000000000..7f860dfe807 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java @@ -0,0 +1,221 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.LinkedList; +import java.util.List; +import jdk.internal.dynalink.support.TypeUtilities; + + +/** + * Represents overloaded methods applicable to a specific call site signature. + * + * @author Attila Szegedi + */ +class ApplicableOverloadedMethods { + private final List methods; + private final boolean varArgs; + + /** + * Creates a new ApplicableOverloadedMethods instance + * + * @param methods a list of all overloaded methods with the same name for a class. + * @param callSiteType the type of the call site + * @param test applicability test. One of {@link #APPLICABLE_BY_SUBTYPING}, + * {@link #APPLICABLE_BY_METHOD_INVOCATION_CONVERSION}, or {@link #APPLICABLE_BY_VARIABLE_ARITY}. + */ + ApplicableOverloadedMethods(final List methods, final MethodType callSiteType, + final ApplicabilityTest test) { + this.methods = new LinkedList<>(); + for(MethodHandle m: methods) { + if(test.isApplicable(callSiteType, m)) { + this.methods.add(m); + } + } + varArgs = test == APPLICABLE_BY_VARIABLE_ARITY; + } + + /** + * Retrieves all the methods this object holds. + * + * @return list of all methods. + */ + List getMethods() { + return methods; + } + + /** + * Returns a list of all methods in this objects that are maximally specific. + * + * @return a list of maximally specific methods. + */ + List findMaximallySpecificMethods() { + return MaximallySpecific.getMaximallySpecificMethods(methods, varArgs); + } + + abstract static class ApplicabilityTest { + abstract boolean isApplicable(MethodType callSiteType, MethodHandle method); + } + + /** + * Implements the applicability-by-subtyping test from JLS 15.12.2.2. + */ + static final ApplicabilityTest APPLICABLE_BY_SUBTYPING = new ApplicabilityTest() { + @Override + boolean isApplicable(MethodType callSiteType, MethodHandle method) { + final MethodType methodType = method.type(); + final int methodArity = methodType.parameterCount(); + if(methodArity != callSiteType.parameterCount()) { + return false; + } + // 0th arg is receiver; it doesn't matter for overload + // resolution. + for(int i = 1; i < methodArity; ++i) { + if(!TypeUtilities.isSubtype(callSiteType.parameterType(i), methodType.parameterType(i))) { + return false; + } + } + return true; + } + }; + + /** + * Implements the applicability-by-method-invocation-conversion test from JLS 15.12.2.3. + */ + static final ApplicabilityTest APPLICABLE_BY_METHOD_INVOCATION_CONVERSION = new ApplicabilityTest() { + @Override + boolean isApplicable(MethodType callSiteType, MethodHandle method) { + final MethodType methodType = method.type(); + final int methodArity = methodType.parameterCount(); + if(methodArity != callSiteType.parameterCount()) { + return false; + } + // 0th arg is receiver; it doesn't matter for overload + // resolution. + for(int i = 1; i < methodArity; ++i) { + if(!TypeUtilities.isMethodInvocationConvertible(callSiteType.parameterType(i), + methodType.parameterType(i))) { + return false; + } + } + return true; + } + }; + + /** + * Implements the applicability-by-variable-arity test from JLS 15.12.2.4. + */ + static final ApplicabilityTest APPLICABLE_BY_VARIABLE_ARITY = new ApplicabilityTest() { + @Override + boolean isApplicable(MethodType callSiteType, MethodHandle method) { + if(!method.isVarargsCollector()) { + return false; + } + final MethodType methodType = method.type(); + final int methodArity = methodType.parameterCount(); + final int fixArity = methodArity - 1; + final int callSiteArity = callSiteType.parameterCount(); + if(fixArity > callSiteArity) { + return false; + } + // 0th arg is receiver; it doesn't matter for overload + // resolution. + for(int i = 1; i < fixArity; ++i) { + if(!TypeUtilities.isMethodInvocationConvertible(callSiteType.parameterType(i), + methodType.parameterType(i))) { + return false; + } + } + final Class varArgType = methodType.parameterType(fixArity).getComponentType(); + for(int i = fixArity; i < callSiteArity; ++i) { + if(!TypeUtilities.isMethodInvocationConvertible(callSiteType.parameterType(i), varArgType)) { + return false; + } + } + return true; + } + }; +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/BeanIntrospector.java b/nashorn/src/jdk/internal/dynalink/beans/BeanIntrospector.java new file mode 100644 index 00000000000..fc54e353a6e --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/BeanIntrospector.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import java.util.Collections; +import java.util.Map; + +class BeanIntrospector extends FacetIntrospector { + BeanIntrospector(Class clazz) { + super(clazz, true); + } + + @Override + Map getInnerClassGetters() { + return Collections.emptyMap(); // NOTE: non-static inner classes are also on StaticClassIntrospector. + } + + @Override + MethodHandle editMethodHandle(MethodHandle mh) { + return mh; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java b/nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java new file mode 100644 index 00000000000..14c3a68bbe7 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java @@ -0,0 +1,493 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.Guards; +import jdk.internal.dynalink.support.Lookup; +import jdk.internal.dynalink.support.TypeUtilities; + + +/** + * A class that provides linking capabilities for a single POJO class. Normally not used directly, but managed by + * {@link BeansLinker}. + * + * @author Attila Szegedi + */ +class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicLinker { + BeanLinker(Class clazz) { + super(clazz, Guards.getClassGuard(clazz), Guards.getInstanceOfGuard(clazz)); + if(clazz.isArray()) { + // Some languages won't have a notion of manipulating collections. Exposing "length" on arrays as an + // explicit property is beneficial for them. + // REVISIT: is it maybe a code smell that "dyn:getLength" is not needed? + setPropertyGetter("length", GET_ARRAY_LENGTH, ValidationType.IS_ARRAY); + } + } + + @Override + public boolean canLinkType(Class type) { + return type == clazz; + } + + @Override + FacetIntrospector createFacetIntrospector() { + return new BeanIntrospector(clazz); + } + + @Override + protected GuardedInvocationComponent getGuardedInvocationComponent(CallSiteDescriptor callSiteDescriptor, + LinkerServices linkerServices, List operations) throws Exception { + final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(callSiteDescriptor, + linkerServices, operations); + if(superGic != null) { + return superGic; + } + if(operations.isEmpty()) { + return null; + } + final String op = operations.get(0); + // dyn:getElem(this, id) + // id is typically either an int (for arrays and lists) or an object (for maps). linkerServices can provide + // conversion from call site argument type though. + if("getElem".equals(op)) { + return getElementGetter(callSiteDescriptor, linkerServices, pop(operations)); + } + if("setElem".equals(op)) { + return getElementSetter(callSiteDescriptor, linkerServices, pop(operations)); + } + // dyn:getLength(this) (works on Java arrays, collections, and maps) + if("getLength".equals(op)) { + return getLengthGetter(callSiteDescriptor); + } + return null; + } + + private static MethodHandle GET_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "get", + MethodType.methodType(Object.class, int.class)); + + private static MethodHandle GET_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "get", + MethodType.methodType(Object.class, Object.class)); + + private static MethodHandle LIST_GUARD = Guards.getInstanceOfGuard(List.class); + private static MethodHandle MAP_GUARD = Guards.getInstanceOfGuard(Map.class); + + private GuardedInvocationComponent getElementGetter(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, List operations) throws Exception { + final MethodType callSiteType = callSiteDescriptor.getMethodType(); + final Class declaredType = callSiteType.parameterType(0); + final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, + linkerServices, operations); + + // If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing + // is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're + // dealing with an array, or a list or map, but hey... + // Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers + // in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices. + final GuardedInvocationComponent gic;; + final boolean isMap; + if(declaredType.isArray()) { + gic = new GuardedInvocationComponent(MethodHandles.arrayElementGetter(declaredType)); + isMap = false; + } else if(List.class.isAssignableFrom(declaredType)) { + gic = new GuardedInvocationComponent(GET_LIST_ELEMENT); + isMap = false; + } else if(Map.class.isAssignableFrom(declaredType)) { + gic = new GuardedInvocationComponent(GET_MAP_ELEMENT); + isMap = true; + } else if(clazz.isArray()) { + gic = getClassGuardedInvocationComponent(MethodHandles.arrayElementGetter(clazz), callSiteType); + isMap = false; + } else if(List.class.isAssignableFrom(clazz)) { + gic = new GuardedInvocationComponent(GET_LIST_ELEMENT, Guards.asType(LIST_GUARD, callSiteType), List.class, + ValidationType.INSTANCE_OF); + isMap = false; + } else if(Map.class.isAssignableFrom(clazz)) { + gic = new GuardedInvocationComponent(GET_MAP_ELEMENT, Guards.asType(MAP_GUARD, callSiteType), Map.class, + ValidationType.INSTANCE_OF); + isMap = true; + } else { + // Can't retrieve elements for objects that are neither arrays, nor list, nor maps. + return nextComponent; + } + + // We can have "dyn:getElem:foo", especially in composites, i.e. "dyn:getElem|getProp|getMethod:foo" + final String fixedKey = getFixedKey(callSiteDescriptor); + // Convert the key to a number if we're working with a list or array + final Object typedFixedKey; + if(!isMap && fixedKey != null) { + typedFixedKey = convertKeyToInteger(fixedKey, linkerServices); + if(typedFixedKey == null) { + // key is not numeric, it can never succeed + return nextComponent; + } + } else { + typedFixedKey = fixedKey; + } + + final GuardedInvocation gi = gic.getGuardedInvocation(); + final Binder binder = new Binder(linkerServices, callSiteType, typedFixedKey); + final MethodHandle invocation = gi.getInvocation(); + + if(nextComponent == null) { + return gic.replaceInvocation(binder.bind(invocation)); + } else { + final MethodHandle checkGuard; + if(invocation == GET_LIST_ELEMENT) { + checkGuard = convertArgToInt(RANGE_CHECK_LIST, linkerServices, callSiteDescriptor); + } else if(invocation == GET_MAP_ELEMENT) { + // TODO: A more complex solution could be devised for maps, one where we do a get() first, and fold it + // into a GWT that tests if it returned null, and if it did, do another GWT with containsKey() + // that returns constant null (on true), or falls back to next component (on false) + checkGuard = CONTAINS_MAP; + } else { + checkGuard = convertArgToInt(RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor); + } + return nextComponent.compose(MethodHandles.guardWithTest(binder.bindTest(checkGuard), + binder.bind(invocation), nextComponent.getGuardedInvocation().getInvocation()), gi.getGuard(), + gic.getValidatorClass(), gic.getValidationType()); + } + } + + private static String getFixedKey(final CallSiteDescriptor callSiteDescriptor) { + return callSiteDescriptor.getNameTokenCount() == 2 ? null : callSiteDescriptor.getNameToken( + CallSiteDescriptor.NAME_OPERAND); + } + + private static Object convertKeyToInteger(String fixedKey, LinkerServices linkerServices) throws Exception { + try { + if(linkerServices.canConvert(String.class, Number.class)) { + try { + final Object val = linkerServices.getTypeConverter(String.class, Number.class).invoke(fixedKey); + if(!(val instanceof Number)) { + return null; // not a number + } + final Number n = (Number)val; + if(n instanceof Integer) { + return n; + } + final int intIndex = n.intValue(); + final double doubleValue = n.doubleValue(); + if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinites trigger IOOBE + return null; // not an exact integer + } + return Integer.valueOf(intIndex); + } catch(Exception|Error e) { + throw e; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + return Integer.valueOf(fixedKey); + } catch(NumberFormatException e) { + // key is not a number + return null; + } + } + + private static MethodHandle convertArgToInt(MethodHandle mh, LinkerServices ls, CallSiteDescriptor desc) { + final Class sourceType = desc.getMethodType().parameterType(1); + if(TypeUtilities.isMethodInvocationConvertible(sourceType, Number.class)) { + return mh; + } else if(ls.canConvert(sourceType, Number.class)) { + final MethodHandle converter = ls.getTypeConverter(sourceType, Number.class); + return MethodHandles.filterArguments(mh, 1, converter.asType(converter.type().changeReturnType( + mh.type().parameterType(1)))); + } + return mh; + } + + /** + * Contains methods to adapt an item getter/setter method handle to the requested type, optionally binding it to a + * fixed key first. + * @author Attila Szegedi + * @version $Id: $ + */ + private static class Binder { + private final LinkerServices linkerServices; + private final MethodType methodType; + private final Object fixedKey; + + Binder(LinkerServices linkerServices, MethodType methodType, Object fixedKey) { + this.linkerServices = linkerServices; + this.methodType = fixedKey == null ? methodType : methodType.insertParameterTypes(1, fixedKey.getClass()); + this.fixedKey = fixedKey; + } + + /*private*/ MethodHandle bind(MethodHandle handle) { + return bindToFixedKey(linkerServices.asType(handle, methodType)); + } + + /*private*/ MethodHandle bindTest(MethodHandle handle) { + return bindToFixedKey(Guards.asType(handle, methodType)); + } + + private MethodHandle bindToFixedKey(MethodHandle handle) { + return fixedKey == null ? handle : MethodHandles.insertArguments(handle, 1, fixedKey); + } + } + + private static MethodHandle RANGE_CHECK_ARRAY = findRangeCheck(Object.class); + private static MethodHandle RANGE_CHECK_LIST = findRangeCheck(List.class); + private static MethodHandle CONTAINS_MAP = Lookup.PUBLIC.findVirtual(Map.class, "containsKey", + MethodType.methodType(boolean.class, Object.class)); + + private static MethodHandle findRangeCheck(Class collectionType) { + return Lookup.findOwnStatic(MethodHandles.lookup(), "rangeCheck", boolean.class, collectionType, Object.class); + } + + @SuppressWarnings("unused") + private static final boolean rangeCheck(Object array, Object index) { + if(!(index instanceof Number)) { + return false; + } + final Number n = (Number)index; + final int intIndex = n.intValue(); + final double doubleValue = n.doubleValue(); + if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinite trigger IOOBE + return false; + } + if(0 <= intIndex && intIndex < Array.getLength(array)) { + return true; + } + throw new ArrayIndexOutOfBoundsException("Array index out of range: " + n); + } + + @SuppressWarnings("unused") + private static final boolean rangeCheck(List list, Object index) { + if(!(index instanceof Number)) { + return false; + } + final Number n = (Number)index; + final int intIndex = n.intValue(); + final double doubleValue = n.doubleValue(); + if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinite trigger IOOBE + return false; + } + if(0 <= intIndex && intIndex < list.size()) { + return true; + } + throw new IndexOutOfBoundsException("Index: " + n + ", Size: " + list.size()); + } + + private static MethodHandle SET_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "set", + MethodType.methodType(Object.class, int.class, Object.class)); + + private static MethodHandle PUT_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "put", + MethodType.methodType(Object.class, Object.class, Object.class)); + + private GuardedInvocationComponent getElementSetter(CallSiteDescriptor callSiteDescriptor, + LinkerServices linkerServices, List operations) throws Exception { + final MethodType callSiteType = callSiteDescriptor.getMethodType(); + final Class declaredType = callSiteType.parameterType(0); + + final GuardedInvocationComponent gic; + // If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing + // is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're + // dealing with an array, or a list or map, but hey... + // Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers + // in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices. + final boolean isMap; + if(declaredType.isArray()) { + gic = new GuardedInvocationComponent(MethodHandles.arrayElementSetter(declaredType)); + isMap = false; + } else if(List.class.isAssignableFrom(declaredType)) { + gic = new GuardedInvocationComponent(SET_LIST_ELEMENT); + isMap = false; + } else if(Map.class.isAssignableFrom(declaredType)) { + gic = new GuardedInvocationComponent(PUT_MAP_ELEMENT); + isMap = true; + } else if(clazz.isArray()) { + gic = getClassGuardedInvocationComponent(MethodHandles.arrayElementSetter(clazz), callSiteType); + isMap = false; + } else if(List.class.isAssignableFrom(clazz)) { + gic = new GuardedInvocationComponent(SET_LIST_ELEMENT, Guards.asType(LIST_GUARD, callSiteType), List.class, + ValidationType.INSTANCE_OF); + isMap = false; + } else if(Map.class.isAssignableFrom(clazz)) { + gic = new GuardedInvocationComponent(PUT_MAP_ELEMENT, Guards.asType(MAP_GUARD, callSiteType), Map.class, + ValidationType.INSTANCE_OF); + isMap = true; + } else { + // Can't set elements for objects that are neither arrays, nor list, nor maps. + gic = null; + isMap = false; + } + + // In contrast to, say, getElementGetter, we only compute the nextComponent if the target object is not a map, + // as maps will always succeed in setting the element and will never need to fall back to the next component + // operation. + final GuardedInvocationComponent nextComponent = isMap ? null : getGuardedInvocationComponent( + callSiteDescriptor, linkerServices, operations); + if(gic == null) { + return nextComponent; + } + + // We can have "dyn:setElem:foo", especially in composites, i.e. "dyn:setElem|setProp:foo" + final String fixedKey = getFixedKey(callSiteDescriptor); + // Convert the key to a number if we're working with a list or array + final Object typedFixedKey; + if(!isMap && fixedKey != null) { + typedFixedKey = convertKeyToInteger(fixedKey, linkerServices); + if(typedFixedKey == null) { + // key is not numeric, it can never succeed + return nextComponent; + } + } else { + typedFixedKey = fixedKey; + } + + final GuardedInvocation gi = gic.getGuardedInvocation(); + final Binder binder = new Binder(linkerServices, callSiteType, typedFixedKey); + final MethodHandle invocation = gi.getInvocation(); + + if(nextComponent == null) { + return gic.replaceInvocation(binder.bind(invocation)); + } else { + final MethodHandle checkGuard = convertArgToInt(invocation == SET_LIST_ELEMENT ? RANGE_CHECK_LIST : + RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor); + return nextComponent.compose(MethodHandles.guardWithTest(binder.bindTest(checkGuard), + binder.bind(invocation), nextComponent.getGuardedInvocation().getInvocation()), gi.getGuard(), + gic.getValidatorClass(), gic.getValidationType()); + } + } + + private static MethodHandle GET_ARRAY_LENGTH = Lookup.PUBLIC.findStatic(Array.class, "getLength", + MethodType.methodType(int.class, Object.class)); + + private static MethodHandle GET_COLLECTION_LENGTH = Lookup.PUBLIC.findVirtual(Collection.class, "size", + MethodType.methodType(int.class)); + + private static MethodHandle GET_MAP_LENGTH = Lookup.PUBLIC.findVirtual(Map.class, "size", + MethodType.methodType(int.class)); + + private static MethodHandle COLLECTION_GUARD = Guards.getInstanceOfGuard(Collection.class); + + private GuardedInvocationComponent getLengthGetter(CallSiteDescriptor callSiteDescriptor) { + assertParameterCount(callSiteDescriptor, 1); + final MethodType callSiteType = callSiteDescriptor.getMethodType(); + final Class declaredType = callSiteType.parameterType(0); + // If declared type of receiver at the call site is already an array, collection, or map, bind without guard. + // Thing is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance + // they're dealing with an array, collection, or map, but hey... + if(declaredType.isArray()) { + return new GuardedInvocationComponent(GET_ARRAY_LENGTH.asType(callSiteType)); + } else if(Collection.class.isAssignableFrom(declaredType)) { + return new GuardedInvocationComponent(GET_COLLECTION_LENGTH.asType(callSiteType)); + } else if(Map.class.isAssignableFrom(declaredType)) { + return new GuardedInvocationComponent(GET_MAP_LENGTH.asType(callSiteType)); + } + + // Otherwise, create a binding based on the actual type of the argument with an appropriate guard. + if(clazz.isArray()) { + return new GuardedInvocationComponent(GET_ARRAY_LENGTH.asType(callSiteType), Guards.isArray(0, + callSiteType), ValidationType.IS_ARRAY); + } if(Collection.class.isAssignableFrom(clazz)) { + return new GuardedInvocationComponent(GET_COLLECTION_LENGTH.asType(callSiteType), Guards.asType( + COLLECTION_GUARD, callSiteType), Collection.class, ValidationType.INSTANCE_OF); + } if(Map.class.isAssignableFrom(clazz)) { + return new GuardedInvocationComponent(GET_MAP_LENGTH.asType(callSiteType), Guards.asType(MAP_GUARD, + callSiteType), Map.class, ValidationType.INSTANCE_OF); + } + // Can't retrieve length for objects that are neither arrays, nor collections, nor maps. + return null; + } + + private static void assertParameterCount(CallSiteDescriptor descriptor, int paramCount) { + if(descriptor.getMethodType().parameterCount() != paramCount) { + throw new BootstrapMethodError(descriptor.getName() + " must have exactly " + paramCount + " parameters."); + } + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java b/nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java new file mode 100644 index 00000000000..b372a7f26a0 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java @@ -0,0 +1,180 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.beans.BeanInfo; +import java.lang.invoke.MethodHandles; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.DynamicLinkerFactory; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; + + +/** + * A linker for POJOs. Normally used as the ultimate fallback linker by the {@link DynamicLinkerFactory} so it is given + * the chance to link calls to all objects that no other language runtime recognizes. Specifically, this linker will: + *
        + *
      • expose all public methods of form {@code setXxx()}, {@code getXxx()}, and {@code isXxx()} as property setters and + * getters for {@code dyn:setProp} and {@code dyn:getProp} operations;
      • + *
      • expose all property getters and setters declared by the class' {@link BeanInfo};
      • + *
      • expose all public methods and methods declared by the class' {@link BeanInfo} for invocation through + * {@code dyn:callMethod} operation;
      • + *
      • expose all public methods and methods declared by the class' {@link BeanInfo} for retrieval for + * {@code dyn:getMethod} operation; the methods thus retrieved can then be invoked using {@code dyn:call};
      • + *
      • expose all public fields as properties, unless there are getters or setters for the properties of the same name;
      • + *
      • expose {@code dyn:getLength}, {@code dyn:getElem} and {@code dyn:setElem} on native Java arrays, as well as + * {@link java.util.List} and {@link java.util.Map} objects; ({@code dyn:getLength} works on any + * {@link java.util.Collection});
      • + *
      • expose a virtual property named {@code length} on Java arrays;
      • + *
      • expose {@code dyn:new} on instances of {@link StaticClass} as calls to constructors, including those static class + * objects that represent Java arrays (their constructors take a single {@code int} parameter representing the length of + * the array to create);
      • + *
      • expose static methods, fields, and properties of classes in a similar manner to how instance method, fields, and + * properties are exposed, on {@link StaticClass} objects.
      • + *
      • expose a virtual property named {@code static} on instances of {@link java.lang.Class} to access their + * {@link StaticClass}.
      • + *
      + *

      Overloaded method resolution is performed automatically for property setters, methods, and + * constructors. Additionally, manual overloaded method selection is supported by having a call site specify a name for + * a method that contains an explicit signature, i.e. {@code dyn:getMethod:parseInt(String,int)}. You can use + * non-qualified class names in such signatures regardless of those classes' packages, they will match any class with + * the same non-qualified name. You only have to use a fully qualified class name in case non-qualified class names + * would cause selection ambiguity (that is extremely rare).

      + *

      Variable argument invocation is handled for both methods and constructors.

      + *

      Currently, only public fields and methods are supported. Any Lookup objects passed in the + * {@link LinkRequest}s are ignored and {@link MethodHandles#publicLookup()} is used instead.

      + * + * @author Attila Szegedi + */ +public class BeansLinker implements GuardingDynamicLinker { + private static final ClassValue linkers = new ClassValue() { + @Override + protected TypeBasedGuardingDynamicLinker computeValue(Class clazz) { + // If ClassValue.put() were public, we could just pre-populate with these known mappings... + return + clazz == Class.class ? new ClassLinker() : + clazz == StaticClass.class ? new StaticClassLinker() : + DynamicMethod.class.isAssignableFrom(clazz) ? new DynamicMethodLinker() : + new BeanLinker(clazz); + } + }; + + /** + * Creates a new POJO linker. + */ + public BeansLinker() { + } + + /** + * Returns a bean linker for a particular single class. Useful when you need to override or extend the behavior of + * linking for some classes in your language runtime's linker, but still want to delegate to the default behavior in + * some cases. + * @param clazz the class + * @return a bean linker for that class + */ + public static TypeBasedGuardingDynamicLinker getLinkerForClass(Class clazz) { + return linkers.get(clazz); + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest request, final LinkerServices linkerServices) + throws Exception { + final CallSiteDescriptor callSiteDescriptor = request.getCallSiteDescriptor(); + final int l = callSiteDescriptor.getNameTokenCount(); + // All names conforming to the dynalang MOP should have at least two tokens, the first one being "dyn" + if(l < 2 || "dyn" != callSiteDescriptor.getNameToken(CallSiteDescriptor.SCHEME)) { + return null; + } + + final Object receiver = request.getReceiver(); + if(receiver == null) { + // Can't operate on null + return null; + } + return getLinkerForClass(receiver.getClass()).getGuardedInvocation(request, linkerServices); + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/beans/CheckRestrictedPackage.java b/nashorn/src/jdk/internal/dynalink/beans/CheckRestrictedPackage.java new file mode 100644 index 00000000000..6c877a4d5d6 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/CheckRestrictedPackage.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.reflect.Modifier; + +/** + * A utility class to check whether a given class is in a package with restricted access e.g. "sun.*" etc. See + * {@link CheckRestrictedPackageInternal} for implementation details. + */ +class CheckRestrictedPackage { + /** + * Returns true if the class is either not public, or it resides in a package with restricted access. + * @param clazz the class to test + * @return true if the class is either not public, or it resides in a package with restricted access. + */ + static boolean isRestrictedClass(Class clazz) { + return !Modifier.isPublic(clazz.getModifiers()) || + (System.getSecurityManager() != null && isRestrictedPackage(clazz.getPackage())); + } + + private static boolean isRestrictedPackage(Package pkg) { + // Note: we broke out the actual implementation into CheckRestrictedPackageInternal, so we only load it when + // needed - that is, if we need to check a non-public class with a non-null package, in presence of a security + // manager. + return pkg == null ? false : CheckRestrictedPackageInternal.isRestrictedPackageName(pkg.getName()); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/CheckRestrictedPackageInternal.java b/nashorn/src/jdk/internal/dynalink/beans/CheckRestrictedPackageInternal.java new file mode 100644 index 00000000000..c7401c9febc --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/CheckRestrictedPackageInternal.java @@ -0,0 +1,252 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.Permissions; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; +import java.security.SecureClassLoader; + +/** + * A utility class to check whether a given class is in a package with restricted access e.g. "sun.*". These packages + * are normally listed in the security property "package.access" for most JRE implementations, although we fortunately + * don't rely on it but solely on {@link SecurityManager#checkPackageAccess(String)}). + * + * This class accomplishes the check in a fashion that works reliably even if Dynalink itself (and all the code on the + * stack that led to the invocation) has the permission to access the restricted package. + * + * If Dynalink has a broad set of privileges (notably, it is loaded from boot or extension class path), then it loads + * the {@link RestrictedPackageTester} class into a isolated secure class loader that gives it no permissions + * whatsoever, and uses this completely unprivileged class to subsequently invoke + * {@link SecurityManager#checkPackageAccess(String)}. This will reliably throw a {@link SecurityException} for every + * restricted package even if Dynalink and other code on the stack have the requisite {@code "accessClassInPackage.*"} + * {@link RuntimePermission} privilege. + * + * On the other hand, if Dynalink does not have a broad set of privileges normally granted by the boot or extension + * class path, it will probably lack the privilege to create a new secure class loader into which to load the tester + * class. In this case, it will invoke {@link SecurityManager#checkPackageAccess(String)} itself with the reasoning that + * it will also be sufficient to discover whether a package is restricted or not. + * + * The rationale for this design is that if Dynalink is running as part of a privileged classpath - boot or extension + * class path, it will have all privileges, so a security manager's package access check might succeed if all other code + * on the stack when requesting linking with a particular restricted class is also privileged. A subsequent linking + * request from less privileged code would then also succeed in requesting methods in privileged package. On the other + * hand, if Dynalink is privileged, it will be able to delegate the package access check to the unprivileged class and + * narrow the access based on its result. Finally, if Dynalink itself is unprivileged, it will not be able to load the + * unprivileged class, but then it will also fail the security manager's package access. + * + * With this design, Dynalink effectively restrains itself from giving unauthorized access to restricted packages from + * classes doing the linking in case it itself has access to those packages. The only way to defeat it would be to + * selectively give Dynalink some {@code "accessClassInPackage.*"} permissions while denying it the privilege to + * manipulate class loaders. + */ +class CheckRestrictedPackageInternal { + private static final MethodHandle PACKAGE_ACCESS_CHECK = getPackageAccessCheckMethod(); + private static final String TESTER_CLASS_NAME = "jdk.internal.dynalink.beans.RestrictedPackageTester"; + + /** + * Returns true if the specified package has restricted access. + * @param pkgName the name of the package to check. + * @return true if the specified package has restricted access, false otherwise. + * @throws NullPointerException if pkgName is null, or if there is {@link System#getSecurityManager()} returns null + * as this method is only expected to be invoked in the presence of a security manager. + */ + static boolean isRestrictedPackageName(String pkgName) { + try { + if(PACKAGE_ACCESS_CHECK != null) { + // If we were able to load our unprivileged tester class, use it to check package access + try { + PACKAGE_ACCESS_CHECK.invokeExact(pkgName); + } catch(Error|RuntimeException e) { + throw e; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } else { + // If we didn't have sufficient permissions to load our unprivileged tester class, we're definitely not + // running in a privileged class path, so invoking SecurityManager.checkPackageAccess() directly should + // have the same effect as going through an unprivileged tester. + System.getSecurityManager().checkPackageAccess(pkgName); + } + return false; + } catch(SecurityException e) { + return true; + } + } + + private static MethodHandle getPackageAccessCheckMethod() { + try { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public MethodHandle run() { + return getPackageAccessCheckMethodInternal(); + } + }); + } catch(SecurityException e) { + // We don't have sufficient privileges to load our tester class into a separate protection domain, so just + // return null so isRestrictedPackageName() will default to itself invoking + // SecurityManager.checkPackageAccess(). + return null; + } + } + + static MethodHandle getPackageAccessCheckMethodInternal() { + try { + // Can't use MethodHandles.lookup().findStatic() -- even though both this class and the loaded class are in + // the same package, findStatic() will throw an IllegalAccessException since they have different class + // loaders. That's why we have to use unreflect with a setAccessible(true)... + final Method m = getTesterClass().getDeclaredMethod("checkPackageAccess", String.class); + m.setAccessible(true); + return MethodHandles.lookup().unreflect(m); + } catch(IllegalAccessException|NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + private static Class getTesterClass() { + final ClassLoader loader = getTesterClassLoader(); + try { + final Class checkerClass = Class.forName(TESTER_CLASS_NAME, true, loader); + // Sanity check to ensure we didn't accidentally pick up the class from elsewhere + if(checkerClass.getClassLoader() != loader) { + throw new AssertionError(TESTER_CLASS_NAME + " was loaded from a different class loader"); + } + return checkerClass; + } catch(ClassNotFoundException e) { + throw new AssertionError(e); + } + } + + private static ClassLoader getTesterClassLoader() { + // We deliberately override loadClass instead of findClass so that we don't give a chance to finding this + // class already loaded anywhere else. Not that there's a big possibility for this, especially since the parent + // class loader is the bootstrap class loader, but still... + return new SecureClassLoader(null) { + + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if(name.equals(TESTER_CLASS_NAME)) { + final byte[] bytes = getTesterClassBytes(); + // Define the class with a protection domain that grants no permissions. + Class clazz = defineClass(name, bytes, 0, bytes.length, new ProtectionDomain(null, + new Permissions())); + if(resolve) { + resolveClass(clazz); + } + return clazz; + } else { + return super.loadClass(name, resolve); + } + } + }; + } + + private static byte[] getTesterClassBytes() { + try { + final InputStream in = CheckRestrictedPackage.class.getResourceAsStream("RestrictedPackageTester.class"); + try { + final ByteArrayOutputStream out = new ByteArrayOutputStream(2048); + for(;;) { + final int b = in.read(); + if(b == -1) { + break; + } + out.write(b); + } + return out.toByteArray(); + } finally { + in.close(); + } + } catch(IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/ClassLinker.java b/nashorn/src/jdk/internal/dynalink/beans/ClassLinker.java new file mode 100644 index 00000000000..6b7f17deaae --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/ClassLinker.java @@ -0,0 +1,110 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType; +import jdk.internal.dynalink.support.Lookup; + + +/** + * A linker for java.lang.Class objects. Provides a synthetic property "static" that allows access to static fields and + * methods on the class (respecting property getter/setter conventions). Note that Class objects are not recognized by + * the Dynalink as constructors for the instances of the class, {@link StaticClass} is used for this purpose. + * @author Attila Szegedi + */ +class ClassLinker extends BeanLinker { + + ClassLinker() { + super(Class.class); + // Map "classObject.static" to StaticClass.forClass(classObject). Can use EXACT_CLASS since class Class is final. + setPropertyGetter("static", FOR_CLASS, ValidationType.EXACT_CLASS); + } + + private static final MethodHandle FOR_CLASS = new Lookup(MethodHandles.lookup()).findStatic(StaticClass.class, + "forClass", MethodType.methodType(StaticClass.class, Class.class)); + +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/beans/ClassString.java b/nashorn/src/jdk/internal/dynalink/beans/ClassString.java new file mode 100644 index 00000000000..9fd3b1eba8f --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/ClassString.java @@ -0,0 +1,209 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.LinkedList; +import java.util.List; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.Guards; +import jdk.internal.dynalink.support.TypeUtilities; + + +/** + * + * @author Attila Szegedi + */ +final class ClassString { + private final Class[] classes; + private int hashCode; + + ClassString(Class[] classes) { + this.classes = classes; + } + + ClassString(MethodType type) { + this(type.parameterArray()); + } + + Class[] getClasses() { + return classes; + } + + @Override + public boolean equals(Object other) { + if(!(other instanceof ClassString)) { + return false; + } + final Class[] otherClasses = ((ClassString)other).classes; + if(otherClasses.length != classes.length) { + return false; + } + for(int i = 0; i < otherClasses.length; ++i) { + if(otherClasses[i] != classes[i]) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + if(hashCode == 0) { + int h = 0; + for(int i = 0; i < classes.length; ++i) { + h ^= classes[i].hashCode(); + } + hashCode = h; + } + return hashCode; + } + + boolean isVisibleFrom(final ClassLoader classLoader) { + for(int i = 0; i < classes.length; ++i) { + if(!Guards.canReferenceDirectly(classLoader, classes[i].getClassLoader())) { + return false; + } + } + return true; + } + + List getMaximallySpecifics(List methods, LinkerServices linkerServices, boolean varArg) { + return MaximallySpecific.getMaximallySpecificMethods(getApplicables(methods, linkerServices, varArg), varArg, + classes, linkerServices); + } + + /** + * Returns all methods that are applicable to actual parameter classes represented by this ClassString object. + */ + LinkedList getApplicables(List methods, LinkerServices linkerServices, boolean varArg) { + final LinkedList list = new LinkedList<>(); + for(final MethodHandle member: methods) { + if(isApplicable(member, linkerServices, varArg)) { + list.add(member); + } + } + return list; + } + + /** + * Returns true if the supplied method is applicable to actual parameter classes represented by this ClassString + * object. + * + */ + private boolean isApplicable(MethodHandle method, LinkerServices linkerServices, boolean varArg) { + final Class[] formalTypes = method.type().parameterArray(); + final int cl = classes.length; + final int fl = formalTypes.length - (varArg ? 1 : 0); + if(varArg) { + if(cl < fl) { + return false; + } + } else { + if(cl != fl) { + return false; + } + } + // Starting from 1 as we ignore the receiver type + for(int i = 1; i < fl; ++i) { + if(!canConvert(linkerServices, classes[i], formalTypes[i])) { + return false; + } + } + if(varArg) { + final Class varArgType = formalTypes[fl].getComponentType(); + for(int i = fl; i < cl; ++i) { + if(!canConvert(linkerServices, classes[i], varArgType)) { + return false; + } + } + } + return true; + } + + private static boolean canConvert(LinkerServices ls, Class from, Class to) { + return ls == null ? TypeUtilities.isMethodInvocationConvertible(from, to) : ls.canConvert(from, to); + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/beans/DynamicMethod.java b/nashorn/src/jdk/internal/dynalink/beans/DynamicMethod.java new file mode 100644 index 00000000000..a4edeeef800 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/DynamicMethod.java @@ -0,0 +1,169 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.StringTokenizer; +import jdk.internal.dynalink.linker.LinkerServices; + + +/** + * Represents a single dynamic method. A "dynamic" method can be bound to a single Java method, or can be bound to all + * overloaded methods of the same name on a class. Getting an invocation of a dynamic method bound to multiple + * overloaded methods will perform overload resolution (actually, it will perform partial overloaded resolution at link + * time, but if that fails to identify exactly one target method, it will generate a method handle that will perform the + * rest of the overload resolution at invocation time for actual argument types). + * + * @author Attila Szegedi + */ +abstract class DynamicMethod { + private final String name; + + DynamicMethod(String name) { + this.name = name; + } + + String getName() { + return name; + } + + /** + * Creates an invocation for the dynamic method. If the method is overloaded, it will perform overloaded method + * resolution based on the specified method type. The resulting resolution can either identify a single method to be + * invoked among the overloads, or it can identify multiple ones. In the latter case, the returned method handle + * will perform further overload resolution among these candidates at every invocation. If the method to be invoked + * is a variable arguments (vararg) method, it will pack the extra arguments in an array before the invocation of + * the underlying method if it is not already done. + * + * @param callSiteType the method type at a call site + * @param linkerServices linker services. Used for language-specific type conversions. + * @return an invocation suitable for calling the method from the specified call site. + */ + abstract MethodHandle getInvocation(MethodType callSiteType, LinkerServices linkerServices); + + /** + * Returns a simple dynamic method representing a single underlying Java method (possibly selected among several + * overloads) with formal parameter types exactly matching the passed signature. + * @param paramTypes the comma-separated list of requested parameter type names. The names will match both + * qualified and unqualified type names. + * @return a simple dynamic method representing a single underlying Java method, or null if none of the Java methods + * behind this dynamic method exactly match the requested parameter types. + */ + abstract SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes); + + /** + * True if this dynamic method already contains a method handle with an identical signature as the passed in method + * handle. + * @param mh the method handle to check + * @return true if it already contains an equivalent method handle. + */ + abstract boolean contains(MethodHandle mh); + + static boolean typeMatchesDescription(String paramTypes, MethodType type) { + final StringTokenizer tok = new StringTokenizer(paramTypes, ", "); + for(int i = 1; i < type.parameterCount(); ++i) { // i = 1 as we ignore the receiver + if(!(tok.hasMoreTokens() && typeNameMatches(tok.nextToken(), type.parameterType(i)))) { + return false; + } + } + return !tok.hasMoreTokens(); + } + + private static boolean typeNameMatches(String typeName, Class type) { + final int lastDot = typeName.lastIndexOf('.'); + final String fullTypeName = type.getCanonicalName(); + return lastDot != -1 && fullTypeName.endsWith(typeName.substring(lastDot)) || typeName.equals(fullTypeName); + } + + static String getClassAndMethodName(Class clazz, String name) { + final String clazzName = clazz.getCanonicalName(); + return (clazzName == null ? clazz.getName() : clazzName) + "." + name; + } + + @Override + public String toString() { + return "[" + getClass().getName() + " " + getName() + "]"; + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java b/nashorn/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java new file mode 100644 index 00000000000..d1994553c89 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java @@ -0,0 +1,130 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.Guards; + + +/** + * Simple linker that implements the "dyn:call" operation for {@link DynamicMethod} objects - the objects returned by + * "dyn:getMethod" from {@link AbstractJavaLinker}. + */ +class DynamicMethodLinker implements TypeBasedGuardingDynamicLinker { + @Override + public boolean canLinkType(Class type) { + return DynamicMethod.class.isAssignableFrom(type); + }; + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, LinkerServices linkerServices) { + final Object receiver = linkRequest.getReceiver(); + if(!(receiver instanceof DynamicMethod)) { + return null; + } + final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor(); + if(desc.getNameTokenCount() != 2 && desc.getNameToken(CallSiteDescriptor.SCHEME) != "dyn") { + return null; + } + final String operator = desc.getNameToken(CallSiteDescriptor.OPERATOR); + if(operator == "call") { + final MethodType type = desc.getMethodType(); + final MethodHandle invocation = ((DynamicMethod)receiver).getInvocation(type.dropParameterTypes(0, 1), + linkerServices); + if(invocation == null) { + return null; + } + return new GuardedInvocation(MethodHandles.dropArguments(invocation, 0, type.parameterType(0)), + Guards.getIdentityGuard(receiver)); + } + return null; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java b/nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java new file mode 100644 index 00000000000..2002c4da552 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java @@ -0,0 +1,188 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import jdk.internal.dynalink.support.Lookup; + + +/** + * Base for classes that expose class field and method information to an {@link AbstractJavaLinker}. There are + * subclasses for instance (bean) and static facet of a class. + * @author Attila Szegedi + */ +abstract class FacetIntrospector implements AutoCloseable { + private final Class clazz; + private final boolean instance; + private final boolean isRestricted; + + protected final AccessibleMembersLookup membersLookup; + + FacetIntrospector(Class clazz, boolean instance) { + this.clazz = clazz; + this.instance = instance; + isRestricted = CheckRestrictedPackage.isRestrictedClass(clazz); + membersLookup = new AccessibleMembersLookup(clazz, instance); + } + + /** + * Returns getters for inner classes. + * @return getters for inner classes. + */ + abstract Map getInnerClassGetters(); + + /** + * Returns the fields for the class facet. + * @return the fields for the class facet. + */ + Collection getFields() { + if(isRestricted) { + // NOTE: we can't do anything here. Unlike with methods in AccessibleMethodsLookup, we can't just return + // the fields from a public superclass, because this class might define same-named fields which will shadow + // the superclass fields, and we have no way to know if they do, since we're denied invocation of + // getFields(). Therefore, the only correct course of action is to not expose any public fields from a class + // defined in a restricted package. + return Collections.emptySet(); + } + + final Field[] fields = clazz.getFields(); + final Collection cfields = new ArrayList<>(fields.length); + for(Field field: fields) { + if(instance != Modifier.isStatic(field.getModifiers()) && isAccessible(field)) { + cfields.add(field); + } + } + return cfields; + } + + boolean isAccessible(Member m) { + final Class declaring = m.getDeclaringClass(); + // (declaring == clazz) is just an optimization - we're calling this only from code that operates on a + // non-restriced class, so if the declaring class is identical to the class being inspected, then forego + // a potentially expensive restricted-package check. + return declaring == clazz || !CheckRestrictedPackage.isRestrictedClass(declaring); + } + + /** + * Returns all the methods in the facet. + * @return all the methods in the facet. + */ + Collection getMethods() { + return membersLookup.getMethods(); + } + + + MethodHandle unreflectGetter(Field field) { + return editMethodHandle(Lookup.PUBLIC.unreflectGetter(field)); + } + + MethodHandle unreflectSetter(Field field) { + return editMethodHandle(Lookup.PUBLIC.unreflectSetter(field)); + } + + MethodHandle unreflect(Method method) { + return editMethodHandle(Lookup.PUBLIC.unreflect(method)); + } + + /** + * Returns an edited method handle. A facet might need to edit an unreflected method handle before it is usable with + * the facet. By default, returns the passed method handle unchanged. The class' static facet will introduce a + * dropArguments. + * @param mh the method handle to edit. + * @return the edited method handle. + */ + abstract MethodHandle editMethodHandle(MethodHandle mh); + + @Override + public void close() { + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/beans/GuardedInvocationComponent.java b/nashorn/src/jdk/internal/dynalink/beans/GuardedInvocationComponent.java new file mode 100644 index 00000000000..11d5929b45d --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/GuardedInvocationComponent.java @@ -0,0 +1,251 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import jdk.internal.dynalink.linker.GuardedInvocation; + + +/** + * Represents one component for a GuardedInvocation of a potentially composite operation of an + * {@link AbstractJavaLinker}. In addition to holding a guarded invocation, it holds semantic information about its + * guard. All guards produced in the AbstractJavaLinker are either "Class.isInstance()" or "getClass() == clazz" + * expressions. This allows choosing the most restrictive guard as the guard for the composition of two components. + * @author Attila Szegedi + * @version $Id: $ + */ +class GuardedInvocationComponent { + enum ValidationType { + NONE, // No guard; the operation can be linked unconditionally (quite rare); least strict. + INSTANCE_OF, // "validatorClass.isInstance(obj)" guard + EXACT_CLASS, // "obj.getClass() == validatorClass" guard; most strict. + IS_ARRAY, // "obj.getClass().isArray()" + } + + private final GuardedInvocation guardedInvocation; + private final Validator validator; + + GuardedInvocationComponent(MethodHandle invocation) { + this(invocation, null, ValidationType.NONE); + } + + GuardedInvocationComponent(MethodHandle invocation, MethodHandle guard, ValidationType validationType) { + this(invocation, guard, null, validationType); + } + + GuardedInvocationComponent(MethodHandle invocation, MethodHandle guard, Class validatorClass, + ValidationType validationType) { + this(invocation, guard, new Validator(validatorClass, validationType)); + } + + GuardedInvocationComponent(GuardedInvocation guardedInvocation, Class validatorClass, + ValidationType validationType) { + this(guardedInvocation, new Validator(validatorClass, validationType)); + } + + GuardedInvocationComponent replaceInvocation(MethodHandle newInvocation) { + return replaceInvocation(newInvocation, guardedInvocation.getGuard()); + } + + GuardedInvocationComponent replaceInvocation(MethodHandle newInvocation, MethodHandle newGuard) { + return new GuardedInvocationComponent(guardedInvocation.replaceMethods(newInvocation, + newGuard), validator); + } + + private GuardedInvocationComponent(MethodHandle invocation, MethodHandle guard, Validator validator) { + this(new GuardedInvocation(invocation, guard), validator); + } + + private GuardedInvocationComponent(GuardedInvocation guardedInvocation, Validator validator) { + this.guardedInvocation = guardedInvocation; + this.validator = validator; + } + + GuardedInvocation getGuardedInvocation() { + return guardedInvocation; + } + + Class getValidatorClass() { + return validator.validatorClass; + } + + ValidationType getValidationType() { + return validator.validationType; + } + + GuardedInvocationComponent compose(MethodHandle compositeInvocation, MethodHandle otherGuard, + Class otherValidatorClass, ValidationType otherValidationType) { + final Validator compositeValidator = validator.compose(new Validator(otherValidatorClass, otherValidationType)); + final MethodHandle compositeGuard = compositeValidator == validator ? guardedInvocation.getGuard() : otherGuard; + return new GuardedInvocationComponent(compositeInvocation, compositeGuard, compositeValidator); + } + + private static class Validator { + /*private*/ final Class validatorClass; + /*private*/ final ValidationType validationType; + + Validator(Class validatorClass, ValidationType validationType) { + this.validatorClass = validatorClass; + this.validationType = validationType; + } + + Validator compose(Validator other) { + if(other.validationType == ValidationType.NONE) { + return this; + } + switch(validationType) { + case NONE: + return other; + case INSTANCE_OF: + switch(other.validationType) { + case INSTANCE_OF: + if(isAssignableFrom(other)) { + return other; + } else if(other.isAssignableFrom(this)) { + return this; + } + break; + case EXACT_CLASS: + if(isAssignableFrom(other)) { + return other; + } + break; + case IS_ARRAY: + if(validatorClass.isArray()) { + return this; + } + break; + case NONE: + throw new AssertionError(); // Not possible + } + break; + case EXACT_CLASS: + switch(other.validationType) { + case INSTANCE_OF: + if(other.isAssignableFrom(this)) { + return this; + } + break; + case EXACT_CLASS: + if(validatorClass == other.validatorClass) { + return this; + } + break; + case IS_ARRAY: + if(validatorClass.isArray()) { + return this; + } + break; + case NONE: + throw new AssertionError(); // Not possible + } + break; + case IS_ARRAY: + switch(other.validationType) { + case INSTANCE_OF: + case EXACT_CLASS: + if(other.validatorClass.isArray()) { + return other; + } + break; + case IS_ARRAY: + return this; + case NONE: + throw new AssertionError(); // Not possible + } + break; + } + throw new AssertionError("Incompatible composition " + this + " vs " + other); + } + + private boolean isAssignableFrom(Validator other) { + return validatorClass.isAssignableFrom(other.validatorClass); + } + + @Override + public String toString() { + return "Validator[" + validationType + (validatorClass == null ? "" : (" " + validatorClass.getName())) + "]"; + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/MaximallySpecific.java b/nashorn/src/jdk/internal/dynalink/beans/MaximallySpecific.java new file mode 100644 index 00000000000..9366abdc0db --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/MaximallySpecific.java @@ -0,0 +1,211 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import jdk.internal.dynalink.linker.ConversionComparator.Comparison; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.TypeUtilities; + + +/** + * Utility class that encapsulates the algorithm for choosing the maximally specific methods. + * + * @author Attila Szegedi + */ +class MaximallySpecific { + /** + * Given a list of methods, returns a list of maximally specific methods. + * + * @param methods the list of methods + * @param varArgs whether to assume the methods are varargs + * @return the list of maximally specific methods. + */ + static List getMaximallySpecificMethods(List methods, boolean varArgs) { + return getMaximallySpecificMethods(methods, varArgs, null, null); + } + + /** + * Given a list of methods, returns a list of maximally specific methods, applying language-runtime specific + * conversion preferences. + * + * @param methods the list of methods + * @param varArgs whether to assume the methods are varargs + * @param argTypes concrete argument types for the invocation + * @return the list of maximally specific methods. + */ + static List getMaximallySpecificMethods(List methods, boolean varArgs, + Class[] argTypes, LinkerServices ls) { + if(methods.size() < 2) { + return methods; + } + final LinkedList maximals = new LinkedList<>(); + for(MethodHandle m: methods) { + final MethodType methodType = m.type(); + boolean lessSpecific = false; + for(Iterator maximal = maximals.iterator(); maximal.hasNext();) { + final MethodHandle max = maximal.next(); + switch(isMoreSpecific(methodType, max.type(), varArgs, argTypes, ls)) { + case TYPE_1_BETTER: { + maximal.remove(); + break; + } + case TYPE_2_BETTER: { + lessSpecific = true; + break; + } + case INDETERMINATE: { + // do nothing + } + } + } + if(!lessSpecific) { + maximals.addLast(m); + } + } + return maximals; + } + + private static Comparison isMoreSpecific(MethodType t1, MethodType t2, boolean varArgs, Class[] argTypes, + LinkerServices ls) { + final int pc1 = t1.parameterCount(); + final int pc2 = t2.parameterCount(); + assert varArgs || (pc1 == pc2) && (argTypes == null || argTypes.length == pc1); + assert (argTypes == null) == (ls == null); + final int maxPc = Math.max(Math.max(pc1, pc2), argTypes == null ? 0 : argTypes.length); + boolean t1MoreSpecific = false; + boolean t2MoreSpecific = false; + // NOTE: Starting from 1 as overloaded method resolution doesn't depend on 0th element, which is the type of + // 'this'. We're only dealing with instance methods here, not static methods. Actually, static methods will have + // a fake 'this' of type StaticClass. + for(int i = 1; i < maxPc; ++i) { + final Class c1 = getParameterClass(t1, pc1, i, varArgs); + final Class c2 = getParameterClass(t2, pc2, i, varArgs); + if(c1 != c2) { + final Comparison cmp = compare(c1, c2, argTypes, i, ls); + if(cmp == Comparison.TYPE_1_BETTER && !t1MoreSpecific) { + t1MoreSpecific = true; + if(t2MoreSpecific) { + return Comparison.INDETERMINATE; + } + } + if(cmp == Comparison.TYPE_2_BETTER && !t2MoreSpecific) { + t2MoreSpecific = true; + if(t1MoreSpecific) { + return Comparison.INDETERMINATE; + } + } + } + } + if(t1MoreSpecific) { + return Comparison.TYPE_1_BETTER; + } else if(t2MoreSpecific) { + return Comparison.TYPE_2_BETTER; + } + return Comparison.INDETERMINATE; + } + + private static Comparison compare(Class c1, Class c2, Class[] argTypes, int i, LinkerServices cmp) { + if(cmp != null) { + final Comparison c = cmp.compareConversion(argTypes[i], c1, c2); + if(c != Comparison.INDETERMINATE) { + return c; + } + } + if(TypeUtilities.isSubtype(c1, c2)) { + return Comparison.TYPE_1_BETTER; + } if(TypeUtilities.isSubtype(c2, c1)) { + return Comparison.TYPE_2_BETTER; + } + return Comparison.INDETERMINATE; + } + + private static Class getParameterClass(MethodType t, int l, int i, boolean varArgs) { + return varArgs && i >= l - 1 ? t.parameterType(l - 1).getComponentType() : t.parameterType(i); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java b/nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java new file mode 100644 index 00000000000..a3bb21ddbf1 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java @@ -0,0 +1,313 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import jdk.internal.dynalink.beans.ApplicableOverloadedMethods.ApplicabilityTest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.TypeUtilities; + + +/** + * Represents an overloaded method. + * + * @author Attila Szegedi + */ +class OverloadedDynamicMethod extends DynamicMethod { + /** + * Holds a list of all methods. + */ + private final LinkedList methods; + private final ClassLoader classLoader; + + /** + * Creates a new overloaded dynamic method. + * + * @param clazz the class this method belongs to + * @param name the name of the method + */ + OverloadedDynamicMethod(Class clazz, String name) { + this(new LinkedList(), clazz.getClassLoader(), getClassAndMethodName(clazz, name)); + } + + private OverloadedDynamicMethod(LinkedList methods, ClassLoader classLoader, String name) { + super(name); + this.methods = methods; + this.classLoader = classLoader; + } + + @Override + SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes) { + final LinkedList matchingMethods = new LinkedList<>(); + for(MethodHandle method: methods) { + if(typeMatchesDescription(paramTypes, method.type())) { + matchingMethods.add(method); + } + } + switch(matchingMethods.size()) { + case 0: { + return null; + } + case 1: { + final MethodHandle target = matchingMethods.get(0); + return new SimpleDynamicMethod(target, SimpleDynamicMethod.getMethodNameWithSignature(target, getName())); + } + default: { + throw new BootstrapMethodError("Can't choose among " + matchingMethods + " for argument types " + + paramTypes + " for method " + getName()); + } + } + } + + @Override + public MethodHandle getInvocation(final MethodType callSiteType, final LinkerServices linkerServices) { + // First, find all methods applicable to the call site by subtyping (JLS 15.12.2.2) + final ApplicableOverloadedMethods subtypingApplicables = getApplicables(callSiteType, + ApplicableOverloadedMethods.APPLICABLE_BY_SUBTYPING); + // Next, find all methods applicable by method invocation conversion to the call site (JLS 15.12.2.3). + final ApplicableOverloadedMethods methodInvocationApplicables = getApplicables(callSiteType, + ApplicableOverloadedMethods.APPLICABLE_BY_METHOD_INVOCATION_CONVERSION); + // Finally, find all methods applicable by variable arity invocation. (JLS 15.12.2.4). + final ApplicableOverloadedMethods variableArityApplicables = getApplicables(callSiteType, + ApplicableOverloadedMethods.APPLICABLE_BY_VARIABLE_ARITY); + + // Find the methods that are maximally specific based on the call site signature + List maximallySpecifics = subtypingApplicables.findMaximallySpecificMethods(); + if(maximallySpecifics.isEmpty()) { + maximallySpecifics = methodInvocationApplicables.findMaximallySpecificMethods(); + if(maximallySpecifics.isEmpty()) { + maximallySpecifics = variableArityApplicables.findMaximallySpecificMethods(); + } + } + + // Now, get a list of the rest of the methods; those that are *not* applicable to the call site signature based + // on JLS rules. As paradoxical as that might sound, we have to consider these for dynamic invocation, as they + // might match more concrete types passed in invocations. That's why we provisionally call them "invokables". + // This is typical for very generic signatures at call sites. Typical example: call site specifies + // (Object, Object), and we have a method whose parameter types are (String, int). None of the JLS applicability + // rules will trigger, but we must consider the method, as it can be the right match for a concrete invocation. + @SuppressWarnings({ "unchecked", "rawtypes" }) + final List invokables = (List)methods.clone(); + invokables.removeAll(subtypingApplicables.getMethods()); + invokables.removeAll(methodInvocationApplicables.getMethods()); + invokables.removeAll(variableArityApplicables.getMethods()); + for(final Iterator it = invokables.iterator(); it.hasNext();) { + final MethodHandle m = it.next(); + if(!isApplicableDynamically(linkerServices, callSiteType, m)) { + it.remove(); + } + } + + // If no additional methods can apply at invocation time, and there's more than one maximally specific method + // based on call site signature, that is a link-time ambiguity. In a static scenario, javac would report an + // ambiguity error. + if(invokables.isEmpty() && maximallySpecifics.size() > 1) { + throw new BootstrapMethodError("Can't choose among " + maximallySpecifics + " for argument types " + + callSiteType); + } + + // Merge them all. + invokables.addAll(maximallySpecifics); + switch(invokables.size()) { + case 0: { + // No overloads can ever match the call site type + return null; + } + case 1: { + // Very lucky, we ended up with a single candidate method handle based on the call site signature; we + // can link it very simply by delegating to a SimpleDynamicMethod. + final MethodHandle mh = invokables.iterator().next(); + return new SimpleDynamicMethod(mh).getInvocation(callSiteType, linkerServices); + } + } + + // We have more than one candidate. We have no choice but to link to a method that resolves overloads on every + // invocation (alternatively, we could opportunistically link the one method that resolves for the current + // arguments, but we'd need to install a fairly complex guard for that and when it'd fail, we'd go back all the + // way to candidate selection. + // TODO: cache per call site type + return new OverloadedMethod(invokables, this, callSiteType, linkerServices).getInvoker(); + } + + @Override + public boolean contains(MethodHandle mh) { + final MethodType type = mh.type(); + for(MethodHandle method: methods) { + if(typesEqualNoReceiver(type, method.type())) { + return true; + } + } + return false; + } + + private static boolean typesEqualNoReceiver(MethodType type1, MethodType type2) { + final int pc = type1.parameterCount(); + if(pc != type2.parameterCount()) { + return false; + } + for(int i = 1; i < pc; ++i) { // i = 1: ignore receiver + if(type1.parameterType(i) != type2.parameterType(i)) { + return false; + } + } + return true; + } + + ClassLoader getClassLoader() { + return classLoader; + } + + private static boolean isApplicableDynamically(LinkerServices linkerServices, MethodType callSiteType, + MethodHandle m) { + final MethodType methodType = m.type(); + final boolean varArgs = m.isVarargsCollector(); + final int fixedArgLen = methodType.parameterCount() - (varArgs ? 1 : 0); + final int callSiteArgLen = callSiteType.parameterCount(); + if(varArgs) { + if(callSiteArgLen < fixedArgLen) { + return false; + } + } else if(callSiteArgLen != fixedArgLen) { + return false; + } + // Starting from 1, as receiver type doesn't participate + for(int i = 1; i < fixedArgLen; ++i) { + if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), methodType.parameterType(i))) { + return false; + } + } + if(varArgs) { + final Class varArgArrayType = methodType.parameterType(fixedArgLen); + final Class varArgType = varArgArrayType.getComponentType(); + if(fixedArgLen == callSiteArgLen - 1) { + final Class callSiteArgType = callSiteType.parameterType(fixedArgLen); + // Exactly one vararg; check both exact matching and component + // matching. + return isApplicableDynamically(linkerServices, callSiteArgType, varArgArrayType) + || isApplicableDynamically(linkerServices, callSiteArgType, varArgType); + } else { + for(int i = fixedArgLen; i < callSiteArgLen; ++i) { + if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), varArgType)) { + return false; + } + } + return true; + } + } else { + return true; + } + } + + private static boolean isApplicableDynamically(LinkerServices linkerServices, Class callSiteType, + Class methodType) { + return TypeUtilities.isPotentiallyConvertible(callSiteType, methodType) + || linkerServices.canConvert(callSiteType, methodType); + } + + private ApplicableOverloadedMethods getApplicables(MethodType callSiteType, ApplicabilityTest test) { + return new ApplicableOverloadedMethods(methods, callSiteType, test); + } + + /** + * Add a method identified by a {@link SimpleDynamicMethod} to this overloaded method's set. + * + * @param method the method to add. + */ + public void addMethod(SimpleDynamicMethod method) { + addMethod(method.getTarget()); + } + + /** + * Add a method to this overloaded method's set. + * + * @param method a method to add + */ + public void addMethod(MethodHandle method) { + methods.add(method); + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java b/nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java new file mode 100644 index 00000000000..da8e4c3dec6 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java @@ -0,0 +1,266 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.Lookup; + + +/** + * Represents a subset of overloaded methods for a certain method name on a certain class. It can be either a fixarg or + * a vararg subset depending on the subclass. The method is for a fixed number of arguments though (as it is generated + * for a concrete call site). As such, all methods in the subset can be invoked with the specified number of arguments + * (exactly matching for fixargs, or having less than or equal fixed arguments, for varargs). + * + * @author Attila Szegedi + */ +class OverloadedMethod { + private final Map argTypesToMethods = new ConcurrentHashMap<>(); + private final OverloadedDynamicMethod parent; + private final MethodType callSiteType; + private final MethodHandle invoker; + private final LinkerServices linkerServices; + private final ArrayList fixArgMethods; + private final ArrayList varArgMethods; + + OverloadedMethod(List methodHandles, OverloadedDynamicMethod parent, MethodType callSiteType, + LinkerServices linkerServices) { + this.parent = parent; + this.callSiteType = callSiteType; + this.linkerServices = linkerServices; + + fixArgMethods = new ArrayList<>(methodHandles.size()); + varArgMethods = new ArrayList<>(methodHandles.size()); + final int argNum = callSiteType.parameterCount(); + for(MethodHandle mh: methodHandles) { + if(mh.isVarargsCollector()) { + final MethodHandle asFixed = mh.asFixedArity(); + if(argNum == asFixed.type().parameterCount()) { + fixArgMethods.add(asFixed); + } + varArgMethods.add(mh); + } else { + fixArgMethods.add(mh); + } + } + fixArgMethods.trimToSize(); + varArgMethods.trimToSize(); + + final MethodHandle bound = SELECT_METHOD.bindTo(this); + final MethodHandle collecting = SimpleDynamicMethod.collectArguments(bound, argNum).asType( + callSiteType.changeReturnType(MethodHandle.class)); + invoker = MethodHandles.foldArguments(MethodHandles.exactInvoker(callSiteType), collecting); + } + + MethodHandle getInvoker() { + return invoker; + } + + private static final MethodHandle SELECT_METHOD = Lookup.findOwnSpecial(MethodHandles.lookup(), "selectMethod", + MethodHandle.class, Object[].class); + + @SuppressWarnings("unused") + private MethodHandle selectMethod(Object[] args) throws NoSuchMethodException { + final Class[] argTypes = new Class[args.length]; + for(int i = 0; i < argTypes.length; ++i) { + final Object arg = args[i]; + argTypes[i] = arg == null ? callSiteType.parameterType(i) : arg.getClass(); + } + final ClassString classString = new ClassString(argTypes); + MethodHandle method = argTypesToMethods.get(classString); + if(method == null) { + List methods = classString.getMaximallySpecifics(fixArgMethods, linkerServices, false); + if(methods.isEmpty()) { + methods = classString.getMaximallySpecifics(varArgMethods, linkerServices, true); + } + switch(methods.size()) { + case 0: { + method = getNoSuchMethodThrower(argTypes); + break; + } + case 1: { + method = new SimpleDynamicMethod(methods.get(0)).getInvocation(callSiteType, linkerServices); + break; + } + default: { + // This is unfortunate - invocation time ambiguity. We can still save the day if + method = getAmbiguousMethodThrower(argTypes, methods); + break; + } + } + // Avoid keeping references to unrelated classes; this ruins the performance a bit, but avoids class loader + // memory leaks. + if(classString.isVisibleFrom(parent.getClassLoader())) { + argTypesToMethods.put(classString, method); + } + } + return method; + } + + private MethodHandle getNoSuchMethodThrower(Class[] argTypes) { + return adaptThrower(MethodHandles.insertArguments(THROW_NO_SUCH_METHOD, 0, this, argTypes)); + } + + private static final MethodHandle THROW_NO_SUCH_METHOD = Lookup.findOwnSpecial(MethodHandles.lookup(), + "throwNoSuchMethod", void.class, Class[].class); + + @SuppressWarnings("unused") + private void throwNoSuchMethod(Class[] argTypes) throws NoSuchMethodException { + if(varArgMethods.isEmpty()) { + throw new NoSuchMethodException("None of the fixed arity signatures " + getSignatureList(fixArgMethods) + + " of method " + parent.getName() + " match the argument types " + argTypesString(argTypes)); + } + throw new NoSuchMethodException("None of the fixed arity signatures " + getSignatureList(fixArgMethods) + + " or the variable arity signatures " + getSignatureList(varArgMethods) + " of the method " + + parent.getName() + " match the argument types " + argTypesString(argTypes)); + } + + private MethodHandle getAmbiguousMethodThrower(Class[] argTypes, List methods) { + return adaptThrower(MethodHandles.insertArguments(THROW_AMBIGUOUS_METHOD, 0, this, argTypes, methods)); + } + + private MethodHandle adaptThrower(MethodHandle rawThrower) { + return MethodHandles.dropArguments(rawThrower, 0, callSiteType.parameterList()).asType(callSiteType); + } + + private static final MethodHandle THROW_AMBIGUOUS_METHOD = Lookup.findOwnSpecial(MethodHandles.lookup(), + "throwAmbiguousMethod", void.class, Class[].class, List.class); + + @SuppressWarnings("unused") + private void throwAmbiguousMethod(Class[] argTypes, List methods) throws NoSuchMethodException { + final String arity = methods.get(0).isVarargsCollector() ? "variable" : "fixed"; + throw new NoSuchMethodException("Can't unambiguously select between " + arity + " arity signatures " + + getSignatureList(methods) + " of the method " + parent.getName() + " for argument types " + + argTypesString(argTypes)); + } + + private static String argTypesString(Class[] classes) { + final StringBuilder b = new StringBuilder().append('['); + appendTypes(b, classes, false); + return b.append(']').toString(); + } + + private static String getSignatureList(List methods) { + final StringBuilder b = new StringBuilder().append('['); + final Iterator it = methods.iterator(); + if(it.hasNext()) { + appendSig(b, it.next()); + while(it.hasNext()) { + appendSig(b.append(", "), it.next()); + } + } + return b.append(']').toString(); + } + + private static void appendSig(StringBuilder b, MethodHandle m) { + b.append('('); + appendTypes(b, m.type().parameterArray(), m.isVarargsCollector()); + b.append(')'); + } + + private static void appendTypes(StringBuilder b, Class[] classes, boolean varArg) { + final int l = classes.length; + if(!varArg) { + if(l > 1) { + b.append(classes[1].getCanonicalName()); + for(int i = 2; i < l; ++i) { + b.append(", ").append(classes[i].getCanonicalName()); + } + } + } else { + for(int i = 1; i < l - 1; ++i) { + b.append(classes[i].getCanonicalName()).append(", "); + } + b.append(classes[l - 1].getComponentType().getCanonicalName()).append("..."); + } + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/beans/RestrictedPackageTester.java b/nashorn/src/jdk/internal/dynalink/beans/RestrictedPackageTester.java new file mode 100644 index 00000000000..622ddb75365 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/RestrictedPackageTester.java @@ -0,0 +1,113 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * This class is never referenced directly from code of any other class, but is loaded into a secure class loader that + * gives it no permissions whatsoever, so it can be used to reliably test whether a given package has restricted access + * or not. See {@link CheckRestrictedPackageInternal} for details. + * @author Attila Szegedi + * @version $Id: $ + */ +class RestrictedPackageTester implements PrivilegedAction { + + private final String pkgName; + + private RestrictedPackageTester(String pkgName) { + this.pkgName = pkgName; + } + + static void checkPackageAccess(String pkgName) { + AccessController.doPrivileged(new RestrictedPackageTester(pkgName)); + } + + @Override + public Void run() { + System.getSecurityManager().checkPackageAccess(pkgName); + return null; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java b/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java new file mode 100644 index 00000000000..649c0e1edf0 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java @@ -0,0 +1,241 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Array; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.Guards; + + +/** + * A dynamic method bound to exactly one, non-overloaded Java method. Handles varargs. + * + * @author Attila Szegedi + */ +class SimpleDynamicMethod extends DynamicMethod { + private final MethodHandle target; + + /** + * Creates a simple dynamic method with no name. + * @param target the target method handle + */ + SimpleDynamicMethod(MethodHandle target) { + this(target, null); + } + + /** + * Creates a new simple dynamic method, with a name constructed from the class name, method name, and handle + * signature. + * + * @param target the target method handle + * @param clazz the class declaring the method + * @param name the simple name of the method + */ + SimpleDynamicMethod(MethodHandle target, Class clazz, String name) { + this(target, getName(target, clazz, name)); + } + + SimpleDynamicMethod(MethodHandle target, String name) { + super(name); + this.target = target; + } + + private static String getName(MethodHandle target, Class clazz, String name) { + return getMethodNameWithSignature(target, getClassAndMethodName(clazz, name)); + } + + static String getMethodNameWithSignature(MethodHandle target, String methodName) { + final String typeStr = target.type().toString(); + final int retTypeIndex = typeStr.lastIndexOf(')') + 1; + int secondParamIndex = typeStr.indexOf(',') + 1; + if(secondParamIndex == 0) { + secondParamIndex = retTypeIndex - 1; + } + return typeStr.substring(retTypeIndex) + " " + methodName + "(" + typeStr.substring(secondParamIndex, retTypeIndex); + } + + /** + * Returns the target of this dynamic method + * + * @return the target of this dynamic method + */ + MethodHandle getTarget() { + return target; + } + + @Override + SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes) { + return typeMatchesDescription(paramTypes, target.type()) ? this : null; + } + + @Override + MethodHandle getInvocation(MethodType callSiteType, LinkerServices linkerServices) { + final MethodType methodType = target.type(); + final int paramsLen = methodType.parameterCount(); + final boolean varArgs = target.isVarargsCollector(); + final MethodHandle fixTarget = varArgs ? target.asFixedArity() : target; + final int fixParamsLen = varArgs ? paramsLen - 1 : paramsLen; + final int argsLen = callSiteType.parameterCount(); + if(argsLen < fixParamsLen) { + // Less actual arguments than number of fixed declared arguments; can't invoke. + return null; + } + // Method handle of the same number of arguments as the call site type + if(argsLen == fixParamsLen) { + // Method handle that matches the number of actual arguments as the number of fixed arguments + final MethodHandle matchedMethod; + if(varArgs) { + // If vararg, add a zero-length array of the expected type as the last argument to signify no variable + // arguments. + // TODO: check whether collectArguments() would handle this too. + matchedMethod = MethodHandles.insertArguments(fixTarget, fixParamsLen, Array.newInstance( + methodType.parameterType(fixParamsLen).getComponentType(), 0)); + } else { + // Otherwise, just use the method + matchedMethod = fixTarget; + } + return createConvertingInvocation(matchedMethod, linkerServices, callSiteType); + } + + // What's below only works for varargs + if(!varArgs) { + return null; + } + + final Class varArgType = methodType.parameterType(fixParamsLen); + // Handle a somewhat sinister corner case: caller passes exactly one argument in the vararg position, and we + // must handle both a prepacked vararg array as well as a genuine 1-long vararg sequence. + if(argsLen == paramsLen) { + final Class callSiteLastArgType = callSiteType.parameterType(fixParamsLen); + if(varArgType.isAssignableFrom(callSiteLastArgType)) { + // Call site signature guarantees we'll always be passed a single compatible array; just link directly + // to the method. + return createConvertingInvocation(fixTarget, linkerServices, callSiteType); + } else if(!linkerServices.canConvert(callSiteLastArgType, varArgType)) { + // Call site signature guarantees the argument can definitely not be an array (i.e. it is primitive); + // link immediately to a vararg-packing method handle. + return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType); + } else { + // Call site signature makes no guarantees that the single argument in the vararg position will be + // compatible across all invocations. Need to insert an appropriate guard and fall back to generic + // vararg method when it is not. + return MethodHandles.guardWithTest(Guards.isInstance(varArgType, fixParamsLen, callSiteType), + createConvertingInvocation(fixTarget, linkerServices, callSiteType), + createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType)); + } + } else { + // Remaining case: more than one vararg. + return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType); + } + } + + @Override + public boolean contains(MethodHandle mh) { + return target.type().parameterList().equals(mh.type().parameterList()); + } + + /** + * Creates a method handle out of the original target that will collect the varargs for the exact component type of + * the varArg array. Note that this will nicely trigger language-specific type converters for exactly those varargs + * for which it is necessary when later passed to linkerServices.convertArguments(). + * + * @param target the original method handle + * @param parameterCount the total number of arguments in the new method handle + * @return a collecting method handle + */ + static MethodHandle collectArguments(MethodHandle target, final int parameterCount) { + final MethodType methodType = target.type(); + final int fixParamsLen = methodType.parameterCount() - 1; + final Class arrayType = methodType.parameterType(fixParamsLen); + return target.asCollector(arrayType, parameterCount - fixParamsLen); + } + + private static MethodHandle createConvertingInvocation(final MethodHandle sizedMethod, + final LinkerServices linkerServices, final MethodType callSiteType) { + return linkerServices.asType(sizedMethod, callSiteType); + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/beans/StaticClass.java b/nashorn/src/jdk/internal/dynalink/beans/StaticClass.java new file mode 100644 index 00000000000..48f30255f65 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClass.java @@ -0,0 +1,138 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.io.Serializable; + +/** + * Object that represents the static facet of a class (its static methods, properties, and fields, as well as + * construction of instances using "dyn:new"). Objects of this class are recognized by the {@link BeansLinker} as being + * special, and operations on them will be linked against the represented class' static facet. The "class" synthetic + * property is additionally recognized and returns the Java {@link Class} object, as per {@link #getRepresentedClass()} + * method. Conversely, {@link Class} objects exposed through {@link BeansLinker} expose the "static" synthetic property + * which returns an instance of this class. + */ +public class StaticClass implements Serializable { + private static final ClassValue staticClasses = new ClassValue() { + @Override + protected StaticClass computeValue(Class type) { + return new StaticClass(type); + } + }; + + private static final long serialVersionUID = 1L; + + private final Class clazz; + + /*private*/ StaticClass(Class clazz) { + clazz.getClass(); // NPE check + this.clazz = clazz; + } + + /** + * Retrieves the {@link StaticClass} instance for the specified class. + * @param clazz the class for which the static facet is requested. + * @return the {@link StaticClass} instance representing the specified class. + */ + public static StaticClass forClass(Class clazz) { + return staticClasses.get(clazz); + } + + /** + * Returns the represented Java class. + * @return the represented Java class. + */ + public Class getRepresentedClass() { + return clazz; + } + + @Override + public String toString() { + return "JavaClassStatics[" + clazz.getName() + "]"; + } + + private Object readResolve() { + return forClass(clazz); + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java b/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java new file mode 100644 index 00000000000..d4cedb7f284 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.HashMap; +import java.util.Map; + +class StaticClassIntrospector extends FacetIntrospector { + StaticClassIntrospector(Class clazz) { + super(clazz, false); + } + + @Override + Map getInnerClassGetters() { + final Map map = new HashMap<>(); + for(Class innerClass: membersLookup.getInnerClasses()) { + map.put(innerClass.getSimpleName(), editMethodHandle(MethodHandles.constant(StaticClass.class, + StaticClass.forClass(innerClass)))); + } + return map; + } + + @Override + MethodHandle editMethodHandle(MethodHandle mh) { + MethodHandle newHandle = MethodHandles.dropArguments(mh, 0, Object.class); + // NOTE: this is a workaround for the fact that dropArguments doesn't preserve vararg collector state. + if(mh.isVarargsCollector() && !newHandle.isVarargsCollector()) { + final MethodType type = mh.type(); + newHandle = newHandle.asVarargsCollector(type.parameterType(type.parameterCount() - 1)); + } + return newHandle; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java b/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java new file mode 100644 index 00000000000..2c500ea8403 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java @@ -0,0 +1,204 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.List; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.Lookup; + + +/** + * Provides a linker for the {@link StaticClass} objects. + * @author Attila Szegedi + */ +class StaticClassLinker implements TypeBasedGuardingDynamicLinker { + private final ClassValue linkers = new ClassValue() { + @Override + protected GuardingDynamicLinker computeValue(Class clazz) { + return new SingleClassStaticsLinker(clazz); + } + }; + + private static class SingleClassStaticsLinker extends AbstractJavaLinker { + private final DynamicMethod constructor; + + SingleClassStaticsLinker(Class clazz) { + super(clazz, IS_CLASS.bindTo(clazz)); + // Map "staticClassObject.class" to StaticClass.getRepresentedClass(). Some adventurous soul could subclass + // StaticClass, so we use INSTANCE_OF validation instead of EXACT_CLASS. + setPropertyGetter("class", GET_CLASS, ValidationType.INSTANCE_OF); + constructor = createConstructorMethod(clazz); + } + + /** + * Creates a dynamic method containing all overloads of a class' public constructor + * @param clazz the target class + * @return a dynamic method containing all overloads of a class' public constructor. If the class has no public + * constructors, returns null. + */ + private static DynamicMethod createConstructorMethod(Class clazz) { + if(clazz.isArray()) { + final MethodHandle boundArrayCtor = ARRAY_CTOR.bindTo(clazz.getComponentType()); + return new SimpleDynamicMethod(drop(boundArrayCtor.asType(boundArrayCtor.type().changeReturnType( + clazz))), clazz, ""); + } + + final Constructor[] ctrs = clazz.getConstructors(); + final List mhs = new ArrayList<>(ctrs.length); + for(int i = 0; i < ctrs.length; ++i) { + mhs.add(drop(Lookup.PUBLIC.unreflectConstructor(ctrs[i]))); + } + return createDynamicMethod(mhs, clazz, ""); + } + + private static MethodHandle drop(MethodHandle mh) { + return MethodHandles.dropArguments(mh, 0, StaticClass.class); + } + + @Override + FacetIntrospector createFacetIntrospector() { + return new StaticClassIntrospector(clazz); + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest request, LinkerServices linkerServices) + throws Exception { + final GuardedInvocation gi = super.getGuardedInvocation(request, linkerServices); + if(gi != null) { + return gi; + } + final CallSiteDescriptor desc = request.getCallSiteDescriptor(); + final String op = desc.getNameToken(CallSiteDescriptor.OPERATOR); + final MethodType methodType = desc.getMethodType(); + if("new" == op && constructor != null) { + final MethodHandle ctorInvocation = constructor.getInvocation(methodType, linkerServices); + if(ctorInvocation != null) { + return new GuardedInvocation(ctorInvocation, getClassGuard(methodType)); + } + } + return null; + } + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest request, LinkerServices linkerServices) throws Exception { + final Object receiver = request.getReceiver(); + if(receiver instanceof StaticClass) { + return linkers.get(((StaticClass)receiver).getRepresentedClass()).getGuardedInvocation(request, + linkerServices); + } + return null; + } + + @Override + public boolean canLinkType(Class type) { + return type == StaticClass.class; + } + + /*private*/ static final MethodHandle GET_CLASS = new Lookup(MethodHandles.lookup()).findVirtual(StaticClass.class, + "getRepresentedClass", MethodType.methodType(Class.class)); + + /*private*/ static final MethodHandle IS_CLASS = new Lookup(MethodHandles.lookup()).findStatic(StaticClassLinker.class, + "isClass", MethodType.methodType(Boolean.TYPE, Class.class, Object.class)); + + /*private*/ static final MethodHandle ARRAY_CTOR = Lookup.PUBLIC.findStatic(Array.class, "newInstance", + MethodType.methodType(Object.class, Class.class, int.class)); + + @SuppressWarnings("unused") + private static boolean isClass(Class clazz, Object obj) { + return obj instanceof StaticClass && ((StaticClass)obj).getRepresentedClass() == clazz; + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/beans/messages.properties b/nashorn/src/jdk/internal/dynalink/beans/messages.properties new file mode 100644 index 00000000000..b930988c1b5 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/messages.properties @@ -0,0 +1,25 @@ +# Copyright 2009-2013 Attila Szegedi +# +# Licensed under either the Apache License, Version 2.0 (the "Apache +# License") or the BSD License (the "BSD License"), with licensee +# being free to choose either of the two at their discretion. +# +# You may not use this file except in compliance with either the Apache +# License or the BSD License. +# +# A copy of the BSD License is available in the root directory of the +# source distribution of the project under the file name +# "Dynalink-License-BSD.txt". +# +# A copy of the Apache License is available in the root directory of the +# source distribution of the project under the file name +# "Dynalink-License-Apache-2.0.txt". Alternatively, you may obtain a +# copy of the Apache License at +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See your chosen License for the specific language governing permissions +# and limitations under that License. + +couldNotDiscoverAccessibleMethods=Could not discover accessible methods of class {0}, trying its superclasses and interfaces. \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/beans/package.html b/nashorn/src/jdk/internal/dynalink/beans/package.html new file mode 100644 index 00000000000..f405d1649e2 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/package.html @@ -0,0 +1,86 @@ + + + + +

      + Contains the linker for POJOs. +

      + diff --git a/nashorn/src/jdk/internal/dynalink/linker/ConversionComparator.java b/nashorn/src/jdk/internal/dynalink/linker/ConversionComparator.java new file mode 100644 index 00000000000..8f2d1e0d0f7 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/ConversionComparator.java @@ -0,0 +1,114 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.linker; + + +/** + * Optional interface to be implemented by {@link GuardingTypeConverterFactory} implementers. Language-specific + * conversions can cause increased overloaded method resolution ambiguity, as many methods can become applicable because + * of additional conversions. The static way of selecting the "most specific" method will fail more often, because there + * will be multiple maximally specific method with unrelated signatures. In these cases, language runtimes can be asked + * to resolve the ambiguity by expressing preferences for one conversion over the other. + * @author Attila Szegedi + */ +public interface ConversionComparator { + /** + * Enumeration of possible outcomes of comparing one conversion to another. + */ + enum Comparison { + INDETERMINATE, + TYPE_1_BETTER, + TYPE_2_BETTER, + } + + /** + * Determines which of the two target types is the preferred conversion target from a source type. + * @param sourceType the source type. + * @param targetType1 one potential target type + * @param targetType2 another potential target type. + * @return one of Comparison constants that establish which - if any - of the target types is preferred for the + * conversion. + */ + public Comparison compareConversion(Class sourceType, Class targetType1, Class targetType2); +} diff --git a/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java b/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java new file mode 100644 index 00000000000..f045dd2c59b --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java @@ -0,0 +1,315 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.linker; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.SwitchPoint; +import java.lang.invoke.WrongMethodTypeException; +import java.util.List; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.support.Guards; + + +/** + * Represents a conditionally valid method handle. It is an immutable triple of an invocation method handle, a guard + * method handle that defines the applicability of the invocation handle, and a switch point that can be used for + * external invalidation of the invocation handle. The invocation handle is suitable for invocation if the guard + * handle returns true for its arguments, and as long as the switch point is not invalidated. Both the guard and the + * switch point are optional; neither, one, or both can be present. + * + * @author Attila Szegedi + */ +public class GuardedInvocation { + private final MethodHandle invocation; + private final MethodHandle guard; + private final SwitchPoint switchPoint; + + /** + * Creates a new guarded invocation. + * + * @param invocation the method handle representing the invocation. Must not be null. + * @param guard the method handle representing the guard. Must have the same method type as the invocation, except + * it must return boolean. For some useful guards, check out the {@link Guards} class. It can be null to represent + * an unconditional invocation, although that is unusual. + * @throws NullPointerException if invocation is null. + */ + public GuardedInvocation(MethodHandle invocation, MethodHandle guard) { + this(invocation, guard, null); + } + + /** + * Creates a new guarded invocation. + * + * @param invocation the method handle representing the invocation. Must not be null. + * @param guard the method handle representing the guard. Must have the same method type as the invocation, except + * it must return boolean. For some useful guards, check out the {@link Guards} class. It can be null. If both it + * and the switch point are null, this represents an unconditional invocation, which is legal but unusual. + * @param switchPoint the optional switch point that can be used to invalidate this linkage. + * @throws NullPointerException if invocation is null. + */ + public GuardedInvocation(MethodHandle invocation, MethodHandle guard, SwitchPoint switchPoint) { + invocation.getClass(); // NPE check + this.invocation = invocation; + this.guard = guard; + this.switchPoint = switchPoint; + } + + /** + * Creates a new guarded invocation. + * + * @param invocation the method handle representing the invocation. Must not be null. + * @param switchPoint the optional switch point that can be used to invalidate this linkage. + * @param guard the method handle representing the guard. Must have the same method type as the invocation, except + * it must return boolean. For some useful guards, check out the {@link Guards} class. It can be null. If both it + * and the switch point are null, this represents an unconditional invocation, which is legal but unusual. + * @throws NullPointerException if invocation is null. + */ + public GuardedInvocation(MethodHandle invocation, SwitchPoint switchPoint, MethodHandle guard) { + this(invocation, guard, switchPoint); + } + /** + * Returns the invocation method handle. + * + * @return the invocation method handle. It will never be null. + */ + public MethodHandle getInvocation() { + return invocation; + } + + /** + * Returns the guard method handle. + * + * @return the guard method handle. Can be null. + */ + public MethodHandle getGuard() { + return guard; + } + + /** + * Returns the switch point that can be used to invalidate the invocation handle. + * + * @return the switch point that can be used to invalidate the invocation handle. Can be null. + */ + public SwitchPoint getSwitchPoint() { + return switchPoint; + } + + /** + * Returns true if and only if this guarded invocation has a switchpoint, and that switchpoint has been invalidated. + * @return true if and only if this guarded invocation has a switchpoint, and that switchpoint has been invalidated. + */ + public boolean hasBeenInvalidated() { + return switchPoint != null && switchPoint.hasBeenInvalidated(); + } + + /** + * Asserts that the invocation is of the specified type, and the guard (if present) is of the specified type with a + * boolean return type. + * + * @param type the asserted type + * @throws WrongMethodTypeException if the invocation and the guard are not of the expected method type. + */ + public void assertType(MethodType type) { + assertType(invocation, type); + if(guard != null) { + assertType(guard, type.changeReturnType(Boolean.TYPE)); + } + } + + /** + * Creates a new guarded invocation with different methods, preserving the switch point. + * + * @param newInvocation the new invocation + * @param newGuard the new guard + * @return a new guarded invocation with the replaced methods and the same switch point as this invocation. + */ + public GuardedInvocation replaceMethods(MethodHandle newInvocation, MethodHandle newGuard) { + return new GuardedInvocation(newInvocation, newGuard, switchPoint); + } + + private GuardedInvocation replaceMethodsOrThis(MethodHandle newInvocation, MethodHandle newGuard) { + if(newInvocation == invocation && newGuard == guard) { + return this; + } + return replaceMethods(newInvocation, newGuard); + } + + /** + * Changes the type of the invocation, as if {@link MethodHandle#asType(MethodType)} was applied to its invocation + * and its guard, if it has one (with return type changed to boolean, and parameter count potentially truncated for + * the guard). If the invocation already is of the required type, returns this object. + * @param newType the new type of the invocation. + * @return a guarded invocation with the new type applied to it. + */ + public GuardedInvocation asType(MethodType newType) { + return replaceMethodsOrThis(invocation.asType(newType), guard == null ? null : Guards.asType(guard, newType)); + } + + /** + * Changes the type of the invocation, as if {@link LinkerServices#asType(MethodHandle, MethodType)} was applied to + * its invocation and its guard, if it has one (with return type changed to boolean, and parameter count potentially + * truncated for the guard). If the invocation already is of the required type, returns this object. + * @param linkerServices the linker services to use for the conversion + * @param newType the new type of the invocation. + * @return a guarded invocation with the new type applied to it. + */ + public GuardedInvocation asType(LinkerServices linkerServices, MethodType newType) { + return replaceMethodsOrThis(linkerServices.asType(invocation, newType), guard == null ? null : + Guards.asType(linkerServices, guard, newType)); + } + + /** + * Changes the type of the invocation, as if {@link MethodHandle#asType(MethodType)} was applied to its invocation + * and its guard, if it has one (with return type changed to boolean for guard). If the invocation already is of the + * required type, returns this object. + * @param desc a call descriptor whose method type is adapted. + * @return a guarded invocation with the new type applied to it. + */ + public GuardedInvocation asType(CallSiteDescriptor desc) { + return asType(desc.getMethodType()); + } + + /** + * Applies argument filters to both the invocation and the guard (if there is one). + * @param pos the position of the first argumen being filtered + * @param filters the argument filters + * @return a filtered invocation + */ + public GuardedInvocation filterArguments(int pos, MethodHandle... filters) { + return replaceMethods(MethodHandles.filterArguments(invocation, pos, filters), guard == null ? null : + MethodHandles.filterArguments(guard, pos, filters)); + } + + /** + * Makes an invocation that drops arguments in both the invocation and the guard (if there is one). + * @param pos the position of the first argument being dropped + * @param valueTypes the types of the values being dropped + * @return an invocation that drops arguments + */ + public GuardedInvocation dropArguments(int pos, List> valueTypes) { + return replaceMethods(MethodHandles.dropArguments(invocation, pos, valueTypes), guard == null ? null : + MethodHandles.dropArguments(guard, pos, valueTypes)); + } + + /** + * Makes an invocation that drops arguments in both the invocation and the guard (if there is one). + * @param pos the position of the first argument being dropped + * @param valueTypes the types of the values being dropped + * @return an invocation that drops arguments + */ + public GuardedInvocation dropArguments(int pos, Class... valueTypes) { + return replaceMethods(MethodHandles.dropArguments(invocation, pos, valueTypes), guard == null ? null : + MethodHandles.dropArguments(guard, pos, valueTypes)); + } + + + /** + * Composes the invocation, switchpoint, and the guard into a composite method handle that knows how to fall back. + * @param fallback the fallback method handle in case switchpoint is invalidated or guard returns false. + * @return a composite method handle. + */ + public MethodHandle compose(MethodHandle fallback) { + return compose(fallback, fallback); + } + + /** + * Composes the invocation, switchpoint, and the guard into a composite method handle that knows how to fall back. + * @param switchpointFallback the fallback method handle in case switchpoint is invalidated. + * @param guardFallback the fallback method handle in case guard returns false. + * @return a composite method handle. + */ + public MethodHandle compose(MethodHandle switchpointFallback, MethodHandle guardFallback) { + final MethodHandle guarded = + guard == null ? invocation : MethodHandles.guardWithTest(guard, invocation, guardFallback); + return switchPoint == null ? guarded : switchPoint.guardWithTest(guarded, switchpointFallback); + } + + private static void assertType(MethodHandle mh, MethodType type) { + if(!mh.type().equals(type)) { + throw new WrongMethodTypeException("Expected type: " + type + " actual type: " + mh.type()); + } + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/linker/GuardingDynamicLinker.java b/nashorn/src/jdk/internal/dynalink/linker/GuardingDynamicLinker.java new file mode 100644 index 00000000000..a2acee3cef4 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/GuardingDynamicLinker.java @@ -0,0 +1,112 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.linker; + +/** + * The base interface for language-specific dynamic linkers. Such linkers always have to produce method handles with + * guards, as the validity of the method handle for calls at a call site inevitably depends on some condition (at the + * very least, it depends on the receiver belonging to the language runtime of the linker). Language runtime + * implementors will normally implement one for their own language, and declare it in the + * META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker file within their JAR file. + * + * @author Attila Szegedi + */ +public interface GuardingDynamicLinker { + /** + * Creates a guarded invocation appropriate for a particular invocation with the specified arguments at a call site. + * + * @param linkRequest the object describing the request for linking a particular invocation + * @param linkerServices linker services + * @return a guarded invocation with a method handle suitable for the arguments, as well as a guard condition that + * if fails should trigger relinking. Must return null if it can't resolve the invocation. If the returned + * invocation is unconditional (which is actually quite rare), the guard in the return value can be null. The + * invocation can also have a switch point for asynchronous invalidation of the linkage. If the linker does not + * recognize any native language runtime contexts in arguments, or does recognize its own, but receives a call site + * descriptor without its recognized context in the arguments, it should invoke + * {@link LinkRequest#withoutRuntimeContext()} and link for that. + * @throws Exception if the operation fails for whatever reason + */ + public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, LinkerServices linkerServices) + throws Exception; +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/linker/GuardingTypeConverterFactory.java b/nashorn/src/jdk/internal/dynalink/linker/GuardingTypeConverterFactory.java new file mode 100644 index 00000000000..138bd894ff1 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/GuardingTypeConverterFactory.java @@ -0,0 +1,114 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.linker; + +import jdk.internal.dynalink.support.TypeUtilities; + +/** + * Optional interface that can be implemented by {@link GuardingDynamicLinker} implementations to provide + * language-runtime specific implicit type conversion capabilities. Note that if you implement this interface, you will + * very likely want to implement {@link ConversionComparator} interface too, as your additional language-specific + * conversions, in absence of a strategy for prioritizing these conversions, will cause more ambiguity in selecting the + * correct overload when trying to link to an overloaded POJO method. + * + * @author Attila Szegedi + */ +public interface GuardingTypeConverterFactory { + /** + * Returns a guarded invocation that receives an Object of the specified source type and returns an Object converted + * to the specified target type. The type of the invocation is targetType(sourceType), while the type of the guard + * is boolean(sourceType). Note that this will never be invoked for type conversions allowed by the JLS 5.3 "Method + * Invocation Conversion", see {@link TypeUtilities#isMethodInvocationConvertible(Class, Class)} for details. An + * implementation can assume it is never requested to produce a converter for these conversions. + * + * @param sourceType source type + * @param targetType the target type. + * @return a guarded invocation that can take an object (if it passes guard) and returns another object that is its + * representation coerced into the target type. In case the factory is certain it is unable to handle a conversion, + * it can return null. In case the factory is certain that it can always handle the conversion, it can return an + * unconditional invocation (one whose guard is null). + * @throws Exception if there was an error during creation of the converter + */ + public GuardedInvocation convertToType(Class sourceType, Class targetType) throws Exception; +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/linker/LinkRequest.java b/nashorn/src/jdk/internal/dynalink/linker/LinkRequest.java new file mode 100644 index 00000000000..528be640c32 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/LinkRequest.java @@ -0,0 +1,149 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.linker; + +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.DynamicLinkerFactory; + +/** + * Represents a request to link a particular invocation at a particular call site. Instances of these requests are being + * passed to {@link GuardingDynamicLinker}. + * + * @author Attila Szegedi + */ +public interface LinkRequest { + /** + * Returns the call site descriptor for the call site being linked. + * + * @return the call site descriptor for the call site being linked. + */ + public CallSiteDescriptor getCallSiteDescriptor(); + + /** + * Returns the arguments for the invocation being linked. The returned array is a clone; modifications to it won't + * affect the arguments in this request. + * + * @return the arguments for the invocation being linked. + */ + public Object[] getArguments(); + + /** + * Returns the 0th argument for the invocation being linked; this is typically the receiver object. + * + * @return the receiver object. + */ + public Object getReceiver(); + + /** + * Returns true if the call site is considered unstable, that is, it has been relinked more times than was + * specified in {@link DynamicLinkerFactory#setUnstableRelinkThreshold(int)}. Linkers should use this as a + * hint to prefer producing linkage that is more stable (its guard fails less frequently), even if that assumption + * causes a less effective version of an operation to be linked. This is just a hint, of course, and linkers are + * free to ignore this property. + * @return true if the call site is considered unstable. + */ + public boolean isCallSiteUnstable(); + + /** + * Returns a request stripped from runtime context arguments. Some language runtimes will include runtime-specific + * context parameters in their call sites as few arguments between 0th argument "this" and the normal arguments. If + * a linker does not recognize such contexts at all, or does not recognize the call site as one with its own + * context, it can ask for the alternative link request with context parameters and arguments removed, and link + * against it instead. + * + * @return the context-stripped request. If the link request does not have any language runtime specific context + * parameters, the same link request is returned. + */ + public LinkRequest withoutRuntimeContext(); + + /** + * Returns a request identical to this one with call site descriptor and arguments replaced with the ones specified. + * + * @param callSiteDescriptor the new call site descriptor + * @param arguments the new arguments + * @return a new request identical to this one, except with the call site descriptor and arguments replaced with the + * specified ones. + */ + public LinkRequest replaceArguments(CallSiteDescriptor callSiteDescriptor, Object[] arguments); +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/linker/LinkerServices.java b/nashorn/src/jdk/internal/dynalink/linker/LinkerServices.java new file mode 100644 index 00000000000..ab821db161b --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/LinkerServices.java @@ -0,0 +1,165 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.linker; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.DynamicLinker; +import jdk.internal.dynalink.linker.ConversionComparator.Comparison; + + +/** + * Interface for services provided to {@link GuardingDynamicLinker} instances by the {@link DynamicLinker} that owns + * them. You can think of it as the interface of the {@link DynamicLinker} that faces the {@link GuardingDynamicLinker} + * s. + * + * @author Attila Szegedi + */ +public interface LinkerServices { + /** + * Similar to {@link MethodHandle#asType(MethodType)} except it also hooks in method handles produced by + * {@link GuardingTypeConverterFactory} implementations, providing for language-specific type coercing of + * parameters. It will apply {@link MethodHandle#asType(MethodType)} for all primitive-to-primitive, + * wrapper-to-primitive, primitive-to-wrapper conversions as well as for all upcasts. For all other conversions, + * it'll insert {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with composite filters + * provided by {@link GuardingTypeConverterFactory} implementations. It doesn't use language-specific conversions on + * the return type. + * + * @param handle target method handle + * @param fromType the types of source arguments + * @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)} and + * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with + * {@link GuardingTypeConverterFactory} produced type converters as filters. + */ + public MethodHandle asType(MethodHandle handle, MethodType fromType); + + /** + * Given a source and target type, returns a method handle that converts between them. Never returns null; in worst + * case it will return an identity conversion (that might fail for some values at runtime). You rarely need to use + * this method directly; you should mostly rely on {@link #asType(MethodHandle, MethodType)} instead. You really + * only need this method if you have a piece of your program that is written in Java, and you need to reuse existing + * type conversion machinery in a non-invokedynamic context. + * @param sourceType the type to convert from + * @param targetType the type to convert to + * @return a method handle performing the conversion. + */ + public MethodHandle getTypeConverter(Class sourceType, Class targetType); + + /** + * Returns true if there might exist a conversion between the requested types (either an automatic JVM conversion, + * or one provided by any available {@link GuardingTypeConverterFactory}), or false if there definitely does not + * exist a conversion between the requested types. Note that returning true does not guarantee that the conversion + * will succeed at runtime (notably, if the "from" or "to" types are sufficiently generic), but returning false + * guarantees that it would fail. + * + * @param from the source type for the conversion + * @param to the target type for the conversion + * @return true if there can be a conversion, false if there can not. + */ + public boolean canConvert(Class from, Class to); + + /** + * Creates a guarded invocation using the {@link DynamicLinker} that exposes this linker services interface. Linkers + * can typically use them to delegate linking of wrapped objects. + * + * @param linkRequest a request for linking the invocation + * @return a guarded invocation linked by the top-level linker (or any of its delegates). Can be null if no + * available linker is able to link the invocation. + * @throws Exception in case the top-level linker throws an exception + */ + public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest) throws Exception; + + /** + * Determines which of the two type conversions from a source type to the two target types is preferred. This is + * used for dynamic overloaded method resolution. If the source type is convertible to exactly one target type with + * a method invocation conversion, it is chosen, otherwise available {@link ConversionComparator}s are consulted. + * @param sourceType the source type. + * @param targetType1 one potential target type + * @param targetType2 another potential target type. + * @return one of Comparison constants that establish which - if any - of the target types is preferable for the + * conversion. + */ + public Comparison compareConversion(Class sourceType, Class targetType1, Class targetType2); +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/linker/TypeBasedGuardingDynamicLinker.java b/nashorn/src/jdk/internal/dynalink/linker/TypeBasedGuardingDynamicLinker.java new file mode 100644 index 00000000000..c7fac02d500 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/TypeBasedGuardingDynamicLinker.java @@ -0,0 +1,102 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.linker; + +/** + * A guarding dynamic linker that can determine whether it can link the call site solely based on the type of the first + * argument at linking invocation time. (The first argument is usually the receiver class). Most language-specific + * linkers will fall into this category, as they recognize their native objects as Java objects of classes implementing + * a specific language-native interface or superclass. The linker mechanism can optimize the dispatch for these linkers. + * + * @author Attila Szegedi + */ +public interface TypeBasedGuardingDynamicLinker extends GuardingDynamicLinker { + /** + * Returns true if the linker can link an invocation where the first argument (receiver) is of the specified type. + * + * @param type the type to link + * @return true if the linker can link calls for the receiver type, or false otherwise. + */ + public boolean canLinkType(Class type); +} diff --git a/nashorn/src/jdk/internal/dynalink/linker/package.html b/nashorn/src/jdk/internal/dynalink/linker/package.html new file mode 100644 index 00000000000..4e3991d7614 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/package.html @@ -0,0 +1,87 @@ + + + + +

      + Contains interfaces and classes needed by language runtimes to implement + their own language-specific linkers. +

      + diff --git a/nashorn/src/jdk/internal/dynalink/package.html b/nashorn/src/jdk/internal/dynalink/package.html new file mode 100644 index 00000000000..588823ac8c3 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/package.html @@ -0,0 +1,93 @@ + + + + +

      + Contains the main API for using the dynamic linking facilities. A + scripting framework or a language runtime that does not define its own + linker but only uses linkers available in the system will only need to + use classes and interfaces from this package. +

      +

      + Languages that wish to define and use their own linkers will also need to + use the {@link jdk.internal.dynalink.linker} package. +

      + diff --git a/nashorn/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java b/nashorn/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java new file mode 100644 index 00000000000..401ab1a2636 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java @@ -0,0 +1,186 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.util.Objects; +import jdk.internal.dynalink.CallSiteDescriptor; + + +/** + * A base class for call site descriptor implementations. Provides reconstruction of the name from the tokens, as well + * as a generally useful {@code equals} and {@code hashCode} methods. + * @author Attila Szegedi + */ +public abstract class AbstractCallSiteDescriptor implements CallSiteDescriptor { + + @Override + public String getName() { + return appendName(new StringBuilder(getNameLength())).toString(); + } + + @Override + public Lookup getLookup() { + return MethodHandles.publicLookup(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof CallSiteDescriptor && equals((CallSiteDescriptor)obj); + } + + /** + * Returns true if this call site descriptor is equal to the passed call site descriptor. + * @param csd the other call site descriptor. + * @return true if they are equal. + */ + public boolean equals(CallSiteDescriptor csd) { + if(csd == null) { + return false; + } + if(csd == this) { + return true; + } + final int ntc = getNameTokenCount(); + if(ntc != csd.getNameTokenCount()) { + return false; + } + for(int i = ntc; i-- > 0;) { // Reverse order as variability is higher at the end + if(!Objects.equals(getNameToken(i), csd.getNameToken(i))) { + return false; + } + } + if(!getMethodType().equals(csd.getMethodType())) { + return false; + } + return lookupsEqual(getLookup(), csd.getLookup()); + } + + @Override + public int hashCode() { + final int c = getNameTokenCount(); + int h = 0; + for(int i = 0; i < c; ++i) { + h = h * 31 + getNameToken(i).hashCode(); + } + return h * 31 + getMethodType().hashCode(); + } + + @Override + public String toString() { + final String mt = getMethodType().toString(); + final String l = getLookup().toString(); + final StringBuilder b = new StringBuilder(l.length() + 1 + mt.length() + getNameLength()); + return appendName(b).append(mt).append("@").append(l).toString(); + } + + private int getNameLength() { + final int c = getNameTokenCount(); + int l = 0; + for(int i = 0; i < c; ++i) { + l += getNameToken(i).length(); + } + return l + c - 1; + } + + private StringBuilder appendName(StringBuilder b) { + b.append(getNameToken(0)); + final int c = getNameTokenCount(); + for(int i = 1; i < c; ++i) { + b.append(':').append(getNameToken(i)); + } + return b; + } + + private static boolean lookupsEqual(Lookup l1, Lookup l2) { + if(l1 == l2) { + return true; + } + if(l1.lookupClass() != l2.lookupClass()) { + return false; + } + return l1.lookupModes() == l2.lookupModes(); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/AbstractRelinkableCallSite.java b/nashorn/src/jdk/internal/dynalink/support/AbstractRelinkableCallSite.java new file mode 100644 index 00000000000..248ce9b2b63 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/AbstractRelinkableCallSite.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MutableCallSite; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.RelinkableCallSite; + + +/** + * A basic implementation of the {@link RelinkableCallSite} as a {@link MutableCallSite} subclass. + * + * @author Attila Szegedi + */ +public abstract class AbstractRelinkableCallSite extends MutableCallSite implements RelinkableCallSite { + private final CallSiteDescriptor descriptor; + + /** + * Creates a new relinkable call site. + * @param descriptor the descriptor for this call site + */ + protected AbstractRelinkableCallSite(CallSiteDescriptor descriptor) { + super(descriptor.getMethodType()); + this.descriptor = descriptor; + } + + @Override + public CallSiteDescriptor getDescriptor() { + return descriptor; + } + + @Override + public void initialize(MethodHandle relinkAndInvoke) { + setTarget(relinkAndInvoke); + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/support/AutoDiscovery.java b/nashorn/src/jdk/internal/dynalink/support/AutoDiscovery.java new file mode 100644 index 00000000000..72e93cc2418 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/AutoDiscovery.java @@ -0,0 +1,134 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.util.LinkedList; +import java.util.List; +import java.util.ServiceLoader; +import jdk.internal.dynalink.DynamicLinkerFactory; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; + + +/** + * Provides methods for automatic discovery of all guarding dynamic linkers listed in the + * /META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker resources of all JAR files for a + * particular class loader. Ordinarily, you will not use this class directly, but you will use a + * {@link DynamicLinkerFactory} instead. + */ +public class AutoDiscovery { + + private AutoDiscovery() { + } + + /** + * Discovers all guarding dynamic linkers listed in JAR files of the context class loader of the current thread. + * + * @return a list of available linkers. Can be zero-length list but not null. + */ + public static List loadLinkers() { + return getLinkers(ServiceLoader.load(GuardingDynamicLinker.class)); + } + + /** + * Discovers all guarding dynamic linkers listed in JAR files of the specified class loader. + * + * @param cl the class loader to use + * @return a list of guarding dynamic linkers available through the specified class loader. Can be zero-length list + * but not null. + */ + public static List loadLinkers(ClassLoader cl) { + return getLinkers(ServiceLoader.load(GuardingDynamicLinker.class, cl)); + } + + /** + * I can't believe there's no Collections API for making a List given an Iterator... + */ + private static List getLinkers(ServiceLoader loader) { + final List list = new LinkedList<>(); + for(final T linker: loader) { + list.add(linker); + } + return list; + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/support/Backport.java b/nashorn/src/jdk/internal/dynalink/support/Backport.java new file mode 100644 index 00000000000..1be7dc32acc --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/Backport.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.lang.invoke.MethodHandles; + +/** + * @author Attila Szegedi + */ +public class Backport { + /** + * True if Remi's JSR-292 backport agent is active; false if we're using native OpenJDK JSR-292 support. + */ + public static final boolean inUse = MethodHandles.class.getName().startsWith("jsr292"); + + private Backport() { + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/BottomGuardingDynamicLinker.java b/nashorn/src/jdk/internal/dynalink/support/BottomGuardingDynamicLinker.java new file mode 100644 index 00000000000..bab8f59e174 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/BottomGuardingDynamicLinker.java @@ -0,0 +1,116 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; + +/** + * A linker that can't link any call site. Only used internally by {@link CompositeTypeBasedGuardingDynamicLinker}. Can + * be used by other language runtimes if they need it though. + * + * @author Attila Szegedi + */ +public class BottomGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker { + + /** + * The sole instance of this stateless linker. + */ + public static final BottomGuardingDynamicLinker INSTANCE = new BottomGuardingDynamicLinker(); + + private BottomGuardingDynamicLinker() { + } + + @Override + public boolean canLinkType(Class type) { + return false; + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, LinkerServices linkerServices) { + return null; + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/support/CallSiteDescriptorFactory.java b/nashorn/src/jdk/internal/dynalink/support/CallSiteDescriptorFactory.java new file mode 100644 index 00000000000..d74f73711d0 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/CallSiteDescriptorFactory.java @@ -0,0 +1,265 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import java.lang.ref.WeakReference; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.StringTokenizer; +import java.util.WeakHashMap; +import jdk.internal.dynalink.CallSiteDescriptor; + + +/** + * Usable as a default factory for call site descriptor implementations. It is weakly canonicalizing, meaning it will + * return the same immutable call site descriptor for identical inputs, i.e. repeated requests for a descriptor + * signifying public lookup for "dyn:getProp:color" of type "Object(Object)" will return the same object as long as + * a previously created, at least softly reachable one exists. It also uses several different implementations of the + * {@link CallSiteDescriptor} internally, and chooses the most space-efficient one based on the input. + * @author Attila Szegedi + */ +public class CallSiteDescriptorFactory { + private static final WeakHashMap> publicDescs = + new WeakHashMap<>(); + + + private CallSiteDescriptorFactory() { + } + + /** + * Creates a new call site descriptor instance. The actual underlying class of the instance is dependent on the + * passed arguments to be space efficient; i.e. if you only use the public lookup, you'll get back an + * implementation that doesn't waste space on storing the lookup object. + * @param lookup the lookup that determines access rights at the call site. If your language runtime doesn't have + * equivalents of Java access concepts, just use {@link MethodHandles#publicLookup()}. Must not be null. + * @param name the name of the method at the call site. Must not be null. + * @param methodType the type of the method at the call site. Must not be null. + * @return a call site descriptor representing the input. Note that although the method name is "create", it will + * in fact return a weakly-referenced canonical instance. + */ + public static CallSiteDescriptor create(Lookup lookup, String name, MethodType methodType) { + name.getClass(); // NPE check + methodType.getClass(); // NPE check + lookup.getClass(); // NPE check + final String[] tokenizedName = tokenizeName(name); + if(isPublicLookup(lookup)) { + return getCanonicalPublicDescriptor(createPublicCallSiteDescriptor(tokenizedName, methodType)); + } else { + return new LookupCallSiteDescriptor(tokenizedName, methodType, lookup); + } + } + + static CallSiteDescriptor getCanonicalPublicDescriptor(final CallSiteDescriptor desc) { + synchronized(publicDescs) { + final WeakReference ref = publicDescs.get(desc); + if(ref != null) { + final CallSiteDescriptor canonical = ref.get(); + if(canonical != null) { + return canonical; + } + } + publicDescs.put(desc, new WeakReference<>(desc)); + } + return desc; + } + + private static CallSiteDescriptor createPublicCallSiteDescriptor(String[] tokenizedName, MethodType methodType) { + final int l = tokenizedName.length; + if(l > 0 && tokenizedName[0] == "dyn") { + if(l == 2) { + return new UnnamedDynCallSiteDescriptor(tokenizedName[1], methodType); + } if (l == 3) { + return new NamedDynCallSiteDescriptor(tokenizedName[1], tokenizedName[2], methodType); + } + } + return new DefaultCallSiteDescriptor(tokenizedName, methodType); + } + + private static boolean isPublicLookup(Lookup lookup) { + return lookup == MethodHandles.publicLookup(); + } + + /** + * Tokenizes the composite name along colons, as well as {@link NameCodec#decode(String) demangles} and interns + * the tokens. The first two tokens are not demangled as they are supposed to be the naming scheme and the name of + * the operation which can be expected to consist of just alphabetical characters. + * @param name the composite name consisting of colon-separated, possibly mangled tokens. + * @return an array of tokens + */ + public static String[] tokenizeName(String name) { + final StringTokenizer tok = new StringTokenizer(name, CallSiteDescriptor.TOKEN_DELIMITER); + final String[] tokens = new String[tok.countTokens()]; + for(int i = 0; i < tokens.length; ++i) { + String token = tok.nextToken(); + if(i > 1) { + token = NameCodec.decode(token); + } + tokens[i] = token.intern(); + } + return tokens; + } + + /** + * Tokenizes a composite operation name along pipe characters. I.e. if you have a "dyn:getElem|getProp|getMethod" + * operation, returns a list of ["getElem", "getProp", "getMethod"]. The tokens are not interned. + * @param desc the call site descriptor with the operation + * @return a list of tokens + */ + public static List tokenizeOperators(CallSiteDescriptor desc) { + final String ops = desc.getNameToken(CallSiteDescriptor.OPERATOR); + final StringTokenizer tok = new StringTokenizer(ops, CallSiteDescriptor.OPERATOR_DELIMITER); + final int count = tok.countTokens(); + if(count == 1) { + return Collections.singletonList(ops); + } + final String[] tokens = new String[count]; + for(int i = 0; i < count; ++i) { + tokens[i] = tok.nextToken(); + } + return Arrays.asList(tokens); + } + + /** + * Returns a new call site descriptor that is identical to the passed one, except that it has some parameter types + * removed from its method type. + * @param desc the original call site descriptor + * @param start index of the first parameter to remove + * @param end index of the first parameter to not remove + * @return a new call site descriptor with modified method type + */ + public static CallSiteDescriptor dropParameterTypes(CallSiteDescriptor desc, int start, int end) { + return desc.changeMethodType(desc.getMethodType().dropParameterTypes(start, end)); + } + + /** + * Returns a new call site descriptor that is identical to the passed one, except that it has a single parameter + * type changed in its method type. + * @param desc the original call site descriptor + * @param num index of the parameter to change + * @param nptype the new parameter type + * @return a new call site descriptor with modified method type + */ + public static CallSiteDescriptor changeParameterType(CallSiteDescriptor desc, int num, Class nptype) { + return desc.changeMethodType(desc.getMethodType().changeParameterType(num, nptype)); + } + + /** + * Returns a new call site descriptor that is identical to the passed one, except that it has the return type + * changed in its method type. + * @param desc the original call site descriptor + * @param nrtype the new return type + * @return a new call site descriptor with modified method type + */ + public static CallSiteDescriptor changeReturnType(CallSiteDescriptor desc, Class nrtype) { + return desc.changeMethodType(desc.getMethodType().changeReturnType(nrtype)); + } + + /** + * Returns a new call site descriptor that is identical to the passed one, except that it has additional parameter + * types inserted into its method type. + * @param desc the original call site descriptor + * @param num index at which the new parameters are inserted + * @param ptypesToInsert the new types to insert + * @return a new call site descriptor with modified method type + */ + public static CallSiteDescriptor insertParameterTypes(CallSiteDescriptor desc, int num, Class... ptypesToInsert) { + return desc.changeMethodType(desc.getMethodType().insertParameterTypes(num, ptypesToInsert)); + } + + /** + * Returns a new call site descriptor that is identical to the passed one, except that it has additional parameter + * types inserted into its method type. + * @param desc the original call site descriptor + * @param num index at which the new parameters are inserted + * @param ptypesToInsert the new types to insert + * @return a new call site descriptor with modified method type + */ + public static CallSiteDescriptor insertParameterTypes(CallSiteDescriptor desc, int num, List> ptypesToInsert) { + return desc.changeMethodType(desc.getMethodType().insertParameterTypes(num, ptypesToInsert)); + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/support/ClassMap.java b/nashorn/src/jdk/internal/dynalink/support/ClassMap.java new file mode 100644 index 00000000000..7369d2557cf --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/ClassMap.java @@ -0,0 +1,177 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * A dual map that can either strongly or weakly reference a given class depending on whether the class is visible from + * a class loader or not. + * + * @author Attila Szegedi + * @param the type of the values in the map + */ +public abstract class ClassMap { + private final ConcurrentMap, T> map = new ConcurrentHashMap<>(); + private final Map, Reference> weakMap = new WeakHashMap<>(); + private final ClassLoader classLoader; + + /** + * Creates a new class map. It will use strong references for all keys and values where the key is a class visible + * from the class loader, and will use weak keys and soft values for all other classes. + * + * @param classLoader the classloader that determines strong referenceability. + */ + protected ClassMap(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + /** + * Compute the value associated with the given class. It is possible that the method will be invoked several times + * (or even concurrently) for the same class parameter. + * + * @param clazz the class to compute the value for + * @return the return value. Must not be null. + */ + protected abstract T computeValue(Class clazz); + + /** + * Returns the class loader that governs the strong referenceability of this class map. + * + * @return the class loader that governs the strong referenceability of this class map. + */ + public ClassLoader getClassLoader() { + return classLoader; + } + + /** + * Returns the value associated with the class + * + * @param clazz the class + * @return the value associated with the class + */ + public T get(Class clazz) { + // Check in fastest first - objects we're allowed to strongly reference + final T v = map.get(clazz); + if(v != null) { + return v; + } + // Check objects we're not allowed to strongly reference + Reference ref; + synchronized(weakMap) { + ref = weakMap.get(clazz); + } + if(ref != null) { + final T refv = ref.get(); + if(refv != null) { + return refv; + } + } + // Not found in either place; create a new value + final T newV = computeValue(clazz); + assert newV != null; + // If allowed to strongly reference, put it in the fast map + if(Guards.canReferenceDirectly(classLoader, clazz.getClassLoader())) { + final T oldV = map.putIfAbsent(clazz, newV); + return oldV != null ? oldV : newV; + } + // Otherwise, put it into the weak map + synchronized(weakMap) { + ref = weakMap.get(clazz); + if(ref != null) { + final T oldV = ref.get(); + if(oldV != null) { + return oldV; + } + } + weakMap.put(clazz, new SoftReference<>(newV)); + return newV; + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/CompositeGuardingDynamicLinker.java b/nashorn/src/jdk/internal/dynalink/support/CompositeGuardingDynamicLinker.java new file mode 100644 index 00000000000..f13eb9b24c5 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/CompositeGuardingDynamicLinker.java @@ -0,0 +1,132 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; + + +/** + * A {@link GuardingDynamicLinker} that delegates sequentially to a list of other guarding dynamic linkers. The first + * value returned from a component linker other than null is returned. If no component linker returns an invocation, + * null is returned. + * + * @author Attila Szegedi + */ +public class CompositeGuardingDynamicLinker implements GuardingDynamicLinker, Serializable { + + private static final long serialVersionUID = 1L; + + private final GuardingDynamicLinker[] linkers; + + /** + * Creates a new composite linker. + * + * @param linkers a list of component linkers. + */ + public CompositeGuardingDynamicLinker(Iterable linkers) { + final List l = new LinkedList<>(); + for(GuardingDynamicLinker linker: linkers) { + l.add(linker); + } + this.linkers = l.toArray(new GuardingDynamicLinker[l.size()]); + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, final LinkerServices linkerServices) + throws Exception { + for(final GuardingDynamicLinker linker: linkers) { + final GuardedInvocation invocation = linker.getGuardedInvocation(linkRequest, linkerServices); + if(invocation != null) { + return invocation; + } + } + return null; + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/support/CompositeTypeBasedGuardingDynamicLinker.java b/nashorn/src/jdk/internal/dynalink/support/CompositeTypeBasedGuardingDynamicLinker.java new file mode 100644 index 00000000000..b0ea761a415 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/CompositeTypeBasedGuardingDynamicLinker.java @@ -0,0 +1,226 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.io.Serializable; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; + + +/** + * A composite type-based guarding dynamic linker. When a receiver of a not yet seen class is encountered, all linkers + * are queried sequentially on their {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)} method. The linkers + * returning true are then bound to the class, and next time a receiver of same type is encountered, the linking is + * delegated to those linkers only, speeding up dispatch. + * + * @author Attila Szegedi + */ +public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker, Serializable { + private static final long serialVersionUID = 1L; + + // Using a separate static class instance so there's no strong reference from the class value back to the composite + // linker. + private static class ClassToLinker extends ClassValue> { + private static final List NO_LINKER = Collections.emptyList(); + private final TypeBasedGuardingDynamicLinker[] linkers; + private final List[] singletonLinkers; + + @SuppressWarnings("unchecked") + ClassToLinker(TypeBasedGuardingDynamicLinker[] linkers) { + this.linkers = linkers; + singletonLinkers = new List[linkers.length]; + for(int i = 0; i < linkers.length; ++i) { + singletonLinkers[i] = Collections.singletonList(linkers[i]); + } + } + + @Override + protected List computeValue(Class clazz) { + List list = NO_LINKER; + for(int i = 0; i < linkers.length; ++i) { + final TypeBasedGuardingDynamicLinker linker = linkers[i]; + if(linker.canLinkType(clazz)) { + switch(list.size()) { + case 0: { + list = singletonLinkers[i]; + break; + } + case 1: { + list = new LinkedList<>(list); + } + //$FALL-THROUGH$ + default: { + list.add(linker); + } + } + } + } + return list; + } + } + + private final ClassValue> classToLinker; + + /** + * Creates a new composite type-based linker. + * + * @param linkers the component linkers + */ + public CompositeTypeBasedGuardingDynamicLinker(Iterable linkers) { + final List l = new LinkedList<>(); + for(TypeBasedGuardingDynamicLinker linker: linkers) { + l.add(linker); + } + this.classToLinker = new ClassToLinker(l.toArray(new TypeBasedGuardingDynamicLinker[l.size()])); + } + + @Override + public boolean canLinkType(Class type) { + return !classToLinker.get(type).isEmpty(); + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, final LinkerServices linkerServices) + throws Exception { + final Object obj = linkRequest.getReceiver(); + if(obj == null) { + return null; + } + for(TypeBasedGuardingDynamicLinker linker: classToLinker.get(obj.getClass())) { + final GuardedInvocation invocation = linker.getGuardedInvocation(linkRequest, linkerServices); + if(invocation != null) { + return invocation; + } + } + return null; + } + + /** + * Optimizes a list of type-based linkers. If a group of adjacent linkers in the list all implement + * {@link TypeBasedGuardingDynamicLinker}, they will be replaced with a single instance of + * {@link CompositeTypeBasedGuardingDynamicLinker} that contains them. + * + * @param linkers the list of linkers to optimize + * @return the optimized list + */ + public static List optimize(Iterable linkers) { + final List llinkers = new LinkedList<>(); + final List tblinkers = new LinkedList<>(); + for(GuardingDynamicLinker linker: linkers) { + if(linker instanceof TypeBasedGuardingDynamicLinker) { + tblinkers.add((TypeBasedGuardingDynamicLinker)linker); + } else { + addTypeBased(llinkers, tblinkers); + llinkers.add(linker); + } + } + addTypeBased(llinkers, tblinkers); + return llinkers; + } + + private static void addTypeBased(List llinkers, + List tblinkers) { + switch(tblinkers.size()) { + case 0: { + break; + } + case 1: { + llinkers.addAll(tblinkers); + tblinkers.clear(); + break; + } + default: { + llinkers.add(new CompositeTypeBasedGuardingDynamicLinker(tblinkers)); + tblinkers.clear(); + break; + } + } + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/support/DefaultCallSiteDescriptor.java b/nashorn/src/jdk/internal/dynalink/support/DefaultCallSiteDescriptor.java new file mode 100644 index 00000000000..abf3ddad1a4 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/DefaultCallSiteDescriptor.java @@ -0,0 +1,135 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.CallSiteDescriptor; + + +/** + * A default, fairly light implementation of a call site descriptor used for describing non-standard operations. It does + * not store {@link Lookup} objects but always returns the public lookup from its {@link #getLookup()} method. If you + * need to support non-public lookup, you can use {@link LookupCallSiteDescriptor}. + * @author Attila Szegedi + */ +class DefaultCallSiteDescriptor extends AbstractCallSiteDescriptor { + + private final String[] tokenizedName; + private final MethodType methodType; + + DefaultCallSiteDescriptor(String[] tokenizedName, MethodType methodType) { + this.tokenizedName = tokenizedName; + this.methodType = methodType; + } + + @Override + public int getNameTokenCount() { + return tokenizedName.length; + } + + @Override + public String getNameToken(int i) { + try { + return tokenizedName[i]; + } catch(ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException(e.getMessage()); + } + } + + String[] getTokenizedName() { + return tokenizedName; + } + + @Override + public MethodType getMethodType() { + return methodType; + } + + @Override + public CallSiteDescriptor changeMethodType(MethodType newMethodType) { + return CallSiteDescriptorFactory.getCanonicalPublicDescriptor(new DefaultCallSiteDescriptor(tokenizedName, + newMethodType)); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/Guards.java b/nashorn/src/jdk/internal/dynalink/support/Guards.java new file mode 100644 index 00000000000..6107d4acca9 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/Guards.java @@ -0,0 +1,360 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.logging.Level; +import java.util.logging.Logger; +import jdk.internal.dynalink.linker.LinkerServices; + + +/** + * Utility methods for creating typical guards. TODO: introduce reasonable caching of created guards. + * + * @author Attila Szegedi + */ +public class Guards { + private static final Logger LOG = Logger + .getLogger(Guards.class.getName(), "jdk.internal.dynalink.support.messages"); + + private Guards() { + } + + /** + * Creates a guard method handle with arguments of a specified type, but with boolean return value. When invoked, it + * returns true if the first argument is of the specified class (exactly of it, not a subclass). The rest of the + * arguments will be ignored. + * + * @param clazz the class of the first argument to test for + * @param type the method type + * @return a method handle testing whether its first argument is of the specified class. + */ + @SuppressWarnings("boxing") + public static MethodHandle isOfClass(Class clazz, MethodType type) { + final Class declaredType = type.parameterType(0); + if(clazz == declaredType) { + LOG.log(Level.WARNING, "isOfClassGuardAlwaysTrue", new Object[] { clazz.getName(), 0, type }); + return constantTrue(type); + } + if(!declaredType.isAssignableFrom(clazz)) { + LOG.log(Level.WARNING, "isOfClassGuardAlwaysFalse", new Object[] { clazz.getName(), 0, type }); + return constantFalse(type); + } + return getClassBoundArgumentTest(IS_OF_CLASS, clazz, 0, type); + } + + /** + * Creates a method handle with arguments of a specified type, but with boolean return value. When invoked, it + * returns true if the first argument is instance of the specified class or its subclass). The rest of the arguments + * will be ignored. + * + * @param clazz the class of the first argument to test for + * @param type the method type + * @return a method handle testing whether its first argument is of the specified class or subclass. + */ + public static MethodHandle isInstance(Class clazz, MethodType type) { + return isInstance(clazz, 0, type); + } + + /** + * Creates a method handle with arguments of a specified type, but with boolean return value. When invoked, it + * returns true if the n'th argument is instance of the specified class or its subclass). The rest of the arguments + * will be ignored. + * + * @param clazz the class of the first argument to test for + * @param pos the position on the argument list to test + * @param type the method type + * @return a method handle testing whether its first argument is of the specified class or subclass. + */ + @SuppressWarnings("boxing") + public static MethodHandle isInstance(Class clazz, int pos, MethodType type) { + final Class declaredType = type.parameterType(pos); + if(clazz.isAssignableFrom(declaredType)) { + LOG.log(Level.WARNING, "isInstanceGuardAlwaysTrue", new Object[] { clazz.getName(), pos, type }); + return constantTrue(type); + } + if(!declaredType.isAssignableFrom(clazz)) { + LOG.log(Level.WARNING, "isInstanceGuardAlwaysFalse", new Object[] { clazz.getName(), pos, type }); + return constantFalse(type); + } + return getClassBoundArgumentTest(IS_INSTANCE, clazz, pos, type); + } + + /** + * Creates a method handle that returns true if the argument in the specified position is a Java array. + * + * @param pos the position in the argument lit + * @param type the method type of the handle + * @return a method handle that returns true if the argument in the specified position is a Java array; the rest of + * the arguments are ignored. + */ + @SuppressWarnings("boxing") + public static MethodHandle isArray(int pos, MethodType type) { + final Class declaredType = type.parameterType(pos); + if(declaredType.isArray()) { + LOG.log(Level.WARNING, "isArrayGuardAlwaysTrue", new Object[] { pos, type }); + return constantTrue(type); + } + if(!declaredType.isAssignableFrom(Object[].class)) { + LOG.log(Level.WARNING, "isArrayGuardAlwaysFalse", new Object[] { pos, type }); + return constantFalse(type); + } + return asType(IS_ARRAY, pos, type); + } + + /** + * Return true if it is safe to strongly reference a class from the referred class loader from a class associated + * with the referring class loader without risking a class loader memory leak. + * + * @param referrerLoader the referrer class loader + * @param referredLoader the referred class loader + * @return true if it is safe to strongly reference the class + */ + public static boolean canReferenceDirectly(ClassLoader referrerLoader, final ClassLoader referredLoader) { + if(referredLoader == null) { + // Can always refer directly to a system class + return true; + } + if(referrerLoader == null) { + // System classes can't refer directly to any non-system class + return false; + } + // Otherwise, can only refer directly to classes residing in same or + // parent class loader. + + ClassLoader referrer = referrerLoader; + do { + if(referrer == referredLoader) { + return true; + } + referrer = referrer.getParent(); + } while(referrer != null); + return false; + } + + private static MethodHandle getClassBoundArgumentTest(MethodHandle test, Class clazz, int pos, MethodType type) { + // Bind the class to the first argument of the test + return asType(test.bindTo(clazz), pos, type); + } + + /** + * Takes a guard-test method handle, and adapts it to the requested type, returning a boolean. Only applies + * conversions as per {@link MethodHandle#asType(MethodType)}. + * @param test the test method handle + * @param type the type to adapt the method handle to + * @return the adapted method handle + */ + public static MethodHandle asType(MethodHandle test, MethodType type) { + return test.asType(getTestType(test, type)); + } + + /** + * Takes a guard-test method handle, and adapts it to the requested type, returning a boolean. Applies the passed + * {@link LinkerServices} object's {@link LinkerServices#asType(MethodHandle, MethodType)}. + * @param linkerServices the linker services to use for type conversions + * @param test the test method handle + * @param type the type to adapt the method handle to + * @return the adapted method handle + */ + public static MethodHandle asType(LinkerServices linkerServices, MethodHandle test, MethodType type) { + return linkerServices.asType(test, getTestType(test, type)); + } + + private static MethodType getTestType(MethodHandle test, MethodType type) { + return type.dropParameterTypes(test.type().parameterCount(), + type.parameterCount()).changeReturnType(boolean.class); + } + + private static MethodHandle asType(MethodHandle test, int pos, MethodType type) { + assert test != null; + assert type != null; + assert type.parameterCount() > 0; + assert pos >= 0 && pos < type.parameterCount(); + assert test.type().parameterCount() == 1; + assert test.type().returnType() == Boolean.TYPE; + return MethodHandles.permuteArguments(test.asType(test.type().changeParameterType(0, type.parameterType(pos))), + type.changeReturnType(Boolean.TYPE), new int[] { pos }); + } + + private static final MethodHandle IS_OF_CLASS = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, + "isOfClass", MethodType.methodType(Boolean.TYPE, Class.class, Object.class)); + + private static final MethodHandle IS_INSTANCE = Lookup.PUBLIC.findVirtual(Class.class, "isInstance", + MethodType.methodType(Boolean.TYPE, Object.class)); + + private static final MethodHandle IS_ARRAY = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, "isArray", + MethodType.methodType(Boolean.TYPE, Object.class)); + + private static final MethodHandle IS_IDENTICAL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, + "isIdentical", MethodType.methodType(Boolean.TYPE, Object.class, Object.class)); + + private static final MethodHandle IS_NULL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, + "isNull", MethodType.methodType(Boolean.TYPE, Object.class)); + + private static final MethodHandle IS_NOT_NULL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, + "isNotNull", MethodType.methodType(Boolean.TYPE, Object.class)); + + /** + * Creates a guard method that tests its only argument for being of an exact particular class. + * @param clazz the class to test for. + * @return the desired guard method. + */ + public static MethodHandle getClassGuard(Class clazz) { + return IS_OF_CLASS.bindTo(clazz); + } + + /** + * Creates a guard method that tests its only argument for being an instance of a particular class. + * @param clazz the class to test for. + * @return the desired guard method. + */ + public static MethodHandle getInstanceOfGuard(Class clazz) { + return IS_INSTANCE.bindTo(clazz); + } + + /** + * Creates a guard method that tests its only argument for being referentially identical to another object + * @param obj the object used as referential identity test + * @return the desired guard method. + */ + public static MethodHandle getIdentityGuard(Object obj) { + return IS_IDENTICAL.bindTo(obj); + } + + /** + * Returns a guard that tests whether the first argument is null. + * @return a guard that tests whether the first argument is null. + */ + public static MethodHandle isNull() { + return IS_NULL; + } + + /** + * Returns a guard that tests whether the first argument is not null. + * @return a guard that tests whether the first argument is not null. + */ + public static MethodHandle isNotNull() { + return IS_NOT_NULL; + } + + @SuppressWarnings("unused") + private static boolean isNull(Object obj) { + return obj == null; + } + + @SuppressWarnings("unused") + private static boolean isNotNull(Object obj) { + return obj != null; + } + + @SuppressWarnings("unused") + private static boolean isArray(Object o) { + return o != null && o.getClass().isArray(); + } + + @SuppressWarnings("unused") + private static boolean isOfClass(Class c, Object o) { + return o != null && o.getClass() == c; + } + + @SuppressWarnings("unused") + private static boolean isIdentical(Object o1, Object o2) { + return o1 == o2; + } + + private static MethodHandle constantTrue(MethodType type) { + return constantBoolean(Boolean.TRUE, type); + } + + private static MethodHandle constantFalse(MethodType type) { + return constantBoolean(Boolean.FALSE, type); + } + + private static MethodHandle constantBoolean(Boolean value, MethodType type) { + return MethodHandles.permuteArguments(MethodHandles.constant(Boolean.TYPE, value), + type.changeReturnType(Boolean.TYPE)); + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/support/LinkRequestImpl.java b/nashorn/src/jdk/internal/dynalink/support/LinkRequestImpl.java new file mode 100644 index 00000000000..1ca14cffbef --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/LinkRequestImpl.java @@ -0,0 +1,143 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.LinkRequest; + +/** + * Default implementation of the {@link LinkRequest}, representing a link request to a call site that passes no language + * runtime specific native context arguments on the stack. + * + * @author Attila Szegedi + */ +public class LinkRequestImpl implements LinkRequest { + + private final CallSiteDescriptor callSiteDescriptor; + private final Object[] arguments; + private final boolean callSiteUnstable; + + /** + * Creates a new link request. + * + * @param callSiteDescriptor the descriptor for the call site being linked + * @param callSiteUnstable true if the call site being linked is considered unstable + * @param arguments the arguments for the invocation + */ + public LinkRequestImpl(CallSiteDescriptor callSiteDescriptor, boolean callSiteUnstable, Object... arguments) { + this.callSiteDescriptor = callSiteDescriptor; + this.callSiteUnstable = callSiteUnstable; + this.arguments = arguments; + } + + @Override + public Object[] getArguments() { + return arguments != null ? arguments.clone() : null; + } + + @Override + public Object getReceiver() { + return arguments != null && arguments.length > 0 ? arguments[0] : null; + } + + @Override + public CallSiteDescriptor getCallSiteDescriptor() { + return callSiteDescriptor; + } + + @Override + public boolean isCallSiteUnstable() { + return callSiteUnstable; + } + + @Override + public LinkRequest withoutRuntimeContext() { + return this; + } + + @Override + public LinkRequest replaceArguments(CallSiteDescriptor newCallSiteDescriptor, Object[] newArguments) { + return new LinkRequestImpl(newCallSiteDescriptor, callSiteUnstable, newArguments); + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/support/LinkerServicesImpl.java b/nashorn/src/jdk/internal/dynalink/support/LinkerServicesImpl.java new file mode 100644 index 00000000000..42c37cbda27 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/LinkerServicesImpl.java @@ -0,0 +1,141 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.linker.ConversionComparator.Comparison; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; + + +/** + * Default implementation of the {@link LinkerServices} interface. + * + * @author Attila Szegedi + */ +public class LinkerServicesImpl implements LinkerServices { + + private final TypeConverterFactory typeConverterFactory; + private final GuardingDynamicLinker topLevelLinker; + + /** + * Creates a new linker services object. + * + * @param typeConverterFactory the type converter factory exposed by the services. + * @param topLevelLinker the top level linker used by the services. + */ + public LinkerServicesImpl(final TypeConverterFactory typeConverterFactory, + final GuardingDynamicLinker topLevelLinker) { + this.typeConverterFactory = typeConverterFactory; + this.topLevelLinker = topLevelLinker; + } + + @Override + public boolean canConvert(Class from, Class to) { + return typeConverterFactory.canConvert(from, to); + } + + @Override + public MethodHandle asType(MethodHandle handle, MethodType fromType) { + return typeConverterFactory.asType(handle, fromType); + } + + @Override + public MethodHandle getTypeConverter(Class sourceType, Class targetType) { + return typeConverterFactory.getTypeConverter(sourceType, targetType); + } + + @Override + public Comparison compareConversion(Class sourceType, Class targetType1, Class targetType2) { + return typeConverterFactory.compareConversion(sourceType, targetType1, targetType2); + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest) throws Exception { + return topLevelLinker.getGuardedInvocation(linkRequest, this); + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/support/Lookup.java b/nashorn/src/jdk/internal/dynalink/support/Lookup.java new file mode 100644 index 00000000000..cff6e943cea --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/Lookup.java @@ -0,0 +1,361 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * A wrapper around MethodHandles.Lookup that masks checked exceptions in those cases when you're looking up methods + * within your own codebase (therefore it is an error if they are not present). + * + * @author Attila Szegedi + */ +public class Lookup { + private final MethodHandles.Lookup lookup; + + /** + * Creates a new instance, bound to an instance of {@link java.lang.invoke.MethodHandles.Lookup}. + * + * @param lookup the {@link java.lang.invoke.MethodHandles.Lookup} it delegates to. + */ + public Lookup(MethodHandles.Lookup lookup) { + this.lookup = lookup; + } + + /** + * A canonical Lookup object that wraps {@link MethodHandles#publicLookup()}. + */ + public static final Lookup PUBLIC = new Lookup(MethodHandles.publicLookup()); + + /** + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, converting any encountered + * {@link IllegalAccessException} into an {@link IllegalAccessError}. + * + * @param m the method to unreflect + * @return the unreflected method handle. + */ + public MethodHandle unreflect(Method m) { + try { + return lookup.unreflect(m); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect method " + m); + ee.initCause(e); + throw ee; + } + } + + + /** + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter(Field)}, converting any encountered + * {@link IllegalAccessException} into an {@link IllegalAccessError}. + * + * @param f the field for which a getter is unreflected + * @return the unreflected field getter handle. + */ + public MethodHandle unreflectGetter(Field f) { + try { + return lookup.unreflectGetter(f); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect getter for field " + f); + ee.initCause(e); + throw ee; + } + } + + /** + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#findGetter(Class, String, Class)}, converting any + * encountered {@link IllegalAccessException} into an {@link IllegalAccessError} and {@link NoSuchFieldException} + * into a {@link NoSuchFieldError}. + * + * @param refc the class declaring the field + * @param name the name of the field + * @param type the type of the field + * @return the unreflected field getter handle. + * @throws IllegalAccessError if the field is inaccessible. + * @throws NoSuchFieldError if the field does not exist. + */ + public MethodHandle findGetter(Classrefc, String name, Class type) { + try { + return lookup.findGetter(refc, name, type); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to access getter for field " + refc.getName() + + "." + name + " of type " + type.getName()); + ee.initCause(e); + throw ee; + } catch(NoSuchFieldException e) { + final NoSuchFieldError ee = new NoSuchFieldError("Failed to find getter for field " + refc.getName() + + "." + name + " of type " + type.getName()); + ee.initCause(e); + throw ee; + } + } + + /** + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectSetter(Field)}, converting any encountered + * {@link IllegalAccessException} into an {@link IllegalAccessError}. + * + * @param f the field for which a setter is unreflected + * @return the unreflected field setter handle. + */ + public MethodHandle unreflectSetter(Field f) { + try { + return lookup.unreflectSetter(f); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect setter for field " + f); + ee.initCause(e); + throw ee; + } + } + + /** + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)}, converting any + * encountered {@link IllegalAccessException} into an {@link IllegalAccessError}. + * + * @param c the constructor to unreflect + * @return the unreflected constructor handle. + */ + public MethodHandle unreflectConstructor(Constructor c) { + try { + return lookup.unreflectConstructor(c); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect constructor " + c); + ee.initCause(e); + throw ee; + } + } + + /** + * Performs a findSpecial on the underlying lookup, except for the backport where it rather uses unreflect. Converts + * any encountered {@link IllegalAccessException} into an {@link IllegalAccessError} and a + * {@link NoSuchMethodException} into a {@link NoSuchMethodError}. + * + * @param declaringClass class declaring the method + * @param name the name of the method + * @param type the type of the method + * @return a method handle for the method + * @throws IllegalAccessError if the method is inaccessible. + * @throws NoSuchMethodError if the method does not exist. + */ + public MethodHandle findSpecial(Class declaringClass, String name, MethodType type) { + try { + if(Backport.inUse) { + final Method m = declaringClass.getDeclaredMethod(name, type.parameterArray()); + if(!Modifier.isPublic(declaringClass.getModifiers()) || !Modifier.isPublic(m.getModifiers())) { + m.setAccessible(true); + } + return unreflect(m); + } else { + return lookup.findSpecial(declaringClass, name, type, declaringClass); + } + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to access special method " + methodDescription( + declaringClass, name, type)); + ee.initCause(e); + throw ee; + } catch(NoSuchMethodException e) { + final NoSuchMethodError ee = new NoSuchMethodError("Failed to find special method " + methodDescription( + declaringClass, name, type)); + ee.initCause(e); + throw ee; + } + } + + private static String methodDescription(Class declaringClass, String name, MethodType type) { + return declaringClass.getName() + "#" + name + type; + } + + /** + * Performs a findStatic on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an + * {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}. + * + * @param declaringClass class declaring the method + * @param name the name of the method + * @param type the type of the method + * @return a method handle for the method + * @throws IllegalAccessError if the method is inaccessible. + * @throws NoSuchMethodError if the method does not exist. + */ + public MethodHandle findStatic(Class declaringClass, String name, MethodType type) { + try { + return lookup.findStatic(declaringClass, name, type); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to access static method " + methodDescription( + declaringClass, name, type)); + ee.initCause(e); + throw ee; + } catch(NoSuchMethodException e) { + final NoSuchMethodError ee = new NoSuchMethodError("Failed to find static method " + methodDescription( + declaringClass, name, type)); + ee.initCause(e); + throw ee; + } + } + + /** + * Performs a findVirtual on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an + * {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}. + * + * @param declaringClass class declaring the method + * @param name the name of the method + * @param type the type of the method + * @return a method handle for the method + * @throws IllegalAccessError if the method is inaccessible. + * @throws NoSuchMethodError if the method does not exist. + */ + public MethodHandle findVirtual(Class declaringClass, String name, MethodType type) { + try { + return lookup.findVirtual(declaringClass, name, type); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to access virtual method " + methodDescription( + declaringClass, name, type)); + ee.initCause(e); + throw ee; + } catch(NoSuchMethodException e) { + final NoSuchMethodError ee = new NoSuchMethodError("Failed to find virtual method " + methodDescription( + declaringClass, name, type)); + ee.initCause(e); + throw ee; + } + } + + /** + * Given a lookup, finds using {@link #findSpecial(Class, String, MethodType)} a method on that lookup's class. + * Useful in classes' code for convenient linking to their own privates. + * @param lookup the lookup for the class + * @param name the name of the method + * @param rtype the return type of the method + * @param ptypes the parameter types of the method + * @return the method handle for the method + */ + public static MethodHandle findOwnSpecial(MethodHandles.Lookup lookup, String name, Class rtype, Class... ptypes) { + return new Lookup(lookup).findOwnSpecial(name, rtype, ptypes); + } + + + /** + * Finds using {@link #findSpecial(Class, String, MethodType)} a method on that lookup's class. Useful in classes' + * code for convenient linking to their own privates. It's easier to use than {@code findSpecial} in that you can + * just list the parameter types, and don't have to specify lookup class. + * @param name the name of the method + * @param rtype the return type of the method + * @param ptypes the parameter types of the method + * @return the method handle for the method + */ + public MethodHandle findOwnSpecial(String name, Class rtype, Class... ptypes) { + return findSpecial(lookup.lookupClass(), name, MethodType.methodType(rtype, ptypes)); + } + + /** + * Given a lookup, finds using {@link #findStatic(Class, String, MethodType)} a method on that lookup's class. + * Useful in classes' code for convenient linking to their own privates. It's easier to use than {@code findStatic} + * in that you can just list the parameter types, and don't have to specify lookup class. + * @param lookup the lookup for the class + * @param name the name of the method + * @param rtype the return type of the method + * @param ptypes the parameter types of the method + * @return the method handle for the method + */ + public static MethodHandle findOwnStatic(MethodHandles.Lookup lookup, String name, Class rtype, Class... ptypes) { + return new Lookup(lookup).findOwnStatic(name, rtype, ptypes); + } + + /** + * Finds using {@link #findStatic(Class, String, MethodType)} a method on that lookup's class. Useful in classes' + * code for convenient linking to their own privates. It's easier to use than {@code findStatic} in that you can + * just list the parameter types, and don't have to specify lookup class. + * @param name the name of the method + * @param rtype the return type of the method + * @param ptypes the parameter types of the method + * @return the method handle for the method + */ + public MethodHandle findOwnStatic(String name, Class rtype, Class... ptypes) { + return findStatic(lookup.lookupClass(), name, MethodType.methodType(rtype, ptypes)); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/LookupCallSiteDescriptor.java b/nashorn/src/jdk/internal/dynalink/support/LookupCallSiteDescriptor.java new file mode 100644 index 00000000000..655685c4aa3 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/LookupCallSiteDescriptor.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.CallSiteDescriptor; + + +/** + * A call site descriptor that stores a specific {@link Lookup}. It does not, however, store static bootstrap arguments. + * @author Attila Szegedi + */ +class LookupCallSiteDescriptor extends DefaultCallSiteDescriptor { + private Lookup lookup; + + /** + * Create a new call site descriptor from explicit information. + * @param tokenizedName the name of the method + * @param methodType the method type + * @param lookup the lookup + */ + LookupCallSiteDescriptor(String[] tokenizedName, MethodType methodType, Lookup lookup) { + super(tokenizedName, methodType); + this.lookup = lookup; + } + + @Override + public Lookup getLookup() { + return lookup; + } + + @Override + public CallSiteDescriptor changeMethodType(MethodType newMethodType) { + return new LookupCallSiteDescriptor(getTokenizedName(), newMethodType, lookup); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/NameCodec.java b/nashorn/src/jdk/internal/dynalink/support/NameCodec.java new file mode 100644 index 00000000000..1c7cd29b95f --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/NameCodec.java @@ -0,0 +1,218 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import jdk.internal.dynalink.CallSiteDescriptor; + +/** + * Implements the name mangling and demangling as specified by John Rose's + * "Symbolic Freedom in the + * VM" article. It is recommended that implementers of languages on the JVM uniformly adopt this for symbolic + * interoperability between languages. Normally, you would mangle the names as you're generating bytecode, and then + * demangle them when you're creating {@link CallSiteDescriptor} objects. Note that you are expected to mangle + * individual tokens, and not the whole name at the call site, i.e. the colon character normally separating the tokens + * is never mangled. I.e. you wouldn't mangle {@code dyn:getProp:color} into {@code dyn\!getProp\!color}, but you would + * mangle {@code dyn:getProp:color$} into {@code dyn:getProp:\=color\%} (only mangling the individual token containing + * the symbol {@code color$}). {@link CallSiteDescriptorFactory#tokenizeName(String)} (and by implication, all call site + * descriptors it creates) will automatically perform demangling on the passed names. If you use this factory, or you + * have your own way of creating call site descriptors, but you still delegate to this method of the default factory + * (it is recommended that you do), then you have demangling handled for you already, and only need to ensure that you + * mangle the names when you're emitting them in the bytecode. + * + * @author Attila Szegedi + */ +public class NameCodec { + private static final char ESCAPE_CHAR = '\\'; + private static final char EMPTY_ESCAPE = '='; + private static final String EMPTY_NAME = new String(new char[] { ESCAPE_CHAR, EMPTY_ESCAPE }); + private static final char EMPTY_CHAR = 0xFEFF; + + private static final int MIN_ENCODING = '$'; + private static final int MAX_ENCODING = ']'; + private static final char[] ENCODING = new char[MAX_ENCODING - MIN_ENCODING + 1]; + private static final int MIN_DECODING = '!'; + private static final int MAX_DECODING = '}'; + private static final char[] DECODING = new char[MAX_DECODING - MIN_DECODING + 1]; + + static { + addEncoding('/', '|'); + addEncoding('.', ','); + addEncoding(';', '?'); + addEncoding('$', '%'); + addEncoding('<', '^'); + addEncoding('>', '_'); + addEncoding('[', '{'); + addEncoding(']', '}'); + addEncoding(':', '!'); + addEncoding('\\', '-'); + DECODING[EMPTY_ESCAPE - MIN_DECODING] = EMPTY_CHAR; + } + + private NameCodec() { + } + + /** + * Encodes ("mangles") an unencoded symbolic name. + * @param name the symbolic name to mangle + * @return the mangled form of the symbolic name. + */ + public static String encode(String name) { + final int l = name.length(); + if(l == 0) { + return EMPTY_NAME; + } + StringBuilder b = null; + int lastEscape = -1; + for(int i = 0; i < l; ++i) { + final int encodeIndex = name.charAt(i) - MIN_ENCODING; + if(encodeIndex >= 0 && encodeIndex < ENCODING.length) { + final char e = ENCODING[encodeIndex]; + if(e != 0) { + if(b == null) { + b = new StringBuilder(name.length() + 3); + if(name.charAt(0) != ESCAPE_CHAR && i > 0) { + b.append(EMPTY_NAME); + } + b.append(name, 0, i); + } else { + b.append(name, lastEscape + 1, i); + } + b.append(ESCAPE_CHAR).append(e); + lastEscape = i; + } + } + } + if(b == null) { + return name.toString(); + } + assert lastEscape != -1; + b.append(name, lastEscape + 1, l); + return b.toString(); + } + + /** + * Decodes ("demangles") an encoded symbolic name. + * @param name the symbolic name to demangle + * @return the demangled form of the symbolic name. + */ + public static String decode(String name) { + if(name.charAt(0) != ESCAPE_CHAR) { + return name; + } + final int l = name.length(); + if(l == 2 && name.charAt(1) == EMPTY_CHAR) { + return ""; + } + StringBuilder b = new StringBuilder(name.length()); + int lastEscape = -2; + int lastBackslash = -1; + for(;;) { + int nextBackslash = name.indexOf(ESCAPE_CHAR, lastBackslash + 1); + if(nextBackslash == -1 || nextBackslash == l - 1) { + break; + } + final int decodeIndex = name.charAt(nextBackslash + 1) - MIN_DECODING; + if(decodeIndex >= 0 && decodeIndex < DECODING.length) { + final char d = DECODING[decodeIndex]; + if(d == EMPTY_CHAR) { + // "\=" is only valid at the beginning of a mangled string + if(nextBackslash == 0) { + lastEscape = 0; + } + } else if(d != 0) { + b.append(name, lastEscape + 2, nextBackslash).append(d); + lastEscape = nextBackslash; + } + } + lastBackslash = nextBackslash; + } + b.append(name, lastEscape + 2, l); + return b.toString(); + } + + private static void addEncoding(char from, char to) { + ENCODING[from - MIN_ENCODING] = to; + DECODING[to - MIN_DECODING] = from; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/NamedDynCallSiteDescriptor.java b/nashorn/src/jdk/internal/dynalink/support/NamedDynCallSiteDescriptor.java new file mode 100644 index 00000000000..79c5d1f3e77 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/NamedDynCallSiteDescriptor.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.CallSiteDescriptor; + + +class NamedDynCallSiteDescriptor extends UnnamedDynCallSiteDescriptor { + private final String name; + + NamedDynCallSiteDescriptor(String op, String name, MethodType methodType) { + super(op, methodType); + this.name = name; + } + + @Override + public int getNameTokenCount() { + return 3; + } + + @Override + public String getNameToken(int i) { + switch(i) { + case 0: return "dyn"; + case 1: return getOp(); + case 2: return name; + default: throw new IndexOutOfBoundsException(String.valueOf(i)); + } + } + + @Override + public CallSiteDescriptor changeMethodType(MethodType newMethodType) { + return CallSiteDescriptorFactory.getCanonicalPublicDescriptor(new NamedDynCallSiteDescriptor(getOp(), name, + newMethodType)); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/RuntimeContextLinkRequestImpl.java b/nashorn/src/jdk/internal/dynalink/support/RuntimeContextLinkRequestImpl.java new file mode 100644 index 00000000000..efd20455965 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/RuntimeContextLinkRequestImpl.java @@ -0,0 +1,142 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.LinkRequest; + +/** + * A link request implementation for call sites that pass language runtime specific context arguments on the stack. The + * context specific arguments should be the first "n" arguments. + * + * @author Attila Szegedi + */ +public class RuntimeContextLinkRequestImpl extends LinkRequestImpl { + + private final int runtimeContextArgCount; + private LinkRequestImpl contextStrippedRequest; + + /** + * Creates a new link request. + * + * @param callSiteDescriptor the descriptor for the call site being linked + * @param arguments the arguments for the invocation + * @param callSiteUnstable true if the call site being linked is considered unstable + * @param runtimeContextArgCount the number of the leading arguments on the stack that represent the language + * runtime specific context arguments. + * @throws IllegalArgumentException if runtimeContextArgCount is less than 1. + */ + public RuntimeContextLinkRequestImpl(CallSiteDescriptor callSiteDescriptor, boolean callSiteUnstable, + Object[] arguments, int runtimeContextArgCount) { + super(callSiteDescriptor, callSiteUnstable, arguments); + if(runtimeContextArgCount < 1) { + throw new IllegalArgumentException("runtimeContextArgCount < 1"); + } + this.runtimeContextArgCount = runtimeContextArgCount; + } + + @Override + public LinkRequest withoutRuntimeContext() { + if(contextStrippedRequest == null) { + contextStrippedRequest = + new LinkRequestImpl(CallSiteDescriptorFactory.dropParameterTypes(getCallSiteDescriptor(), 1, + runtimeContextArgCount + 1), isCallSiteUnstable(), getTruncatedArguments()); + } + return contextStrippedRequest; + } + + @Override + public LinkRequest replaceArguments(CallSiteDescriptor callSiteDescriptor, Object[] arguments) { + return new RuntimeContextLinkRequestImpl(callSiteDescriptor, isCallSiteUnstable(), arguments, + runtimeContextArgCount); + } + + private Object[] getTruncatedArguments() { + final Object[] args = getArguments(); + final Object[] newargs = new Object[args.length - runtimeContextArgCount]; + newargs[0] = args[0]; // "this" remains at the 0th position + System.arraycopy(args, runtimeContextArgCount + 1, newargs, 1, newargs.length - 1); + return newargs; + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java b/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java new file mode 100644 index 00000000000..2fed7db7a8f --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java @@ -0,0 +1,320 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.WrongMethodTypeException; +import java.util.LinkedList; +import java.util.List; +import jdk.internal.dynalink.linker.ConversionComparator; +import jdk.internal.dynalink.linker.ConversionComparator.Comparison; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; +import jdk.internal.dynalink.linker.LinkerServices; + + +/** + * A factory for type converters. This class is the main implementation behind the + * {@link LinkerServices#asType(MethodHandle, MethodType)}. It manages the known {@link GuardingTypeConverterFactory} + * instances and creates appropriate converters for method handles. + * + * @author Attila Szegedi + */ +public class TypeConverterFactory { + + private final GuardingTypeConverterFactory[] factories; + private final ConversionComparator[] comparators; + + private final ClassValue> converterMap = new ClassValue>() { + @Override + protected ClassMap computeValue(final Class sourceType) { + return new ClassMap(sourceType.getClassLoader()) { + @Override + protected MethodHandle computeValue(Class targetType) { + try { + return createConverter(sourceType, targetType); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }; + } + }; + + private final ClassValue> converterIdentityMap = new ClassValue>() { + @Override + protected ClassMap computeValue(final Class sourceType) { + return new ClassMap(sourceType.getClassLoader()) { + @Override + protected MethodHandle computeValue(Class targetType) { + if(!canAutoConvert(sourceType, targetType)) { + final MethodHandle converter = getTypeConverterNull(sourceType, targetType); + if(converter != null) { + return converter; + } + } + return IDENTITY_CONVERSION.asType(MethodType.methodType(targetType, sourceType)); + } + }; + } + }; + + /** + * Creates a new type converter factory from the available {@link GuardingTypeConverterFactory} instances. + * + * @param factories the {@link GuardingTypeConverterFactory} instances to compose. + */ + public TypeConverterFactory(Iterable factories) { + final List l = new LinkedList<>(); + final List c = new LinkedList<>(); + for(GuardingTypeConverterFactory factory: factories) { + l.add(factory); + if(factory instanceof ConversionComparator) { + c.add((ConversionComparator)factory); + } + } + this.factories = l.toArray(new GuardingTypeConverterFactory[l.size()]); + this.comparators = c.toArray(new ConversionComparator[c.size()]); + + } + + /** + * Similar to {@link MethodHandle#asType(MethodType)} except it also hooks in method handles produced by + * {@link GuardingTypeConverterFactory} implementations, providing for language-specific type coercing of + * parameters. It will apply {@link MethodHandle#asType(MethodType)} for all primitive-to-primitive, + * wrapper-to-primitive, primitive-to-wrapper conversions as well as for all upcasts. For all other conversions, + * it'll insert {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with composite filters + * provided by {@link GuardingTypeConverterFactory} implementations. + * + * @param handle target method handle + * @param fromType the types of source arguments + * @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)} and + * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with + * {@link GuardingTypeConverterFactory} produced type converters as filters. + */ + public MethodHandle asType(MethodHandle handle, final MethodType fromType) { + MethodHandle newHandle = handle; + final MethodType toType = newHandle.type(); + final int l = toType.parameterCount(); + if(l != fromType.parameterCount()) { + throw new WrongMethodTypeException("Parameter counts differ: " + handle.type() + " vs. " + fromType); + } + int pos = 0; + final List converters = new LinkedList<>(); + for(int i = 0; i < l; ++i) { + final Class fromParamType = fromType.parameterType(i); + final Class toParamType = toType.parameterType(i); + if(canAutoConvert(fromParamType, toParamType)) { + newHandle = applyConverters(newHandle, pos, converters); + } else { + final MethodHandle converter = getTypeConverterNull(fromParamType, toParamType); + if(converter != null) { + if(converters.isEmpty()) { + pos = i; + } + converters.add(converter); + } else { + newHandle = applyConverters(newHandle, pos, converters); + } + } + } + newHandle = applyConverters(newHandle, pos, converters); + + // Convert return type + final Class fromRetType = fromType.returnType(); + final Class toRetType = toType.returnType(); + if(fromRetType != Void.TYPE && toRetType != Void.TYPE) { + if(!canAutoConvert(toRetType, fromRetType)) { + final MethodHandle converter = getTypeConverterNull(toRetType, fromRetType); + if(converter != null) { + newHandle = MethodHandles.filterReturnValue(newHandle, converter); + } + } + } + + // Take care of automatic conversions + return newHandle.asType(fromType); + } + + private static MethodHandle applyConverters(MethodHandle handle, int pos, List converters) { + if(converters.isEmpty()) { + return handle; + } + final MethodHandle newHandle = + MethodHandles.filterArguments(handle, pos, converters.toArray(new MethodHandle[converters.size()])); + converters.clear(); + return newHandle; + } + + /** + * Returns true if there might exist a conversion between the requested types (either an automatic JVM conversion, + * or one provided by any available {@link GuardingTypeConverterFactory}), or false if there definitely does not + * exist a conversion between the requested types. Note that returning true does not guarantee that the conversion + * will succeed at runtime (notably, if the "from" or "to" types are sufficiently generic), but returning false + * guarantees that it would fail. + * + * @param from the source type for the conversion + * @param to the target type for the conversion + * @return true if there can be a conversion, false if there can not. + */ + public boolean canConvert(final Class from, final Class to) { + return canAutoConvert(from, to) || getTypeConverterNull(from, to) != null; + } + + /** + * Determines which of the two type conversions from a source type to the two target types is preferred. This is + * used for dynamic overloaded method resolution. If the source type is convertible to exactly one target type with + * a method invocation conversion, it is chosen, otherwise available {@link ConversionComparator}s are consulted. + * @param sourceType the source type. + * @param targetType1 one potential target type + * @param targetType2 another potential target type. + * @return one of Comparison constants that establish which - if any - of the target types is preferable for the + * conversion. + */ + public Comparison compareConversion(Class sourceType, Class targetType1, Class targetType2) { + for(ConversionComparator comparator: comparators) { + final Comparison result = comparator.compareConversion(sourceType, targetType1, targetType2); + if(result != Comparison.INDETERMINATE) { + return result; + } + } + if(TypeUtilities.isMethodInvocationConvertible(sourceType, targetType1)) { + if(!TypeUtilities.isMethodInvocationConvertible(sourceType, targetType2)) { + return Comparison.TYPE_1_BETTER; + } + } else if(TypeUtilities.isMethodInvocationConvertible(sourceType, targetType2)) { + return Comparison.TYPE_2_BETTER; + } + return Comparison.INDETERMINATE; + } + + /** + * Determines whether it's safe to perform an automatic conversion between the source and target class. + * + * @param fromType convert from this class + * @param toType convert to this class + * @return true if it's safe to let MethodHandles.convertArguments() to handle this conversion. + */ + /*private*/ static boolean canAutoConvert(final Class fromType, final Class toType) { + return TypeUtilities.isMethodInvocationConvertible(fromType, toType); + } + + /*private*/ MethodHandle getTypeConverterNull(Class sourceType, Class targetType) { + final MethodHandle converter = converterMap.get(sourceType).get(targetType); + return converter == IDENTITY_CONVERSION ? null : converter; + } + + /** + * Given a source and target type, returns a method handle that converts between them. Never returns null; in worst + * case it will return an identity conversion (that might fail for some values at runtime). You can use this method + * if you have a piece of your program that is written in Java, and you need to reuse existing type conversion + * machinery in a non-invokedynamic context. + * @param sourceType the type to convert from + * @param targetType the type to convert to + * @return a method handle performing the conversion. + */ + public MethodHandle getTypeConverter(Class sourceType, Class targetType) { + return converterIdentityMap.get(sourceType).get(targetType); + } + + /*private*/ MethodHandle createConverter(Class sourceType, Class targetType) throws Exception { + final MethodType type = MethodType.methodType(targetType, sourceType); + final MethodHandle identity = IDENTITY_CONVERSION.asType(type); + MethodHandle last = identity; + for(int i = factories.length; i-- > 0;) { + final GuardedInvocation next = factories[i].convertToType(sourceType, targetType); + if(next != null) { + next.assertType(type); + last = next.compose(last); + } + } + return last == identity ? IDENTITY_CONVERSION : last; + } + + /*private*/ static final MethodHandle IDENTITY_CONVERSION = MethodHandles.identity(Object.class); +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/support/TypeUtilities.java b/nashorn/src/jdk/internal/dynalink/support/TypeUtilities.java new file mode 100644 index 00000000000..a534b091b26 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/TypeUtilities.java @@ -0,0 +1,442 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Various static utility methods for testing type relationships. + * + * @author Attila Szegedi + */ +public class TypeUtilities { + static final Class OBJECT_CLASS = Object.class; + + private TypeUtilities() { + } + + /** + * Given two types represented by c1 and c2, returns a type that is their most specific common superclass or + * superinterface. + * + * @param c1 one type + * @param c2 another type + * @return their most common superclass or superinterface. If they have several unrelated superinterfaces as their + * most specific common type, or the types themselves are completely unrelated interfaces, {@link java.lang.Object} + * is returned. + */ + public static Class getMostSpecificCommonType(Class c1, Class c2) { + if(c1 == c2) { + return c1; + } + Class c3 = c2; + if(c3.isPrimitive()) { + if(c3 == Byte.TYPE) + c3 = Byte.class; + else if(c3 == Short.TYPE) + c3 = Short.class; + else if(c3 == Character.TYPE) + c3 = Character.class; + else if(c3 == Integer.TYPE) + c3 = Integer.class; + else if(c3 == Float.TYPE) + c3 = Float.class; + else if(c3 == Long.TYPE) + c3 = Long.class; + else if(c3 == Double.TYPE) + c3 = Double.class; + } + Set> a1 = getAssignables(c1, c3); + Set> a2 = getAssignables(c3, c1); + a1.retainAll(a2); + if(a1.isEmpty()) { + // Can happen when at least one of the arguments is an interface, + // as they don't have Object at the root of their hierarchy. + return Object.class; + } + // Gather maximally specific elements. Yes, there can be more than one + // thank to interfaces. I.e., if you call this method for String.class + // and Number.class, you'll have Comparable, Serializable, and Object + // as maximal elements. + List> max = new ArrayList<>(); + outer: for(Class clazz: a1) { + for(Iterator> maxiter = max.iterator(); maxiter.hasNext();) { + Class maxClazz = maxiter.next(); + if(isSubtype(maxClazz, clazz)) { + // It can't be maximal, if there's already a more specific + // maximal than it. + continue outer; + } + if(isSubtype(clazz, maxClazz)) { + // If it's more specific than a currently maximal element, + // that currently maximal is no longer a maximal. + maxiter.remove(); + } + } + // If we get here, no current maximal is more specific than the + // current class, so it is considered maximal as well + max.add(clazz); + } + if(max.size() > 1) { + return OBJECT_CLASS; + } + return max.get(0); + } + + private static Set> getAssignables(Class c1, Class c2) { + Set> s = new HashSet<>(); + collectAssignables(c1, c2, s); + return s; + } + + private static void collectAssignables(Class c1, Class c2, Set> s) { + if(c1.isAssignableFrom(c2)) { + s.add(c1); + } + Class sc = c1.getSuperclass(); + if(sc != null) { + collectAssignables(sc, c2, s); + } + Class[] itf = c1.getInterfaces(); + for(int i = 0; i < itf.length; ++i) { + collectAssignables(itf[i], c2, s); + } + } + + private static final Map, Class> WRAPPER_TYPES = createWrapperTypes(); + private static final Map, Class> PRIMITIVE_TYPES = invertMap(WRAPPER_TYPES); + private static final Map> PRIMITIVE_TYPES_BY_NAME = createClassNameMapping(WRAPPER_TYPES.keySet()); + + private static Map, Class> createWrapperTypes() { + final Map, Class> wrapperTypes = new IdentityHashMap<>(8); + wrapperTypes.put(Boolean.TYPE, Boolean.class); + wrapperTypes.put(Byte.TYPE, Byte.class); + wrapperTypes.put(Character.TYPE, Character.class); + wrapperTypes.put(Short.TYPE, Short.class); + wrapperTypes.put(Integer.TYPE, Integer.class); + wrapperTypes.put(Long.TYPE, Long.class); + wrapperTypes.put(Float.TYPE, Float.class); + wrapperTypes.put(Double.TYPE, Double.class); + return Collections.unmodifiableMap(wrapperTypes); + } + + private static Map> createClassNameMapping(Collection> classes) { + final Map> map = new HashMap<>(); + for(Class clazz: classes) { + map.put(clazz.getName(), clazz); + } + return map; + } + + private static Map invertMap(Map map) { + final Map inverted = new IdentityHashMap<>(map.size()); + for(Map.Entry entry: map.entrySet()) { + inverted.put(entry.getValue(), entry.getKey()); + } + return Collections.unmodifiableMap(inverted); + } + + /** + * Determines whether one type can be converted to another type using a method invocation conversion, as per JLS 5.3 + * "Method Invocation Conversion". This is basically all conversions allowed by subtyping (see + * {@link #isSubtype(Class, Class)}) as well as boxing conversion (JLS 5.1.7) optionally followed by widening + * reference conversion and unboxing conversion (JLS 5.1.8) optionally followed by widening primitive conversion. + * + * @param callSiteType the parameter type at the call site + * @param methodType the parameter type in the method declaration + * @return true if callSiteType is method invocation convertible to the methodType. + */ + public static boolean isMethodInvocationConvertible(Class callSiteType, Class methodType) { + if(methodType.isAssignableFrom(callSiteType)) { + return true; + } + if(callSiteType.isPrimitive()) { + if(methodType.isPrimitive()) { + return isProperPrimitiveSubtype(callSiteType, methodType); + } + // Boxing + widening reference conversion + return methodType.isAssignableFrom(WRAPPER_TYPES.get(callSiteType)); + } + if(methodType.isPrimitive()) { + final Class unboxedCallSiteType = PRIMITIVE_TYPES.get(callSiteType); + return unboxedCallSiteType != null + && (unboxedCallSiteType == methodType || isProperPrimitiveSubtype(unboxedCallSiteType, methodType)); + } + return false; + } + + /** + * Determines whether one type can be potentially converted to another type at runtime. Allows a conversion between + * any subtype and supertype in either direction, and also allows a conversion between any two primitive types, as + * well as between any primitive type and any reference type that can hold a boxed primitive. + * + * @param callSiteType the parameter type at the call site + * @param methodType the parameter type in the method declaration + * @return true if callSiteType is potentially convertible to the methodType. + */ + public static boolean isPotentiallyConvertible(Class callSiteType, Class methodType) { + // Widening or narrowing reference conversion + if(methodType.isAssignableFrom(callSiteType) || callSiteType.isAssignableFrom(methodType)) { + return true; + } + if(callSiteType.isPrimitive()) { + // Allow any conversion among primitives, as well as from any + // primitive to any type that can receive a boxed primitive. + // TODO: narrow this a bit, i.e. allow, say, boolean to Character? + // MethodHandles.convertArguments() allows it, so we might need to + // too. + return methodType.isPrimitive() || isAssignableFromBoxedPrimitive(methodType); + } + if(methodType.isPrimitive()) { + // Allow conversion from any reference type that can contain a + // boxed primitive to any primitive. + // TODO: narrow this a bit too? + return isAssignableFromBoxedPrimitive(callSiteType); + } + return false; + } + + /** + * Determines whether one type is a subtype of another type, as per JLS 4.10 "Subtyping". Note: this is not strict + * or proper subtype, therefore true is also returned for identical types; to be completely precise, it allows + * identity conversion (JLS 5.1.1), widening primitive conversion (JLS 5.1.2) and widening reference conversion (JLS + * 5.1.5). + * + * @param subType the supposed subtype + * @param superType the supposed supertype of the subtype + * @return true if subType can be converted by identity conversion, widening primitive conversion, or widening + * reference conversion to superType. + */ + public static boolean isSubtype(Class subType, Class superType) { + // Covers both JLS 4.10.2 "Subtyping among Class and Interface Types" + // and JLS 4.10.3 "Subtyping among Array Types", as well as primitive + // type identity. + if(superType.isAssignableFrom(subType)) { + return true; + } + // JLS 4.10.1 "Subtyping among Primitive Types". Note we don't test for + // identity, as identical types were taken care of in the + // isAssignableFrom test. As per 4.10.1, the supertype relation is as + // follows: + // double > float + // float > long + // long > int + // int > short + // int > char + // short > byte + if(superType.isPrimitive() && subType.isPrimitive()) { + return isProperPrimitiveSubtype(subType, superType); + } + return false; + } + + /** + * Returns true if a supposed primitive subtype is a proper subtype ( meaning, subtype and not identical) of the + * supposed primitive supertype + * + * @param subType the supposed subtype + * @param superType the supposed supertype + * @return true if subType is a proper (not identical to) primitive subtype of the superType + */ + private static boolean isProperPrimitiveSubtype(Class subType, Class superType) { + if(superType == boolean.class || subType == boolean.class) { + return false; + } + if(subType == byte.class) { + return superType != char.class; + } + if(subType == char.class) { + return superType != short.class && superType != byte.class; + } + if(subType == short.class) { + return superType != char.class && superType != byte.class; + } + if(subType == int.class) { + return superType == long.class || superType == float.class || superType == double.class; + } + if(subType == long.class) { + return superType == float.class || superType == double.class; + } + if(subType == float.class) { + return superType == double.class; + } + return false; + } + + private static final Map, Class> WRAPPER_TO_PRIMITIVE_TYPES = createWrapperToPrimitiveTypes(); + + private static Map, Class> createWrapperToPrimitiveTypes() { + final Map, Class> classes = new IdentityHashMap<>(); + classes.put(Void.class, Void.TYPE); + classes.put(Boolean.class, Boolean.TYPE); + classes.put(Byte.class, Byte.TYPE); + classes.put(Character.class, Character.TYPE); + classes.put(Short.class, Short.TYPE); + classes.put(Integer.class, Integer.TYPE); + classes.put(Long.class, Long.TYPE); + classes.put(Float.class, Float.TYPE); + classes.put(Double.class, Double.TYPE); + return classes; + } + + private static final Set> PRIMITIVE_WRAPPER_TYPES = createPrimitiveWrapperTypes(); + + private static Set> createPrimitiveWrapperTypes() { + final Map, Class> classes = new IdentityHashMap<>(); + addClassHierarchy(classes, Boolean.class); + addClassHierarchy(classes, Byte.class); + addClassHierarchy(classes, Character.class); + addClassHierarchy(classes, Short.class); + addClassHierarchy(classes, Integer.class); + addClassHierarchy(classes, Long.class); + addClassHierarchy(classes, Float.class); + addClassHierarchy(classes, Double.class); + return classes.keySet(); + } + + private static void addClassHierarchy(Map, Class> map, Class clazz) { + if(clazz == null) { + return; + } + map.put(clazz, clazz); + addClassHierarchy(map, clazz.getSuperclass()); + for(Class itf: clazz.getInterfaces()) { + addClassHierarchy(map, itf); + } + } + + /** + * Returns true if the class can be assigned from any boxed primitive. + * + * @param clazz the class + * @return true if the class can be assigned from any boxed primitive. Basically, it is true if the class is any + * primitive wrapper class, or a superclass or superinterface of any primitive wrapper class. + */ + private static boolean isAssignableFromBoxedPrimitive(Class clazz) { + return PRIMITIVE_WRAPPER_TYPES.contains(clazz); + } + + /** + * Given a name of a primitive type (except "void"), returns the class representing it. I.e. when invoked with + * "int", returns {@link Integer#TYPE}. + * @param name the name of the primitive type + * @return the class representing the primitive type, or null if the name does not correspond to a primitive type + * or is "void". + */ + public static Class getPrimitiveTypeByName(String name) { + return PRIMITIVE_TYPES_BY_NAME.get(name); + } + + /** + * When passed a class representing a wrapper for a primitive type, returns the class representing the corresponding + * primitive type. I.e. calling it with {@code Integer.class} will return {@code Integer.TYPE}. If passed a class + * that is not a wrapper for primitive type, returns null. + * @param wrapperType the class object representing a wrapper for a primitive type + * @return the class object representing the primitive type, or null if the passed class is not a primitive wrapper. + */ + public static Class getPrimitiveType(Class wrapperType) { + return WRAPPER_TO_PRIMITIVE_TYPES.get(wrapperType); + } + + + /** + * When passed a class representing a primitive type, returns the class representing the corresponding + * wrapper type. I.e. calling it with {@code int.class} will return {@code Integer.class}. If passed a class + * that is not a primitive type, returns null. + * @param primitiveType the class object representing a primitive type + * @return the class object representing the wrapper type, or null if the passed class is not a primitive. + */ + public static Class getWrapperType(Class primitiveType) { + return WRAPPER_TYPES.get(primitiveType); + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/support/UnnamedDynCallSiteDescriptor.java b/nashorn/src/jdk/internal/dynalink/support/UnnamedDynCallSiteDescriptor.java new file mode 100644 index 00000000000..716080022fb --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/UnnamedDynCallSiteDescriptor.java @@ -0,0 +1,127 @@ +/* + * 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + 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 the copyright holder nor the names of + 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 COPYRIGHT HOLDER + 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. +*/ + +package jdk.internal.dynalink.support; + +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.CallSiteDescriptor; + + +class UnnamedDynCallSiteDescriptor extends AbstractCallSiteDescriptor { + private final MethodType methodType; + private final String op; + + UnnamedDynCallSiteDescriptor(String op, MethodType methodType) { + this.op = op; + this.methodType = methodType; + } + + @Override + public int getNameTokenCount() { + return 2; + } + + String getOp() { + return op; + } + + @Override + public String getNameToken(int i) { + switch(i) { + case 0: return "dyn"; + case 1: return op; + default: throw new IndexOutOfBoundsException(String.valueOf(i)); + } + } + + @Override + public MethodType getMethodType() { + return methodType; + } + + @Override + public CallSiteDescriptor changeMethodType(MethodType newMethodType) { + return CallSiteDescriptorFactory.getCanonicalPublicDescriptor(new UnnamedDynCallSiteDescriptor(op, + newMethodType)); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/messages.properties b/nashorn/src/jdk/internal/dynalink/support/messages.properties new file mode 100644 index 00000000000..eaf1f630d09 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/messages.properties @@ -0,0 +1,86 @@ +# 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. + +# 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, and Oracle licenses the original version of this file under the BSD +# license: +# +# Copyright 2009-2013 Attila Szegedi +# +# Licensed under both the Apache License, Version 2.0 (the "Apache License") +# and the BSD License (the "BSD License"), with licensee being free to +# choose either of the two at their discretion. +# +# You may not use this file except in compliance with either the Apache +# License or the BSD License. +# +# If you choose to use this file in compliance with the Apache License, the +# following notice applies to you: +# +# You may obtain a copy of the Apache License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing +# permissions and limitations under the License. +# +# If you choose to use this file in compliance with the BSD License, the +# following notice applies to you: +# +# 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 the copyright holder nor the names of +# 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 COPYRIGHT HOLDER +# 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. + +isInstanceGuardAlwaysTrue=isInstance guard for {0} in position {1} in method type {2} will always return true +isInstanceGuardAlwaysFalse=isInstance guard for {0} in position {1} in method type {2} will always return false + +isOfClassGuardAlwaysTrue=isOfClass guard for {0} in position {1} in method type {2} will always return true +isOfClassGuardAlwaysFalse=isOfClass guard for {0} in position {1} in method type {2} will always return false + +isArrayGuardAlwaysTrue=isArray guard in position {0} in method type {1} will always return true +isArrayGuardAlwaysFalse=isArray guard in position {0} in method type {1} will always return false \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/support/package.html b/nashorn/src/jdk/internal/dynalink/support/package.html new file mode 100644 index 00000000000..7bf9efcdc21 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/package.html @@ -0,0 +1,89 @@ + + + + +

      + Contains supporting classes for other packages. There is no guarantee that + any of these classes or interfaces will not change in a manner that breaks + backwards compatibility; they are not considered to be part of the public + API. +

      + diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java index 23f38749068..dc5b2e206c9 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java @@ -31,6 +31,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.LAZY; import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE; import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; + import java.io.File; import java.util.Arrays; import java.util.EnumSet; @@ -40,6 +41,7 @@ import java.util.LinkedList; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import jdk.internal.dynalink.support.NameCodec; import jdk.nashorn.internal.codegen.ClassEmitter.Flag; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.FunctionNode; @@ -49,7 +51,6 @@ import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.DebugLogger; import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.options.Options; -import org.dynalang.dynalink.support.NameCodec; /** * Responsible for converting JavaScripts to java byte code. Main entry diff --git a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java index 8553f9a9dd7..4aaa8fecbbe 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java @@ -71,6 +71,7 @@ import java.lang.reflect.Array; import java.util.ArrayDeque; import java.util.EnumSet; import java.util.Iterator; +import jdk.internal.dynalink.support.NameCodec; import jdk.internal.org.objectweb.asm.Handle; import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.nashorn.internal.codegen.ClassEmitter.Flag; @@ -94,7 +95,6 @@ import jdk.nashorn.internal.runtime.Scope; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.options.Options; -import org.dynalang.dynalink.support.NameCodec; /** * This is the main function responsible for emitting method code diff --git a/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java b/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java index 006f1e27e6e..9f2e8be44e0 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java @@ -27,7 +27,6 @@ package jdk.nashorn.internal.codegen; import java.util.List; import java.util.Map; - import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.AccessNode; import jdk.nashorn.internal.ir.BinaryNode; diff --git a/nashorn/src/jdk/nashorn/internal/ir/Block.java b/nashorn/src/jdk/nashorn/internal/ir/Block.java index 31448d38a35..e15c51d1788 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/Block.java +++ b/nashorn/src/jdk/nashorn/internal/ir/Block.java @@ -39,7 +39,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; - import jdk.nashorn.internal.codegen.Frame; import jdk.nashorn.internal.codegen.MethodEmitter.Label; import jdk.nashorn.internal.ir.annotations.Ignore; diff --git a/nashorn/src/jdk/nashorn/internal/ir/CallNode.java b/nashorn/src/jdk/nashorn/internal/ir/CallNode.java index 7ddf3a779b4..9e48bc6e8de 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/CallNode.java +++ b/nashorn/src/jdk/nashorn/internal/ir/CallNode.java @@ -28,7 +28,6 @@ package jdk.nashorn.internal.ir; import java.util.ArrayList; import java.util.Collections; import java.util.List; - import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.annotations.Ignore; import jdk.nashorn.internal.ir.visitor.NodeVisitor; diff --git a/nashorn/src/jdk/nashorn/internal/ir/Node.java b/nashorn/src/jdk/nashorn/internal/ir/Node.java index 102dc288fb7..24ad87936bb 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/Node.java +++ b/nashorn/src/jdk/nashorn/internal/ir/Node.java @@ -26,7 +26,6 @@ package jdk.nashorn.internal.ir; import java.util.IdentityHashMap; - import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.parser.Token; diff --git a/nashorn/src/jdk/nashorn/internal/ir/Symbol.java b/nashorn/src/jdk/nashorn/internal/ir/Symbol.java index 081df86604d..92a98ed5f55 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/Symbol.java +++ b/nashorn/src/jdk/nashorn/internal/ir/Symbol.java @@ -29,7 +29,6 @@ import java.io.PrintWriter; import java.util.HashSet; import java.util.Set; import java.util.StringTokenizer; - import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.options.Options; diff --git a/nashorn/src/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk/nashorn/internal/objects/Global.java index 66316d1dca4..3a9ca905a8a 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java @@ -37,6 +37,8 @@ import java.lang.ref.SoftReference; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; @@ -57,8 +59,6 @@ import jdk.nashorn.internal.runtime.ScriptingFunctions; import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.linker.InvokeByName; import jdk.nashorn.internal.scripts.JO$; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.LinkRequest; /** * Representation of global scope. diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java b/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java index 4592ad91f4b..a8b79235a33 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java @@ -30,6 +30,8 @@ import static jdk.nashorn.internal.runtime.linker.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; @@ -39,8 +41,6 @@ import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; import jdk.nashorn.internal.runtime.linker.PrimitiveLookup; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.LinkRequest; /** * ECMA 15.6 Boolean Objects. diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java index f8aafb70bdd..d1981ff8f1f 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java @@ -35,6 +35,9 @@ import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.runtime.FindProperty; @@ -45,9 +48,6 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator; import jdk.nashorn.internal.runtime.linker.Lookup; import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.LinkRequest; /** * This class is the implementation of the Nashorn-specific global object named {@code JSAdapter}. It can be diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java index b63e2f5b843..d3d6df992cd 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java @@ -30,6 +30,8 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import java.lang.reflect.Array; import java.util.Collection; +import jdk.internal.dynalink.beans.StaticClass; +import jdk.internal.dynalink.support.TypeUtilities; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Function; import jdk.nashorn.internal.objects.annotations.ScriptClass; @@ -37,8 +39,6 @@ import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; -import org.dynalang.dynalink.beans.StaticClass; -import org.dynalang.dynalink.support.TypeUtilities; /** * This class is the implementation for the {@code Java} global object exposed to programs running under Nashorn. This diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java index 22923b1c4fd..88d0e6a3473 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java @@ -25,16 +25,16 @@ package jdk.nashorn.internal.objects; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.beans.StaticClass; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.runtime.NativeJavaPackage; import jdk.nashorn.internal.runtime.ScriptObject; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.beans.StaticClass; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.LinkRequest; /** * This is "JavaImporter" constructor. This constructor allows you to use Java types omitting explicit package names. diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java index b2325d05f91..40aa8c2fba7 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java @@ -36,6 +36,8 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.text.NumberFormat; import java.util.Locale; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; @@ -47,8 +49,6 @@ import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; import jdk.nashorn.internal.runtime.linker.PrimitiveLookup; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.LinkRequest; /** * ECMA 15.7 Number Objects. diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java index 20a40f99737..e4ba4b53d6d 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java @@ -39,6 +39,9 @@ import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.regex.Pattern; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; @@ -56,9 +59,6 @@ import jdk.nashorn.internal.runtime.arrays.ArrayIndex; import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; import jdk.nashorn.internal.runtime.linker.NashornGuards; import jdk.nashorn.internal.runtime.linker.PrimitiveLookup; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.LinkRequest; /** diff --git a/nashorn/src/jdk/nashorn/internal/parser/Lexer.java b/nashorn/src/jdk/nashorn/internal/parser/Lexer.java index 2ae029730a9..d7856d44447 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/Lexer.java +++ b/nashorn/src/jdk/nashorn/internal/parser/Lexer.java @@ -31,6 +31,7 @@ import static jdk.nashorn.internal.parser.TokenType.EOF; import static jdk.nashorn.internal.parser.TokenType.EOL; import static jdk.nashorn.internal.parser.TokenType.ERROR; import static jdk.nashorn.internal.parser.TokenType.ESCSTRING; +import static jdk.nashorn.internal.parser.TokenType.EXECSTRING; import static jdk.nashorn.internal.parser.TokenType.FLOATING; import static jdk.nashorn.internal.parser.TokenType.HEXADECIMAL; import static jdk.nashorn.internal.parser.TokenType.LBRACE; @@ -40,7 +41,6 @@ import static jdk.nashorn.internal.parser.TokenType.RBRACE; import static jdk.nashorn.internal.parser.TokenType.REGEX; import static jdk.nashorn.internal.parser.TokenType.RPAREN; import static jdk.nashorn.internal.parser.TokenType.STRING; -import static jdk.nashorn.internal.parser.TokenType.EXECSTRING; import static jdk.nashorn.internal.parser.TokenType.XML; import jdk.nashorn.internal.runtime.ECMAErrors; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java b/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java index 8e30da7fcbe..b802a1a136f 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java @@ -26,8 +26,8 @@ package jdk.nashorn.internal.runtime; import java.lang.invoke.MethodHandle; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; /** * Runtime interface to the global scope of the current context. diff --git a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java index 32d940fa7f2..06010b805b4 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java @@ -28,9 +28,9 @@ package jdk.nashorn.internal.runtime; import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; +import jdk.internal.dynalink.beans.StaticClass; import jdk.nashorn.internal.codegen.CompilerConstants.Call; import jdk.nashorn.internal.parser.Lexer; -import org.dynalang.dynalink.beans.StaticClass; /** * Representation for ECMAScript types - this maps directly to the ECMA script standard diff --git a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java index 296473a390b..d75abd35845 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java @@ -25,13 +25,13 @@ package jdk.nashorn.internal.runtime; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.beans.StaticClass; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; import jdk.nashorn.internal.objects.NativeJava; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Function; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.beans.StaticClass; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.LinkRequest; /** * An object that exposes Java packages and classes as its properties. Packages are exposed as objects that have further diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java index 48525058a72..c3901d29198 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java @@ -33,14 +33,14 @@ import static jdk.nashorn.internal.runtime.linker.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; import jdk.nashorn.internal.codegen.CompilerConstants.Call; import jdk.nashorn.internal.objects.annotations.SpecializedFunction; import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; import jdk.nashorn.internal.runtime.linker.NashornGuards; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.LinkRequest; /** * Runtime representation of a JavaScript function. diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java index 689ca1ab5a9..d632166270a 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java @@ -39,6 +39,12 @@ final class ScriptLoader extends NashornLoader { super(parent, context); } + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + checkPackageAccess(name); + return super.loadClassTrusted(name, resolve); + } + // package-private and private stuff below this point /** diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java index 33a68a8cd26..85cf460f8a1 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -55,6 +55,10 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; import jdk.nashorn.internal.codegen.CompilerConstants.Call; import jdk.nashorn.internal.codegen.objects.ObjectClassGenerator; import jdk.nashorn.internal.objects.AccessorPropertyDescriptor; @@ -65,10 +69,6 @@ import jdk.nashorn.internal.runtime.linker.Lookup; import jdk.nashorn.internal.runtime.linker.MethodHandleFactory; import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; import jdk.nashorn.internal.runtime.linker.NashornGuards; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.LinkRequest; -import org.dynalang.dynalink.support.CallSiteDescriptorFactory; /** * Base class for generic JavaScript objects. diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java index 3c910f4344c..c49ce203c72 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java @@ -38,11 +38,11 @@ import java.util.Collections; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Objects; +import jdk.internal.dynalink.beans.StaticClass; import jdk.nashorn.internal.codegen.CompilerConstants.Call; import jdk.nashorn.internal.ir.debug.JSONWriter; import jdk.nashorn.internal.parser.Lexer; import jdk.nashorn.internal.runtime.linker.Bootstrap; -import org.dynalang.dynalink.beans.StaticClass; /** diff --git a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java index 6bd3a3fdcc4..8e430f45870 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java @@ -29,18 +29,17 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError; import static jdk.nashorn.internal.runtime.linker.Lookup.MH; import java.lang.invoke.MethodHandle; - +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.nashorn.internal.codegen.objects.ObjectClassGenerator; import jdk.nashorn.internal.runtime.linker.Lookup; import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; import jdk.nashorn.internal.runtime.linker.NashornGuards; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.linker.GuardedInvocation; /** * Instances of this class are quite ephemeral; they only exist for the duration of an invocation of - * {@link ScriptObject#findSetMethod(CallSiteDescriptor, org.dynalang.dynalink.linker.LinkRequest)} and + * {@link ScriptObject#findSetMethod(CallSiteDescriptor, jdk.internal.dynalink.linker.LinkRequest)} and * serve as the actual encapsulation of the algorithm for creating an appropriate property setter method. */ final class SetMethodCreator { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java b/nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java index b14e43ccd31..2c50382e462 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java @@ -58,8 +58,6 @@ final class StructureLoader extends NashornLoader { @Override protected synchronized Class loadClass(final String name, final boolean resolve) throws ClassNotFoundException { - checkPackageAccess(name); - // check the cache first final Class loadedClass = findLoadedClass(name); if (loadedClass != null) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Undefined.java b/nashorn/src/jdk/nashorn/internal/runtime/Undefined.java index 41024e500ae..6d9c69c156f 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Undefined.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Undefined.java @@ -31,10 +31,10 @@ import static jdk.nashorn.internal.runtime.linker.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.support.CallSiteDescriptorFactory; -import org.dynalang.dynalink.support.Guards; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; +import jdk.internal.dynalink.support.Guards; /** * Unique instance of this class is used to represent JavaScript undefined. diff --git a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java index b16cf923acb..e42088c2626 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java @@ -29,11 +29,11 @@ import static jdk.nashorn.internal.runtime.linker.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.LinkRequest; -import org.dynalang.dynalink.support.CallSiteDescriptorFactory; /** diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java index 73d3663a978..3c5e2d81b51 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java @@ -32,15 +32,15 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.DynamicLinker; +import jdk.internal.dynalink.DynamicLinkerFactory; +import jdk.internal.dynalink.beans.BeansLinker; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkerServices; import jdk.nashorn.internal.codegen.CompilerConstants.Call; import jdk.nashorn.internal.codegen.RuntimeCallSite; import jdk.nashorn.internal.runtime.options.Options; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.DynamicLinker; -import org.dynalang.dynalink.DynamicLinkerFactory; -import org.dynalang.dynalink.beans.BeansLinker; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.LinkerServices; /** * This class houses bootstrap method for invokedynamic instructions generated by compiler. diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java index 5ec1f4c9831..458469afe9f 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java @@ -29,14 +29,14 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.Objects; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; import jdk.nashorn.internal.runtime.JSType; import netscape.javascript.JSObject; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.LinkRequest; -import org.dynalang.dynalink.linker.LinkerServices; -import org.dynalang.dynalink.linker.TypeBasedGuardingDynamicLinker; -import org.dynalang.dynalink.support.CallSiteDescriptorFactory; /** * A Dynalink linker to handle web browser built-in JS (DOM etc.) objects as well diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java index 685f141e8ae..c8189d7dd64 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java @@ -70,6 +70,8 @@ import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; +import jdk.internal.dynalink.beans.StaticClass; +import jdk.internal.dynalink.support.LinkRequestImpl; import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.Label; import jdk.internal.org.objectweb.asm.Opcodes; @@ -83,8 +85,6 @@ import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.Undefined; -import org.dynalang.dynalink.beans.StaticClass; -import org.dynalang.dynalink.support.LinkRequestImpl; /** * A factory class that generates adapter classes. Adapter classes allow implementation of Java interfaces and diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java index 1329ccd74fb..00125e490d2 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java @@ -33,10 +33,10 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.util.HashMap; import java.util.Map; +import jdk.internal.dynalink.support.TypeUtilities; import jdk.nashorn.internal.runtime.ConsString; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptObject; -import org.dynalang.dynalink.support.TypeUtilities; /** * Utility class shared by {@link NashornLinker} and {@code NashornPrimitiveLinker} for converting JS values to Java diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java index 0ee1e74b133..445f87d8bd1 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java @@ -43,14 +43,14 @@ import java.util.Map.Entry; import java.util.Random; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +import jdk.internal.dynalink.ChainedCallSite; +import jdk.internal.dynalink.DynamicLinker; +import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.Debug; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.options.Options; -import org.dynalang.dynalink.ChainedCallSite; -import org.dynalang.dynalink.DynamicLinker; -import org.dynalang.dynalink.linker.GuardedInvocation; /** diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java index 6c80fd566e3..5c20bfc3ed8 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java @@ -30,13 +30,13 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import static jdk.nashorn.internal.runtime.linker.Lookup.MH; import java.lang.invoke.MethodHandle; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.Guards; import jdk.nashorn.internal.runtime.ScriptRuntime; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.GuardingDynamicLinker; -import org.dynalang.dynalink.linker.LinkRequest; -import org.dynalang.dynalink.linker.LinkerServices; -import org.dynalang.dynalink.support.Guards; /** * Nashorn bottom linker; used as a last-resort catch-all linker for all linking requests that fall through all other diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java index 79654f54509..a4fbc0740c3 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java @@ -28,9 +28,9 @@ package jdk.nashorn.internal.runtime.linker; import java.lang.invoke.MethodType; import java.lang.ref.WeakReference; import java.util.WeakHashMap; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.support.AbstractCallSiteDescriptor; -import org.dynalang.dynalink.support.CallSiteDescriptorFactory; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.support.AbstractCallSiteDescriptor; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; /** * Nashorn-specific implementation of Dynalink's {@link CallSiteDescriptor}. The reason we have our own subclass is that diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java index 53d69976684..74260dd80f0 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java @@ -29,23 +29,22 @@ import static jdk.nashorn.internal.runtime.linker.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; - +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.ConversionComparator; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.Guards; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.Undefined; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.linker.ConversionComparator; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.GuardingTypeConverterFactory; -import org.dynalang.dynalink.linker.LinkRequest; -import org.dynalang.dynalink.linker.LinkerServices; -import org.dynalang.dynalink.linker.TypeBasedGuardingDynamicLinker; -import org.dynalang.dynalink.support.Guards; /** * This is the main dynamic linker for Nashorn. It is used for linking all {@link ScriptObject} and its subclasses (this * includes {@link ScriptFunction} and its subclasses) as well as {@link Undefined}. This linker is exported to other - * language runtimes by being declared in {@code META-INF/services/org.dynalang.dynalink.linker.GuardingDynamicLinker} + * language runtimes by being declared in {@code META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker} * file of Nashorn's distribution. */ public class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory, ConversionComparator { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java index 0456e00f304..71edc44acc0 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java @@ -29,16 +29,16 @@ import static jdk.nashorn.internal.runtime.linker.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import jdk.internal.dynalink.linker.ConversionComparator; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.TypeUtilities; import jdk.nashorn.internal.runtime.ConsString; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.GlobalObject; -import org.dynalang.dynalink.linker.ConversionComparator; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.GuardingTypeConverterFactory; -import org.dynalang.dynalink.linker.LinkRequest; -import org.dynalang.dynalink.linker.LinkerServices; -import org.dynalang.dynalink.linker.TypeBasedGuardingDynamicLinker; -import org.dynalang.dynalink.support.TypeUtilities; /** * Internal linker for String, Boolean, and Number objects, only ever used by Nashorn engine and not exposed to other @@ -90,7 +90,7 @@ class NashornPrimitiveLinker implements TypeBasedGuardingDynamicLinker, Guarding * @param sourceType the source type to convert from * @param targetType1 one candidate target type * @param targetType2 another candidate target type - * @return one of {@link org.dynalang.dynalink.linker.ConversionComparator.Comparison} values signifying which + * @return one of {@link jdk.internal.dynalink.linker.ConversionComparator.Comparison} values signifying which * target type should be favored for conversion. */ @Override diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java index 4e7c68bd920..de3a1f16a86 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java @@ -25,16 +25,16 @@ package jdk.nashorn.internal.runtime.linker; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.beans.BeansLinker; +import jdk.internal.dynalink.beans.StaticClass; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.Guards; import jdk.nashorn.internal.runtime.ECMAErrors; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.beans.BeansLinker; -import org.dynalang.dynalink.beans.StaticClass; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.GuardingDynamicLinker; -import org.dynalang.dynalink.linker.LinkRequest; -import org.dynalang.dynalink.linker.LinkerServices; -import org.dynalang.dynalink.linker.TypeBasedGuardingDynamicLinker; -import org.dynalang.dynalink.support.Guards; /** * Internal linker for {@link StaticClass} objects, only ever used by Nashorn engine and not exposed to other engines. diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java index ed7be46a46c..131b63b17fc 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java @@ -29,12 +29,12 @@ import static jdk.nashorn.internal.runtime.linker.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; +import jdk.internal.dynalink.support.Guards; import jdk.nashorn.internal.runtime.ScriptObject; -import org.dynalang.dynalink.CallSiteDescriptor; -import org.dynalang.dynalink.linker.GuardedInvocation; -import org.dynalang.dynalink.linker.LinkRequest; -import org.dynalang.dynalink.support.CallSiteDescriptorFactory; -import org.dynalang.dynalink.support.Guards; /** * Implements lookup of methods to link for dynamic operations on JavaScript primitive values (booleans, strings, and diff --git a/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java b/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java index 06b1176a012..7cca54122df 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java @@ -44,7 +44,6 @@ import java.util.StringTokenizer; import java.util.TimeZone; import java.util.TreeMap; import java.util.TreeSet; - import jdk.nashorn.internal.runtime.Logging; import jdk.nashorn.internal.runtime.QuotedStringTokenizer; diff --git a/nashorn/test/script/sandbox/nashorninternals.js b/nashorn/test/script/sandbox/nashorninternals.js index 4072e0719a8..35e8e757478 100644 --- a/nashorn/test/script/sandbox/nashorninternals.js +++ b/nashorn/test/script/sandbox/nashorninternals.js @@ -55,3 +55,7 @@ checkClass("jdk.nashorn.internal.parser.Parser"); checkClass("jdk.nashorn.internal.parser.JSONParser"); checkClass("jdk.nashorn.internal.parser.Lexer"); checkClass("jdk.nashorn.internal.parser.Scanner"); +checkClass("jdk.internal.dynalink.CallSiteDescriptor"); +checkClass("jdk.internal.dynalink.beans.StaticClass"); +checkClass("jdk.internal.dynalink.linker.LinkRequest"); +checkClass("jdk.internal.dynalink.support.AbstractRelinkableCallSite"); diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java index 169ebf9d653..26b478e9805 100644 --- a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java +++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java @@ -26,8 +26,8 @@ package jdk.nashorn.api.scripting; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; diff --git a/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java b/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java index e894a371af2..783fba9694c 100644 --- a/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java @@ -35,7 +35,6 @@ import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import jdk.nashorn.api.scripting.NashornScriptEngineFactory; -import jdk.nashorn.api.scripting.ScriptEngineTest; import jdk.nashorn.internal.runtime.options.Options; import org.testng.annotations.Test; diff --git a/nashorn/test/src/jdk/nashorn/internal/runtime/JSTypeTest.java b/nashorn/test/src/jdk/nashorn/internal/runtime/JSTypeTest.java index f9594197b8e..f9b500e9072 100644 --- a/nashorn/test/src/jdk/nashorn/internal/runtime/JSTypeTest.java +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/JSTypeTest.java @@ -26,8 +26,8 @@ package jdk.nashorn.internal.runtime; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; import org.testng.annotations.Test; From af9c882b95869dbd3acf9ae14fb8b7c560fcc963 Mon Sep 17 00:00:00 2001 From: Marcus Lagergren Date: Thu, 14 Feb 2013 13:52:12 +0100 Subject: [PATCH 148/311] 8008206: The allInteger case for SwitchNode generation in CodeGenerator assumes integer LITERALS only Reviewed-by: sundar, jlaskey --- .../jdk/nashorn/internal/codegen/Attr.java | 4 +++ .../internal/codegen/CodeGenerator.java | 2 +- nashorn/test/script/basic/JDK-8008206.js | 36 +++++++++++++++++++ .../test/script/basic/JDK-8008206.js.EXPECTED | 1 + 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 nashorn/test/script/basic/JDK-8008206.js create mode 100644 nashorn/test/script/basic/JDK-8008206.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java index 1752cfbd3f1..3bf8856955b 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java @@ -542,6 +542,10 @@ final class Attr extends NodeOperatorVisitor { caseNode.setTest(LiteralNode.newInstance(lit, lit.getInt32()).accept(this)); } } + } else { + // the "all integer" case that CodeGenerator optimizes for currently assumes literals only + type = Type.OBJECT; + break; } type = Type.widest(type, caseNode.getTest().getType()); diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 544d8c5ebb7..a37aa24049c 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -1803,7 +1803,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { final Node test = caseNode.getTest(); if (test != null) { - final Integer value = (Integer)((LiteralNode) test).getValue(); + final Integer value = (Integer)((LiteralNode)test).getValue(); final Label entry = caseNode.getEntry(); // Take first duplicate. diff --git a/nashorn/test/script/basic/JDK-8008206.js b/nashorn/test/script/basic/JDK-8008206.js new file mode 100644 index 00000000000..be84f51b910 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8008206.js @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/** + * JDK-8008026 : allInteger case in Switch nodes requiers integer literals only + * + * @test + * @run + */ + +var x = 1; + +switch (x) { + case foo = false, 1: + print("ok"); +} diff --git a/nashorn/test/script/basic/JDK-8008206.js.EXPECTED b/nashorn/test/script/basic/JDK-8008206.js.EXPECTED new file mode 100644 index 00000000000..9766475a418 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8008206.js.EXPECTED @@ -0,0 +1 @@ +ok From 85c55a2aa457b82fe1c2fe463847f660f16ee06e Mon Sep 17 00:00:00 2001 From: Attila Szegedi Date: Thu, 14 Feb 2013 13:51:54 +0100 Subject: [PATCH 149/311] 8007990: No access to interface methods on a restricted class Reviewed-by: jlaskey, lagergren, sundar --- nashorn/make/build.xml | 2 +- nashorn/test/script/basic/JDK-8007990.js | 36 +++++++++++++++++++ .../test/script/basic/JDK-8007990.js.EXPECTED | 1 + 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 nashorn/test/script/basic/JDK-8007990.js create mode 100644 nashorn/test/script/basic/JDK-8007990.js.EXPECTED diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml index 3043b1890e7..342dc2c10c1 100644 --- a/nashorn/make/build.xml +++ b/nashorn/make/build.xml @@ -180,7 +180,7 @@ - + diff --git a/nashorn/test/script/basic/JDK-8007990.js b/nashorn/test/script/basic/JDK-8007990.js new file mode 100644 index 00000000000..7f4f7399b8d --- /dev/null +++ b/nashorn/test/script/basic/JDK-8007990.js @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/** + * JDK-8007990: Access methods declared on public interfaces implemented by + * non-public classes + * + * @test + * @run + */ + +var p = new Packages.java.io.File("test/script/basic/JDK-8007990.js"); +var path = p.toPath(); +var basicView = Packages.java.nio.file.Files.getFileAttributeView(path, Packages.java.nio.file.attribute.BasicFileAttributeView.class); +// We just want to confirm we can access the readAttributes() function +print(basicView.readAttributes().directory); diff --git a/nashorn/test/script/basic/JDK-8007990.js.EXPECTED b/nashorn/test/script/basic/JDK-8007990.js.EXPECTED new file mode 100644 index 00000000000..c508d5366f7 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8007990.js.EXPECTED @@ -0,0 +1 @@ +false From 6aeeee6b63ec7f8fa8ee27a36d99b20d45380384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Thu, 14 Feb 2013 14:07:53 +0100 Subject: [PATCH 150/311] 8008198: java.lang.AssertionError: Invalid break target class jdk.nashorn.internal.ir.TryNode Reviewed-by: attila, jlaskey --- .../jdk/nashorn/internal/ir/LabelNode.java | 2 + .../jdk/nashorn/internal/parser/Parser.java | 3 +- nashorn/test/script/basic/JDK-8008198.js | 55 +++++++++++++++++++ .../test/script/basic/JDK-8008198.js.EXPECTED | 6 ++ 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 nashorn/test/script/basic/JDK-8008198.js create mode 100644 nashorn/test/script/basic/JDK-8008198.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/ir/LabelNode.java b/nashorn/src/jdk/nashorn/internal/ir/LabelNode.java index 6830dca87e2..b74d5637b53 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/LabelNode.java +++ b/nashorn/src/jdk/nashorn/internal/ir/LabelNode.java @@ -125,6 +125,7 @@ public class LabelNode extends Node { * @param breakNode the break node */ public void setBreakNode(final Node breakNode) { + assert breakNode instanceof BreakableNode || breakNode instanceof Block : "Invalid break node: " + breakNode; this.breakNode = breakNode; } @@ -141,6 +142,7 @@ public class LabelNode extends Node { * @param continueNode the continue node */ public void setContinueNode(final Node continueNode) { + assert continueNode instanceof WhileNode : "invalid continue node: " + continueNode; this.continueNode = continueNode; } diff --git a/nashorn/src/jdk/nashorn/internal/parser/Parser.java b/nashorn/src/jdk/nashorn/internal/parser/Parser.java index 1875ee02915..6fc7de587bb 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java +++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java @@ -498,10 +498,11 @@ loop: */ private void pushControlNode(final Node node) { final boolean isLoop = node instanceof WhileNode; + final boolean isBreakable = node instanceof BreakableNode || node instanceof Block; function.getControlStack().push(node); for (final LabelNode labelNode : function.getLabelStack()) { - if (labelNode.getBreakNode() == null) { + if (isBreakable && labelNode.getBreakNode() == null) { labelNode.setBreakNode(node); } diff --git a/nashorn/test/script/basic/JDK-8008198.js b/nashorn/test/script/basic/JDK-8008198.js new file mode 100644 index 00000000000..745cea77a59 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8008198.js @@ -0,0 +1,55 @@ +/* + * 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. + */ + +/** + * JDK-8008198 : java.lang.AssertionError: Invalid break target class jdk.nashorn.internal.ir.TryNode + * + * @test + * @run + */ + +a: try { + print("try"); + break a; + print("wrong"); +} catch (e) { + print("error"); +} finally { + print("finally"); +} +print("done"); + +a: b: if (true) { + c: d: with({}) { + print("with"); + break c; + print("wrong"); + } + print("if"); + break a; + print("wrong"); +} +print("done"); + + + diff --git a/nashorn/test/script/basic/JDK-8008198.js.EXPECTED b/nashorn/test/script/basic/JDK-8008198.js.EXPECTED new file mode 100644 index 00000000000..a7350d75018 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8008198.js.EXPECTED @@ -0,0 +1,6 @@ +try +finally +done +with +if +done From f95919ab1e89d6d8ccd94e6472816637cf3681c3 Mon Sep 17 00:00:00 2001 From: James Laskey Date: Thu, 14 Feb 2013 11:32:49 -0400 Subject: [PATCH 151/311] 8008231: Fix build system to accommodate integration of dynalink Reviewed-by: jlaskey --- nashorn/makefiles/BuildNashorn.gmk | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/nashorn/makefiles/BuildNashorn.gmk b/nashorn/makefiles/BuildNashorn.gmk index bab28ba1cc4..33ef441e22b 100644 --- a/nashorn/makefiles/BuildNashorn.gmk +++ b/nashorn/makefiles/BuildNashorn.gmk @@ -35,8 +35,6 @@ JAVAC_JARS ?= "-Xbootclasspath/p:$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac -jar $(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac.jar JDK_CLASSES := $(JDK_OUTPUTDIR)/classes -# TODO: Remove dependency? -DYNALINK_JAR := $(NASHORN_TOPDIR)/build/dynalink/dynalink.jar NASHORN_JAR := $(NASHORN_DIST)/nashorn.jar NASHORN_VERSION := $(JDK_VERSION) @@ -61,8 +59,7 @@ $(eval $(call SetupJavaCompilation,BUILD_NASHORN,\ SETUP:=COMPILER_SETUP,\ SRC:=$(NASHORN_TOPDIR)/src,\ COPY:=.properties .js,\ - BIN:=$(NASHORN_OUTPUTDIR)/nashorn_classes,\ - ADD_JAVAC_FLAGS:=-cp $(DYNALINK_JAR))) + BIN:=$(NASHORN_OUTPUTDIR)/nashorn_classes)) # Build nasgen $(eval $(call SetupJavaCompilation,BUILD_NASGEN,\ @@ -89,14 +86,6 @@ $(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run: $(BUILD_NASGEN) done $(TOUCH) $@ -# Unpack dynalink.jar for inclusion in nashorn.jar -$(NASHORN_OUTPUTDIR)/classes/_the.dynalink.unpacked: $(DYNALINK_JAR) - $(ECHO) Unpacking dynalink.jar - $(MKDIR) -p $(@D) - $(RM) -rf $(@D)/org - $(UNZIP) -q $(DYNALINK_JAR) -x "META-INF*" -d $(@D) - $(TOUCH) $@ - # Version file needs to be processed with version numbers VERSION_FILE := $(NASHORN_OUTPUTDIR)/classes/jdk/nashorn/internal/runtime/resources/version.properties # Needs to happen after nasgen run since nasgen run deletes it @@ -114,7 +103,6 @@ MANIFEST_ATTRIBUTES:=Name: jdk/nashorn/\nImplementation-Title: Oracle Nashorn\nI # Create nashorn.jar from the final classes dir $(eval $(call SetupArchive,BUILD_NASHORN_JAR,\ $(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run \ - $(NASHORN_OUTPUTDIR)/classes/_the.dynalink.unpacked \ $(VERSION_FILE),\ SRCS:=$(NASHORN_OUTPUTDIR)/classes,\ SUFFIXES:=.class .clazz .js .properties Factory,\ From 07c7afeaac66498536cee778971c4df14d5da520 Mon Sep 17 00:00:00 2001 From: Bharadwaj Yadavalli Date: Thu, 14 Feb 2013 11:09:07 -0800 Subject: [PATCH 152/311] 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 153/311] 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 154/311] 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 155/311] 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 8edbed784ded6c8aa108f94fbb207cbef194fed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Fri, 15 Feb 2013 09:18:05 +0100 Subject: [PATCH 156/311] 8008215: break in catch clause causes java.lang.VerifyError: Inconsistent stackmap Reviewed-by: jlaskey, lagergren --- .../jdk/nashorn/internal/parser/Parser.java | 11 ++++- nashorn/test/script/basic/JDK-8008215.js | 41 +++++++++++++++++++ .../test/script/basic/JDK-8008215.js.EXPECTED | 4 ++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 nashorn/test/script/basic/JDK-8008215.js create mode 100644 nashorn/test/script/basic/JDK-8008215.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/parser/Parser.java b/nashorn/src/jdk/nashorn/internal/parser/Parser.java index 6fc7de587bb..7d3e3a1a5ee 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java +++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java @@ -1742,6 +1742,10 @@ loop: // TRY tested in caller. next(); + // Container block needed to act as target for labeled break statements + final Block outer = newBlock(); + pushControlNode(outer); + // Create try. final TryNode tryNode = new TryNode(source, tryToken, Token.descPosition(tryToken), findControl(TryNode.class)); pushControlNode(tryNode); @@ -1819,12 +1823,17 @@ loop: tryNode.setCatchBlocks(catchBlocks); tryNode.setFinallyBody(finallyStatements); tryNode.setFinish(finish); + outer.setFinish(finish); // Add try. - block.addStatement(tryNode); + outer.addStatement(tryNode); } finally { popControlNode(tryNode); + restoreBlock(); + popControlNode(outer); } + + block.addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer)); } /** diff --git a/nashorn/test/script/basic/JDK-8008215.js b/nashorn/test/script/basic/JDK-8008215.js new file mode 100644 index 00000000000..691b9a4562d --- /dev/null +++ b/nashorn/test/script/basic/JDK-8008215.js @@ -0,0 +1,41 @@ +/* + * 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. + */ + +/** + * JDK-8008215 : break in catch clause causes java.lang.VerifyError: Inconsistent stackmap + * + * @test + * @run + */ + +a: try { + print("try"); + throw new Error(); +} catch (e) { + print("catch"); + break a; + print("error"); +} finally { + print("finally"); +} +print("done"); diff --git a/nashorn/test/script/basic/JDK-8008215.js.EXPECTED b/nashorn/test/script/basic/JDK-8008215.js.EXPECTED new file mode 100644 index 00000000000..a7088738af7 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8008215.js.EXPECTED @@ -0,0 +1,4 @@ +try +catch +finally +done From 7d9a872e3fb44ac5c53d10a7efc281df6642da63 Mon Sep 17 00:00:00 2001 From: Marcus Lagergren Date: Fri, 15 Feb 2013 09:44:15 +0100 Subject: [PATCH 157/311] 8008239: Unpublicized parts of the code generator package that were only package internal Reviewed-by: hannesw, attila --- .../internal/codegen/BranchOptimizer.java | 14 +- .../internal/codegen/ClassEmitter.java | 39 +- .../internal/codegen/CodeGenerator.java | 65 ++-- .../internal/codegen/CompilationPhase.java | 13 +- .../internal/codegen/CompilerConstants.java | 12 +- .../nashorn/internal/codegen/Condition.java | 107 +++++ .../{objects => }/FieldObjectCreator.java | 11 +- .../internal/codegen/FunctionSignature.java | 1 - .../ObjectMapCreator.java => Label.java} | 59 ++- .../codegen/{objects => }/MapCreator.java | 9 +- .../internal/codegen/MethodEmitter.java | 364 ++++++------------ .../{objects => }/ObjectClassGenerator.java | 6 +- .../codegen/{objects => }/ObjectCreator.java | 10 +- .../internal/codegen/SharedScopeCall.java | 8 +- .../nashorn/internal/codegen/Splitter.java | 4 +- .../internal/codegen/types/BooleanType.java | 2 +- .../internal/codegen/types/IntType.java | 2 +- .../internal/codegen/types/LongType.java | 2 +- .../internal/codegen/types/NumberType.java | 2 +- .../jdk/nashorn/internal/ir/AccessNode.java | 4 +- .../src/jdk/nashorn/internal/ir/BaseNode.java | 2 +- .../src/jdk/nashorn/internal/ir/Block.java | 17 +- .../jdk/nashorn/internal/ir/BreakNode.java | 4 +- .../nashorn/internal/ir/BreakableNode.java | 6 +- .../src/jdk/nashorn/internal/ir/CallNode.java | 8 +- .../src/jdk/nashorn/internal/ir/CaseNode.java | 2 +- .../jdk/nashorn/internal/ir/CatchNode.java | 8 +- .../jdk/nashorn/internal/ir/ContinueNode.java | 4 +- .../jdk/nashorn/internal/ir/IdentNode.java | 4 +- .../jdk/nashorn/internal/ir/IndexNode.java | 4 +- .../jdk/nashorn/internal/ir/LabelNode.java | 8 +- .../nashorn/internal/ir/LineNumberNode.java | 2 +- .../jdk/nashorn/internal/ir/ObjectNode.java | 4 +- .../jdk/nashorn/internal/ir/ReturnNode.java | 4 +- .../jdk/nashorn/internal/ir/SplitNode.java | 15 +- .../jdk/nashorn/internal/ir/SwitchNode.java | 19 +- .../jdk/nashorn/internal/ir/ThrowNode.java | 4 +- .../src/jdk/nashorn/internal/ir/TryNode.java | 2 +- .../jdk/nashorn/internal/ir/UnaryNode.java | 2 +- .../jdk/nashorn/internal/ir/WhileNode.java | 16 +- .../src/jdk/nashorn/internal/ir/WithNode.java | 4 +- .../internal/objects/NativeRegExp.java | 3 +- .../internal/objects/ScriptFunctionImpl.java | 1 - .../internal/runtime/AccessorProperty.java | 24 +- .../jdk/nashorn/internal/runtime/Context.java | 9 +- .../internal/runtime/ECMAException.java | 1 - .../internal/runtime/FindProperty.java | 2 +- .../nashorn/internal/runtime/Property.java | 2 +- .../jdk/nashorn/internal/runtime/Scope.java | 5 +- .../internal/runtime/ScriptObject.java | 8 +- .../internal/runtime/ScriptRuntime.java | 8 +- .../internal/runtime/SetMethodCreator.java | 2 +- .../internal/runtime/StructureLoader.java | 2 +- 53 files changed, 459 insertions(+), 481 deletions(-) create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/Condition.java rename nashorn/src/jdk/nashorn/internal/codegen/{objects => }/FieldObjectCreator.java (92%) rename nashorn/src/jdk/nashorn/internal/codegen/{objects/ObjectMapCreator.java => Label.java} (50%) rename nashorn/src/jdk/nashorn/internal/codegen/{objects => }/MapCreator.java (91%) rename nashorn/src/jdk/nashorn/internal/codegen/{objects => }/ObjectClassGenerator.java (99%) rename nashorn/src/jdk/nashorn/internal/codegen/{objects => }/ObjectCreator.java (94%) diff --git a/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java b/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java index a864d5537f7..84cef43764a 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java @@ -25,14 +25,14 @@ package jdk.nashorn.internal.codegen; -import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.EQ; -import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.GE; -import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.GT; -import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.LE; -import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.LT; -import static jdk.nashorn.internal.codegen.MethodEmitter.Condition.NE; +import static jdk.nashorn.internal.codegen.Condition.EQ; +import static jdk.nashorn.internal.codegen.Condition.GE; +import static jdk.nashorn.internal.codegen.Condition.GT; +import static jdk.nashorn.internal.codegen.Condition.LE; +import static jdk.nashorn.internal.codegen.Condition.LT; +import static jdk.nashorn.internal.codegen.Condition.NE; -import jdk.nashorn.internal.codegen.MethodEmitter.Label; +import jdk.nashorn.internal.codegen.Label; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.BinaryNode; import jdk.nashorn.internal.ir.Node; diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java b/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java index b9f645e47f5..7a293a3f3b0 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java @@ -62,6 +62,7 @@ import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.util.TraceClassVisitor; +import jdk.nashorn.internal.codegen.Emitter; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.runtime.Context; @@ -102,7 +103,6 @@ import jdk.nashorn.internal.runtime.Source; * detect if this is not true * * @see Compiler - * @see CodeGenerator */ public class ClassEmitter implements Emitter { @@ -156,7 +156,7 @@ public class ClassEmitter implements Emitter { * @param superClassName super class name for class * @param interfaceNames names of interfaces implemented by this class, or null if none */ - public ClassEmitter(final Context context, final String className, final String superClassName, final String... interfaceNames) { + ClassEmitter(final Context context, final String className, final String superClassName, final String... interfaceNames) { this(context, new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS)); cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, className, null, superClassName, interfaceNames); } @@ -363,7 +363,7 @@ public class ClassEmitter implements Emitter { * @param bytecode byte array representing bytecode * @return disassembly as human readable string */ - public static String disassemble(final byte[] bytecode) { + static String disassemble(final byte[] bytecode) { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (final PrintWriter pw = new PrintWriter(baos)) { new ClassReader(bytecode).accept(new TraceClassVisitor(pw), 0); @@ -411,7 +411,7 @@ public class ClassEmitter implements Emitter { * * @return method emitter to use for weaving this method */ - public MethodEmitter method(final String methodName, final Class rtype, final Class... ptypes) { + MethodEmitter method(final String methodName, final Class rtype, final Class... ptypes) { return method(DEFAULT_METHOD_FLAGS, methodName, rtype, ptypes); //TODO why public default ? } @@ -425,7 +425,7 @@ public class ClassEmitter implements Emitter { * * @return method emitter to use for weaving this method */ - public MethodEmitter method(final EnumSet methodFlags, final String methodName, final Class rtype, final Class... ptypes) { + MethodEmitter method(final EnumSet methodFlags, final String methodName, final Class rtype, final Class... ptypes) { return new MethodEmitter(this, cw.visitMethod(Flag.getValue(methodFlags), methodName, methodDescriptor(rtype, ptypes), null, null)); } @@ -437,7 +437,7 @@ public class ClassEmitter implements Emitter { * * @return method emitter to use for weaving this method */ - public MethodEmitter method(final String methodName, final String descriptor) { + MethodEmitter method(final String methodName, final String descriptor) { return method(DEFAULT_METHOD_FLAGS, methodName, descriptor); } @@ -450,7 +450,7 @@ public class ClassEmitter implements Emitter { * * @return method emitter to use for weaving this method */ - public MethodEmitter method(final EnumSet methodFlags, final String methodName, final String descriptor) { + MethodEmitter method(final EnumSet methodFlags, final String methodName, final String descriptor) { return new MethodEmitter(this, cw.visitMethod(Flag.getValue(methodFlags), methodName, descriptor, null, null)); } @@ -460,7 +460,7 @@ public class ClassEmitter implements Emitter { * @param functionNode the function node to generate a method for * @return method emitter to use for weaving this method */ - public MethodEmitter method(final FunctionNode functionNode) { + MethodEmitter method(final FunctionNode functionNode) { final MethodVisitor mv = cw.visitMethod( ACC_PUBLIC | ACC_STATIC | (functionNode.isVarArg() ? ACC_VARARGS : 0), functionNode.getName(), @@ -476,7 +476,7 @@ public class ClassEmitter implements Emitter { * * @return method emitter to use for weaving */ - public MethodEmitter clinit() { + MethodEmitter clinit() { return method(EnumSet.of(Flag.STATIC), CLINIT.tag(), void.class); } @@ -485,7 +485,7 @@ public class ClassEmitter implements Emitter { * * @return method emitter to use for weaving ()V */ - public MethodEmitter init() { + MethodEmitter init() { return method(INIT.tag(), void.class); } @@ -495,7 +495,7 @@ public class ClassEmitter implements Emitter { * @param ptypes parameter types for constructor * @return method emitter to use for weaving ()V */ - public MethodEmitter init(final Class... ptypes) { + MethodEmitter init(final Class... ptypes) { return method(INIT.tag(), void.class, ptypes); } @@ -507,7 +507,7 @@ public class ClassEmitter implements Emitter { * * @return method emitter to use for weaving (...)V */ - public MethodEmitter init(final EnumSet flags, final Class... ptypes) { + MethodEmitter init(final EnumSet flags, final Class... ptypes) { return method(flags, INIT.tag(), void.class, ptypes); } @@ -521,7 +521,7 @@ public class ClassEmitter implements Emitter { * * @see ClassEmitter.Flag */ - public final void field(final EnumSet fieldFlags, final String fieldName, final Class fieldType, final Object value) { + final void field(final EnumSet fieldFlags, final String fieldName, final Class fieldType, final Object value) { cw.visitField(Flag.getValue(fieldFlags), fieldName, typeDescriptor(fieldType), null, value).visitEnd(); } @@ -534,7 +534,7 @@ public class ClassEmitter implements Emitter { * * @see ClassEmitter.Flag */ - public final void field(final EnumSet fieldFlags, final String fieldName, final Class fieldType) { + final void field(final EnumSet fieldFlags, final String fieldName, final Class fieldType) { field(fieldFlags, fieldName, fieldType, null); } @@ -544,7 +544,7 @@ public class ClassEmitter implements Emitter { * @param fieldName name of field * @param fieldType type of field */ - public final void field(final String fieldName, final Class fieldType) { + final void field(final String fieldName, final Class fieldType) { field(EnumSet.of(Flag.PUBLIC), fieldName, fieldType, null); } @@ -554,7 +554,7 @@ public class ClassEmitter implements Emitter { * * @return byte code array for generated class, null if class generation hasn't been ended with {@link ClassEmitter#end()} */ - public byte[] toByteArray() { + byte[] toByteArray() { assert classEnded; if (!classEnded) { return null; @@ -572,7 +572,7 @@ public class ClassEmitter implements Emitter { * Flags are provided for method handles, protection levels, static/virtual * fields/methods. */ - public static enum Flag { + static enum Flag { /** method handle with static access */ HANDLE_STATIC(H_INVOKESTATIC), /** method handle with new invoke special access */ @@ -603,7 +603,7 @@ public class ClassEmitter implements Emitter { * Get the value of this flag * @return the int value */ - public int getValue() { + int getValue() { return value; } @@ -613,7 +613,7 @@ public class ClassEmitter implements Emitter { * @param flags enum set of flags * @return an integer value representing the flags intrinsic values or:ed together */ - public static int getValue(final EnumSet flags) { + static int getValue(final EnumSet flags) { int v = 0; for (final Flag flag : flags) { v |= flag.getValue(); @@ -621,5 +621,4 @@ public class ClassEmitter implements Emitter { return v; } } - } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java index a37aa24049c..53f45241b98 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -63,13 +63,7 @@ import java.util.Map; import java.util.TreeMap; import jdk.nashorn.internal.codegen.ClassEmitter.Flag; import jdk.nashorn.internal.codegen.CompilerConstants.Call; -import jdk.nashorn.internal.codegen.MethodEmitter.Condition; -import jdk.nashorn.internal.codegen.MethodEmitter.Label; import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode; -import jdk.nashorn.internal.codegen.objects.FieldObjectCreator; -import jdk.nashorn.internal.codegen.objects.MapCreator; -import jdk.nashorn.internal.codegen.objects.ObjectCreator; -import jdk.nashorn.internal.codegen.objects.ObjectMapCreator; import jdk.nashorn.internal.codegen.types.ArrayType; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.AccessNode; @@ -118,6 +112,7 @@ import jdk.nashorn.internal.parser.TokenType; import jdk.nashorn.internal.runtime.CodeInstaller; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ECMAException; +import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.Scope; import jdk.nashorn.internal.runtime.ScriptFunction; @@ -147,7 +142,7 @@ import jdk.nashorn.internal.runtime.linker.LinkerCallSite; * The CodeGenerator visits nodes only once, tags them as resolved and emits * bytecode for them. */ -public final class CodeGenerator extends NodeOperatorVisitor { +final class CodeGenerator extends NodeOperatorVisitor { /** Name of the Global object, cannot be referred to as .class, @see CodeGenerator */ private static final String GLOBAL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "Global"; @@ -189,7 +184,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { * * @return the correct flags for a call site in the current function */ - public int getCallSiteFlags() { + int getCallSiteFlags() { return getCurrentFunctionNode().isStrictMode() ? callSiteFlags | CALLSITE_STRICT : callSiteFlags; } @@ -302,7 +297,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { * * @return the method emitter used */ - public MethodEmitter load(final Node node) { + MethodEmitter load(final Node node) { return load(node, false); } @@ -661,9 +656,8 @@ public final class CodeGenerator extends NodeOperatorVisitor { } else { // get global from scope (which is the self) globalInstance(); } - loadArgs(args, signature, isVarArg, argCount); - method.invokeStatic(callee.getCompileUnit().getUnitClassName(), callee.getName(), signature); + method.invokestatic(callee.getCompileUnit().getUnitClassName(), callee.getName(), signature); assert method.peekType().equals(callee.getReturnType()) : method.peekType() + " != " + callee.getReturnType(); return null; @@ -1138,7 +1132,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { savedMethod.swap(); savedMethod.loadScope(); savedMethod.swap(); - savedMethod.invokeStatic(className, name, signature); + savedMethod.invokestatic(className, name, signature); } } finally { setCurrentCompileUnit(savedCompileUnit); @@ -1191,13 +1185,13 @@ public final class CodeGenerator extends NodeOperatorVisitor { * * @param string string to load */ - public void loadConstant(final String string) { + void loadConstant(final String string) { final String unitClassName = getCurrentCompileUnit().getUnitClassName(); final ClassEmitter classEmitter = getCurrentCompileUnit().getClassEmitter(); final int index = compiler.getConstantData().add(string); method.load(index); - method.invokeStatic(unitClassName, GET_STRING.tag(), methodDescriptor(String.class, int.class)); + method.invokestatic(unitClassName, GET_STRING.tag(), methodDescriptor(String.class, int.class)); classEmitter.needGetConstantMethod(String.class); } @@ -1207,7 +1201,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { * * @param object object to load */ - public void loadConstant(final Object object) { + void loadConstant(final Object object) { final String unitClassName = getCurrentCompileUnit().getUnitClassName(); final ClassEmitter classEmitter = getCurrentCompileUnit().getClassEmitter(); final int index = compiler.getConstantData().add(object); @@ -1215,12 +1209,12 @@ public final class CodeGenerator extends NodeOperatorVisitor { if (cls == PropertyMap.class) { method.load(index); - method.invokeStatic(unitClassName, GET_MAP.tag(), methodDescriptor(PropertyMap.class, int.class)); + method.invokestatic(unitClassName, GET_MAP.tag(), methodDescriptor(PropertyMap.class, int.class)); classEmitter.needGetConstantMethod(PropertyMap.class); } else if (cls.isArray()) { method.load(index); final String methodName = ClassEmitter.getArrayMethodName(cls); - method.invokeStatic(unitClassName, methodName, methodDescriptor(cls, int.class)); + method.invokestatic(unitClassName, methodName, methodDescriptor(cls, int.class)); classEmitter.needGetConstantMethod(cls); } else { method.loadConstants(unitClassName).load(index).arrayload(); @@ -1363,7 +1357,12 @@ public final class CodeGenerator extends NodeOperatorVisitor { */ @Override protected MapCreator newMapCreator(final Class fieldObjectClass) { - return new ObjectMapCreator(fieldObjectClass, keys, symbols); + return new MapCreator(fieldObjectClass, keys, symbols) { + @Override + protected int getPropertyFlags(final Symbol symbol, final boolean isVarArg) { + return super.getPropertyFlags(symbol, isVarArg) | Property.IS_ALWAYS_OBJECT; + } + }; } }.makeObject(method); @@ -1487,7 +1486,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { method.label(falseLabel); load(rhs); - method.invokeStatic(CompilerConstants.className(ScriptRuntime.class), request.toString(), signature); + method.invokestatic(CompilerConstants.className(ScriptRuntime.class), request.toString(), signature); method._goto(endLabel); method.label(trueLabel); @@ -1628,7 +1627,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { load(arg).convert(Type.OBJECT); //TODO this should not be necessary below Lower } - method.invokeStatic( + method.invokestatic( CompilerConstants.className(ScriptRuntime.class), runtimeNode.getRequest().toString(), new FunctionSignature( @@ -1746,7 +1745,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { labels[i] = new Label("split_state_" + i); } - caller.tableSwitch(low, targetCount, breakLabel, labels); + caller.tableswitch(low, targetCount, breakLabel, labels); for (int i = low; i <= targetCount; i++) { caller.label(labels[i - low]); if (i == 0) { @@ -1853,7 +1852,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { table[value - lo] = labels[i]; } - method.tableSwitch(lo, hi, defaultLabel, table); + method.tableswitch(lo, hi, defaultLabel, table); } else { final int[] ints = new int[size]; @@ -1861,7 +1860,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { ints[i] = values[i]; } - method.lookupSwitch(defaultLabel, ints, labels); + method.lookupswitch(defaultLabel, ints, labels); } } else { load(expression); @@ -1869,7 +1868,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { if (expression.getType().isInteger()) { method.convert(Type.NUMBER).dup(); method.store(tag); - method.conditionalJump(MethodEmitter.Condition.NE, true, defaultLabel); + method.conditionalJump(Condition.NE, true, defaultLabel); } else { method.store(tag); } @@ -3245,7 +3244,7 @@ public final class CodeGenerator extends NodeOperatorVisitor { new ObjectCreator(this, new ArrayList(), new ArrayList(), false, false) { @Override - public void makeObject(final MethodEmitter method) { + protected void makeObject(final MethodEmitter method) { final String className = isLazy ? SCRIPTFUNCTION_TRAMPOLINE_OBJECT : SCRIPTFUNCTION_IMPL_OBJECT; method._new(className).dup(); @@ -3286,36 +3285,36 @@ public final class CodeGenerator extends NodeOperatorVisitor { * is from the code pipeline is Global */ private MethodEmitter globalInstance() { - return method.invokeStatic(GLOBAL_OBJECT, "instance", "()L" + GLOBAL_OBJECT + ';'); + return method.invokestatic(GLOBAL_OBJECT, "instance", "()L" + GLOBAL_OBJECT + ';'); } private MethodEmitter globalObjectPrototype() { - return method.invokeStatic(GLOBAL_OBJECT, "objectPrototype", methodDescriptor(ScriptObject.class)); + return method.invokestatic(GLOBAL_OBJECT, "objectPrototype", methodDescriptor(ScriptObject.class)); } private MethodEmitter globalAllocateArguments() { - return method.invokeStatic(GLOBAL_OBJECT, "allocateArguments", methodDescriptor(ScriptObject.class, Object[].class, Object.class, int.class)); + return method.invokestatic(GLOBAL_OBJECT, "allocateArguments", methodDescriptor(ScriptObject.class, Object[].class, Object.class, int.class)); } private MethodEmitter globalNewRegExp() { - return method.invokeStatic(GLOBAL_OBJECT, "newRegExp", methodDescriptor(Object.class, String.class, String.class)); + return method.invokestatic(GLOBAL_OBJECT, "newRegExp", methodDescriptor(Object.class, String.class, String.class)); } private MethodEmitter globalRegExpCopy() { - return method.invokeStatic(GLOBAL_OBJECT, "regExpCopy", methodDescriptor(Object.class, Object.class)); + return method.invokestatic(GLOBAL_OBJECT, "regExpCopy", methodDescriptor(Object.class, Object.class)); } private MethodEmitter globalAllocateArray(final ArrayType type) { //make sure the native array is treated as an array type - return method.invokeStatic(GLOBAL_OBJECT, "allocate", "(" + type.getDescriptor() + ")Ljdk/nashorn/internal/objects/NativeArray;"); + return method.invokestatic(GLOBAL_OBJECT, "allocate", "(" + type.getDescriptor() + ")Ljdk/nashorn/internal/objects/NativeArray;"); } private MethodEmitter globalIsEval() { - return method.invokeStatic(GLOBAL_OBJECT, "isEval", methodDescriptor(boolean.class, Object.class)); + return method.invokestatic(GLOBAL_OBJECT, "isEval", methodDescriptor(boolean.class, Object.class)); } private MethodEmitter globalDirectEval() { - return method.invokeStatic(GLOBAL_OBJECT, "directEval", + return method.invokestatic(GLOBAL_OBJECT, "directEval", methodDescriptor(Object.class, Object.class, Object.class, Object.class, Object.class, Object.class)); } } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java b/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java index 4d41e57ac8e..a756d4a4b03 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java @@ -76,18 +76,7 @@ enum CompilationPhase { CONSTANT_FOLDING_PHASE(EnumSet.of(INITIALIZED), CONSTANT_FOLDED) { @Override boolean transform(final Compiler compiler, final FunctionNode fn) { - final Context context = compiler.getContext(); - - if (context._print_ast) { - context.getErr().println(new ASTWriter(fn)); - } - - if (context._print_parse) { - context.getErr().println(new PrintVisitor(fn)); - } - fn.accept(new FoldConstants()); - return true; } @@ -137,7 +126,7 @@ enum CompilationPhase { if (context._print_lower_parse) { context.getErr().println(new PrintVisitor(fn)); - } + } } } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java index 68bafc20704..23a50685993 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java @@ -320,7 +320,7 @@ public enum CompilerConstants { return new Call(null, className, name, desc) { @Override public MethodEmitter invoke(final MethodEmitter method) { - return method.invokeSpecial(className, name, descriptor); + return method.invokespecial(className, name, descriptor); } }; } @@ -354,7 +354,7 @@ public enum CompilerConstants { return new Call(null, className, name, desc) { @Override public MethodEmitter invoke(final MethodEmitter method) { - return method.invokeStatic(className, name, descriptor); + return method.invokestatic(className, name, descriptor); } }; } @@ -389,7 +389,7 @@ public enum CompilerConstants { return new Call(null, className(clazz), name, methodDescriptor(rtype, ptypes)) { @Override public MethodEmitter invoke(final MethodEmitter method) { - return method.invokeVirtual(className, name, descriptor); + return method.invokevirtual(className, name, descriptor); } }; } @@ -409,7 +409,7 @@ public enum CompilerConstants { return new Call(null, className(clazz), name, methodDescriptor(rtype, ptypes)) { @Override public MethodEmitter invoke(final MethodEmitter method) { - return method.invokeInterface(className, name, descriptor); + return method.invokeinterface(className, name, descriptor); } }; } @@ -519,7 +519,7 @@ public enum CompilerConstants { return new Call(MH.findStatic(lookup, clazz, name, MH.type(rtype, ptypes)), className(clazz), name, methodDescriptor(rtype, ptypes)) { @Override public MethodEmitter invoke(final MethodEmitter method) { - return method.invokeStatic(className, name, descriptor); + return method.invokestatic(className, name, descriptor); } }; } @@ -553,7 +553,7 @@ public enum CompilerConstants { return new Call(MH.findVirtual(lookup, clazz, name, MH.type(rtype, ptypes)), className(clazz), name, methodDescriptor(rtype, ptypes)) { @Override public MethodEmitter invoke(final MethodEmitter method) { - return method.invokeVirtual(className, name, descriptor); + return method.invokevirtual(className, name, descriptor); } }; } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Condition.java b/nashorn/src/jdk/nashorn/internal/codegen/Condition.java new file mode 100644 index 00000000000..f2fb59926c8 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/codegen/Condition.java @@ -0,0 +1,107 @@ +/* + * 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 jdk.nashorn.internal.codegen; + +import static jdk.internal.org.objectweb.asm.Opcodes.IFEQ; +import static jdk.internal.org.objectweb.asm.Opcodes.IFGE; +import static jdk.internal.org.objectweb.asm.Opcodes.IFGT; +import static jdk.internal.org.objectweb.asm.Opcodes.IFLE; +import static jdk.internal.org.objectweb.asm.Opcodes.IFLT; +import static jdk.internal.org.objectweb.asm.Opcodes.IFNE; +import static jdk.internal.org.objectweb.asm.Opcodes.IF_ACMPEQ; +import static jdk.internal.org.objectweb.asm.Opcodes.IF_ACMPNE; +import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPEQ; +import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPGE; +import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPGT; +import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPLE; +import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPLT; +import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPNE; +import jdk.nashorn.internal.ir.RuntimeNode; + +/** + * Condition enum used for all kinds of jumps, regardless of type + */ +enum Condition { + EQ, + NE, + LE, + LT, + GE, + GT; + + static Condition forRuntimeRequest(final RuntimeNode.Request request) { + try { + final String reqString = request.toString().replace("_STRICT", ""); + return Condition.valueOf(reqString); + } catch (final IllegalArgumentException e) { + return null; + } + } + + static int toUnary(final Condition c) { + switch (c) { + case EQ: + return IFEQ; + case NE: + return IFNE; + case LE: + return IFLE; + case LT: + return IFLT; + case GE: + return IFGE; + case GT: + return IFGT; + default: + assert false; + return -1; + } + } + + static int toBinary(final Condition c) { + return toBinary(c, false); + } + + static int toBinary(final Condition c, final boolean isObject) { + switch (c) { + case EQ: + return isObject ? IF_ACMPEQ : IF_ICMPEQ; + case NE: + return isObject ? IF_ACMPNE : IF_ICMPNE; + case LE: + return IF_ICMPLE; + case LT: + return IF_ICMPLT; + case GE: + return IF_ICMPGE; + case GT: + return IF_ICMPGT; + default: + assert false; + return -1; + } + } +} diff --git a/nashorn/src/jdk/nashorn/internal/codegen/objects/FieldObjectCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java similarity index 92% rename from nashorn/src/jdk/nashorn/internal/codegen/objects/FieldObjectCreator.java rename to nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java index 46219f05cd2..83e75cc7ed3 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/objects/FieldObjectCreator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.nashorn.internal.codegen.objects; +package jdk.nashorn.internal.codegen; import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS; import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; @@ -32,8 +32,6 @@ import static jdk.nashorn.internal.codegen.types.Type.OBJECT; import java.util.Iterator; import java.util.List; -import jdk.nashorn.internal.codegen.CodeGenerator; -import jdk.nashorn.internal.codegen.MethodEmitter; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.runtime.PropertyMap; @@ -63,7 +61,7 @@ public abstract class FieldObjectCreator extends ObjectCreator { * @param symbols symbols for fields in object * @param values list of values corresponding to keys */ - public FieldObjectCreator(final CodeGenerator codegen, final List keys, final List symbols, final List values) { + FieldObjectCreator(final CodeGenerator codegen, final List keys, final List symbols, final List values) { this(codegen, keys, symbols, values, false, false); } @@ -77,7 +75,7 @@ public abstract class FieldObjectCreator extends ObjectCreator { * @param isScope is this a scope object * @param hasArguments does the created object have an "arguments" property */ - public FieldObjectCreator(final CodeGenerator codegen, final List keys, final List symbols, final List values, final boolean isScope, final boolean hasArguments) { + FieldObjectCreator(final CodeGenerator codegen, final List keys, final List symbols, final List values, final boolean isScope, final boolean hasArguments) { super(codegen, keys, symbols, isScope, hasArguments); this.values = values; this.callSiteFlags = codegen.getCallSiteFlags(); @@ -97,7 +95,7 @@ public abstract class FieldObjectCreator extends ObjectCreator { * @param method the method emitter */ @Override - public void makeObject(final MethodEmitter method) { + protected void makeObject(final MethodEmitter method) { makeMap(); method._new(getClassName()).dup(); // create instance @@ -190,5 +188,4 @@ public abstract class FieldObjectCreator extends ObjectCreator { loadValue(value); method.dynamicSetIndex(callSiteFlags); } - } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java b/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java index 26d040cdb62..fcfdf624814 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java @@ -202,7 +202,6 @@ public final class FunctionSignature { return methodType; } - private static Type[] objectArgs(final int nArgs) { final Type[] array = new Type[nArgs]; for (int i = 0; i < nArgs; i++) { diff --git a/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectMapCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/Label.java similarity index 50% rename from nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectMapCreator.java rename to nashorn/src/jdk/nashorn/internal/codegen/Label.java index c61100a3845..9d28caafd1d 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectMapCreator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Label.java @@ -22,33 +22,62 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package jdk.nashorn.internal.codegen; -package jdk.nashorn.internal.codegen.objects; +import java.util.ArrayDeque; -import java.util.List; -import jdk.nashorn.internal.ir.Symbol; -import jdk.nashorn.internal.runtime.Property; +import jdk.nashorn.internal.codegen.types.Type; /** - * This map creator is used to guarantee that all properties start out as - * object types. Only semantically significant in the -Dnashorn.fields.dual=true world, - * where we want to avoid invalidation upon initialization e.g. for var x = {a:"str"}; + * Abstraction for labels, separating a label from the underlying + * byte code emitter. Also augmenting label with e.g. a name + * for easier debugging and reading code + * + * see -Dnashorn.codegen.debug, --log=codegen */ +public class Label extends jdk.internal.org.objectweb.asm.Label { + /** Name of this label */ + private final String name; + + /** Type stack at this label */ + private ArrayDeque stack; -public class ObjectMapCreator extends MapCreator { /** * Constructor * - * @param structure structure for object class - * @param keys keys in object - * @param symbols symbols in object corresponding to keys + * @param name name of this label */ - public ObjectMapCreator(final Class structure, final List keys, final List symbols) { - super(structure, keys, symbols); + public Label(final String name) { + super(); + this.name = name; + } + + /** + * Copy constructor + * + * @param label a label to clone + */ + public Label(final Label label) { + super(); + this.name = label.name; + } + + ArrayDeque getStack() { + return stack; + } + + void setStack(final ArrayDeque stack) { + this.stack = stack; } @Override - protected int getPropertyFlags(final Symbol symbol, final boolean isVarArg) { - return super.getPropertyFlags(symbol, isVarArg) | Property.IS_ALWAYS_OBJECT; + public String toString() { + final StringBuilder sb = new StringBuilder(); + String s = super.toString(); + s = s.substring(1, s.length()); + sb.append(name).append('_').append(Long.toHexString(Long.parseLong(s))); + + return sb.toString(); } } + diff --git a/nashorn/src/jdk/nashorn/internal/codegen/objects/MapCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java similarity index 91% rename from nashorn/src/jdk/nashorn/internal/codegen/objects/MapCreator.java rename to nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java index 1696597b862..865c46bf010 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/objects/MapCreator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.nashorn.internal.codegen.objects; +package jdk.nashorn.internal.codegen; import java.util.ArrayList; import java.util.List; @@ -53,7 +53,7 @@ public class MapCreator { * @param keys list of keys for map * @param symbols list of symbols for map */ - public MapCreator(final Class structure, final List keys, final List symbols) { + MapCreator(final Class structure, final List keys, final List symbols) { final int size = keys.size(); this.structure = structure; @@ -68,7 +68,7 @@ public class MapCreator { * * @return New map populated with accessor properties. */ - public PropertyMap makeMap(final boolean hasArguments) { + PropertyMap makeMap(final boolean hasArguments) { final List properties = new ArrayList<>(); assert keys != null; @@ -86,8 +86,7 @@ public class MapCreator { } /** - * Compute property flags given local state of a field. Maybe be overridden and extended, - * as is the case in {@link ObjectMapCreator} + * Compute property flags given local state of a field. May be overridden and extended, * * @param symbol symbol to check * @param hasArguments does the created object have an "arguments" property diff --git a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java index 4aaa8fecbbe..dc1eac9ff28 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java @@ -43,10 +43,6 @@ import static jdk.internal.org.objectweb.asm.Opcodes.IFNULL; import static jdk.internal.org.objectweb.asm.Opcodes.IF_ACMPEQ; import static jdk.internal.org.objectweb.asm.Opcodes.IF_ACMPNE; import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPEQ; -import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPGE; -import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPGT; -import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPLE; -import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPLT; import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPNE; import static jdk.internal.org.objectweb.asm.Opcodes.INSTANCEOF; import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE; @@ -114,7 +110,7 @@ public class MethodEmitter implements Emitter { private final MethodVisitor method; /** Current type stack for current evaluation */ - protected ArrayDeque stack; + private ArrayDeque stack; /** Parent classEmitter representing the class of this method */ private final ClassEmitter classEmitter; @@ -287,7 +283,7 @@ public class MethodEmitter implements Emitter { * * @return the type at position "pos" on the stack */ - public final Type peekType(final int pos) { + final Type peekType(final int pos) { final Iterator iter = stack.iterator(); for (int i = 0; i < pos; i++) { iter.next(); @@ -300,7 +296,7 @@ public class MethodEmitter implements Emitter { * * @return the type at the top of the stack */ - public final Type peekType() { + final Type peekType() { return stack.peek(); } @@ -312,7 +308,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter _new(final String classDescriptor) { + MethodEmitter _new(final String classDescriptor) { debug("new", classDescriptor); method.visitTypeInsn(NEW, classDescriptor); pushType(Type.OBJECT); @@ -327,7 +323,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter _new(final Class clazz) { + MethodEmitter _new(final Class clazz) { return _new(className(clazz)); } @@ -338,7 +334,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter newInstance(final Class clazz) { + MethodEmitter newInstance(final Class clazz) { return invoke(constructorNoLookup(clazz)); } @@ -352,7 +348,7 @@ public class MethodEmitter implements Emitter { * @return the method emitter, or null if depth is illegal and * has no instruction equivalent. */ - public MethodEmitter dup(final int depth) { + MethodEmitter dup(final int depth) { if (peekType().dup(method, depth) == null) { return null; } @@ -396,7 +392,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter dup2() { + MethodEmitter dup2() { debug("dup2"); if (peekType().isCategory2()) { @@ -417,7 +413,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter dup() { + MethodEmitter dup() { return dup(0); } @@ -426,7 +422,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter pop() { + MethodEmitter pop() { debug("pop", peekType()); popType().pop(method); return this; @@ -438,7 +434,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter pop2() { + MethodEmitter pop2() { if (peekType().isCategory2()) { popType(); } else { @@ -453,7 +449,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter swap() { + MethodEmitter swap() { debug("swap"); final Type p0 = popType(); @@ -473,7 +469,7 @@ public class MethodEmitter implements Emitter { * @param start start of scope * @param end end of scope */ - public void localVariable(final Symbol symbol, final Label start, final Label end) { + void localVariable(final Symbol symbol, final Label start, final Label end) { if (!symbol.hasSlot()) { return; } @@ -492,7 +488,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter newStringBuilder() { + MethodEmitter newStringBuilder() { return invoke(constructorNoLookup(StringBuilder.class)).dup(); } @@ -503,7 +499,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter stringBuilderAppend() { + MethodEmitter stringBuilderAppend() { convert(Type.STRING); return invoke(virtualCallNoLookup(StringBuilder.class, "append", StringBuilder.class, String.class)); } @@ -515,7 +511,7 @@ public class MethodEmitter implements Emitter { * @param start start * @param end end */ - public void markerVariable(final String name, final Label start, final Label end) { + void markerVariable(final String name, final Label start, final Label end) { method.visitLocalVariable(name, Type.OBJECT.getDescriptor(), null, start, end, 0); } @@ -525,7 +521,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter and() { + MethodEmitter and() { debug("and"); pushType(get2i().and(method)); return this; @@ -537,7 +533,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter or() { + MethodEmitter or() { debug("or"); pushType(get2i().or(method)); return this; @@ -549,7 +545,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter xor() { + MethodEmitter xor() { debug("xor"); pushType(get2i().xor(method)); return this; @@ -561,7 +557,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter shr() { + MethodEmitter shr() { debug("shr"); popType(Type.INT); pushType(popInteger().shr(method)); @@ -574,7 +570,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter shl() { + MethodEmitter shl() { debug("shl"); popType(Type.INT); pushType(popInteger().shl(method)); @@ -587,7 +583,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter sar() { + MethodEmitter sar() { debug("sar"); popType(Type.INT); pushType(popInteger().sar(method)); @@ -599,7 +595,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter neg() { + MethodEmitter neg() { debug("neg"); pushType(popNumeric().neg(method)); return this; @@ -611,7 +607,7 @@ public class MethodEmitter implements Emitter { * * @param recovery label pointing to start of catch block */ - public void _catch(final Label recovery) { + void _catch(final Label recovery) { stack.clear(); stack.push(Type.OBJECT); label(recovery); @@ -625,7 +621,7 @@ public class MethodEmitter implements Emitter { * @param recovery start label for catch * @param typeDescriptor type descriptor for exception */ - public void _try(final Label entry, final Label exit, final Label recovery, final String typeDescriptor) { + void _try(final Label entry, final Label exit, final Label recovery, final String typeDescriptor) { method.visitTryCatchBlock(entry, exit, recovery, typeDescriptor); } @@ -637,7 +633,7 @@ public class MethodEmitter implements Emitter { * @param recovery start label for catch * @param clazz exception class */ - public void _try(final Label entry, final Label exit, final Label recovery, final Class clazz) { + void _try(final Label entry, final Label exit, final Label recovery, final Class clazz) { method.visitTryCatchBlock(entry, exit, recovery, CompilerConstants.className(clazz)); } @@ -648,7 +644,7 @@ public class MethodEmitter implements Emitter { * @param exit end label for try * @param recovery start label for catch */ - public void _try(final Label entry, final Label exit, final Label recovery) { + void _try(final Label entry, final Label exit, final Label recovery) { _try(entry, exit, recovery, (String)null); } @@ -658,7 +654,7 @@ public class MethodEmitter implements Emitter { * @param unitClassName name of the compile unit from which to load constants * @return this method emitter */ - public MethodEmitter loadConstants(final String unitClassName) { + MethodEmitter loadConstants(final String unitClassName) { getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor()); assert peekType().isArray() : peekType(); return this; @@ -673,7 +669,7 @@ public class MethodEmitter implements Emitter { * @param type the type for which to push UNDEFINED * @return the method emitter */ - public MethodEmitter loadUndefined(final Type type) { + MethodEmitter loadUndefined(final Type type) { debug("load undefined " + type); pushType(type.loadUndefined(method)); return this; @@ -685,7 +681,7 @@ public class MethodEmitter implements Emitter { * @param type the type * @return the method emitter */ - public MethodEmitter loadEmpty(final Type type) { + MethodEmitter loadEmpty(final Type type) { debug("load empty " + type); pushType(type.loadEmpty(method)); return this; @@ -696,7 +692,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter loadNull() { + MethodEmitter loadNull() { debug("aconst_null"); pushType(Type.OBJECT.ldc(method, null)); return this; @@ -709,7 +705,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter loadType(final String className) { + MethodEmitter loadType(final String className) { debug("load type", className); method.visitLdcInsn(jdk.internal.org.objectweb.asm.Type.getObjectType(className)); pushType(Type.OBJECT); @@ -723,7 +719,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter load(final boolean b) { + MethodEmitter load(final boolean b) { debug("load boolean", b); pushType(Type.BOOLEAN.ldc(method, b)); return this; @@ -736,7 +732,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter load(final int i) { + MethodEmitter load(final int i) { debug("load int", i); pushType(Type.INT.ldc(method, i)); return this; @@ -749,7 +745,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter load(final double d) { + MethodEmitter load(final double d) { debug("load double", d); pushType(Type.NUMBER.ldc(method, d)); return this; @@ -762,7 +758,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter load(final long l) { + MethodEmitter load(final long l) { debug("load long", l); pushType(Type.LONG.ldc(method, l)); return this; @@ -772,7 +768,7 @@ public class MethodEmitter implements Emitter { * Fetch the length of an array. * @return Array length. */ - public MethodEmitter arraylength() { + MethodEmitter arraylength() { debug("arraylength"); popType(Type.OBJECT); pushType(Type.OBJECT_ARRAY.arraylength(method)); @@ -786,7 +782,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter load(final String s) { + MethodEmitter load(final String s) { debug("load string", s); if (s == null) { @@ -826,7 +822,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter load(final Symbol symbol) { + MethodEmitter load(final Symbol symbol) { assert symbol != null; if (symbol.hasSlot()) { final int slot = symbol.getSlot(); @@ -837,7 +833,7 @@ public class MethodEmitter implements Emitter { assert !symbol.isScope(); assert functionNode.isVarArg() : "Non-vararg functions have slotted parameters"; final int index = symbol.getFieldIndex(); - if(functionNode.needsArguments()) { + if (functionNode.needsArguments()) { // ScriptObject.getArgument(int) on arguments debug("load symbol", symbol.getName(), " arguments index=", index); loadArguments(); @@ -864,7 +860,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter load(final Type type, final int slot) { + MethodEmitter load(final Type type, final int slot) { debug("explicit load", type, slot); final Type loadType = type.load(method, slot); pushType(loadType == Type.OBJECT && isThisSlot(slot) ? Type.THIS : loadType); @@ -886,7 +882,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter loadThis() { + MethodEmitter loadThis() { load(functionNode.getThisNode().getSymbol()); return this; } @@ -896,7 +892,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter loadScope() { + MethodEmitter loadScope() { if (peekType() == Type.SCOPE) { dup(); return this; @@ -910,7 +906,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter loadResult() { + MethodEmitter loadResult() { load(functionNode.getResultNode().getSymbol()); return this; } @@ -924,11 +920,9 @@ public class MethodEmitter implements Emitter { * @param descName descriptor * @param flags flags that describe this handle, e.g. invokespecial new, or invoke virtual * - * @see ClassEmitter.Flag - * * @return the method emitter */ - public MethodEmitter loadHandle(final String className, final String methodName, final String descName, final EnumSet flags) { + MethodEmitter loadHandle(final String className, final String methodName, final String descName, final EnumSet flags) { debug("load handle "); pushType(Type.OBJECT.ldc(method, new Handle(Flag.getValue(flags), className, methodName, descName))); return this; @@ -939,7 +933,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter loadVarArgs() { + MethodEmitter loadVarArgs() { debug("load var args " + functionNode.getVarArgsNode().getSymbol()); return load(functionNode.getVarArgsNode().getSymbol()); } @@ -949,7 +943,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter loadArguments() { + MethodEmitter loadArguments() { debug("load arguments ", functionNode.getArgumentsNode().getSymbol()); assert functionNode.getArgumentsNode().getSymbol().getSlot() != 0; return load(functionNode.getArgumentsNode().getSymbol()); @@ -960,7 +954,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter loadCallee() { + MethodEmitter loadCallee() { final Symbol calleeSymbol = functionNode.getCalleeNode().getSymbol(); debug("load callee ", calleeSymbol); assert calleeSymbol.getSlot() == 0 : "callee has wrong slot " + calleeSymbol.getSlot() + " in " + functionNode.getName(); @@ -971,7 +965,7 @@ public class MethodEmitter implements Emitter { /** * Pop the scope from the stack and store it in its predefined slot */ - public void storeScope() { + void storeScope() { debug("store scope"); store(functionNode.getScopeNode().getSymbol()); } @@ -979,7 +973,7 @@ public class MethodEmitter implements Emitter { /** * Pop the return from the stack and store it in its predefined slot */ - public void storeResult() { + void storeResult() { debug("store result"); store(functionNode.getResultNode().getSymbol()); } @@ -987,7 +981,7 @@ public class MethodEmitter implements Emitter { /** * Pop the arguments array from the stack and store it in its predefined slot */ - public void storeArguments() { + void storeArguments() { debug("store arguments"); store(functionNode.getArgumentsNode().getSymbol()); } @@ -996,7 +990,7 @@ public class MethodEmitter implements Emitter { * Load an element from an array, determining type automatically * @return the method emitter */ - public MethodEmitter arrayload() { + MethodEmitter arrayload() { debug("Xaload"); popType(Type.INT); pushType(popArray().aload(method)); @@ -1007,7 +1001,7 @@ public class MethodEmitter implements Emitter { * Pop a value, an index and an array from the stack and store * the value at the given index in the array. */ - public void arraystore() { + void arraystore() { debug("Xastore"); final Type value = popType(); final Type index = popType(Type.INT); @@ -1025,7 +1019,7 @@ public class MethodEmitter implements Emitter { * * @param symbol symbol to store stack to */ - public void store(final Symbol symbol) { + void store(final Symbol symbol) { assert symbol != null : "No symbol to store"; if (symbol.hasSlot()) { final int slot = symbol.getSlot(); @@ -1035,7 +1029,7 @@ public class MethodEmitter implements Emitter { assert !symbol.isScope(); assert functionNode.isVarArg() : "Non-vararg functions have slotted parameters"; final int index = symbol.getFieldIndex(); - if(functionNode.needsArguments()) { + if (functionNode.needsArguments()) { debug("store symbol", symbol.getName(), " arguments index=", index); loadArguments(); load(index); @@ -1057,7 +1051,7 @@ public class MethodEmitter implements Emitter { * @param type the type to pop * @param slot the slot */ - public void store(final Type type, final int slot) { + void store(final Type type, final int slot) { popType(type); type.store(method, slot); } @@ -1068,7 +1062,7 @@ public class MethodEmitter implements Emitter { * @param slot the int slot * @param increment the amount to increment */ - public void iinc(final int slot, final int increment) { + void iinc(final int slot, final int increment) { debug("iinc"); method.visitIincInsn(slot, increment); } @@ -1094,7 +1088,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter _instanceof(final String classDescriptor) { + MethodEmitter _instanceof(final String classDescriptor) { debug("instanceof", classDescriptor); popType(Type.OBJECT); method.visitTypeInsn(INSTANCEOF, classDescriptor); @@ -1111,7 +1105,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter _instanceof(final Class clazz) { + MethodEmitter _instanceof(final Class clazz) { return _instanceof(CompilerConstants.className(clazz)); } @@ -1123,7 +1117,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter checkcast(final String classDescriptor) { + MethodEmitter checkcast(final String classDescriptor) { debug("checkcast", classDescriptor); assert peekType().isObject(); method.visitTypeInsn(CHECKCAST, classDescriptor); @@ -1138,7 +1132,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter checkcast(final Class clazz) { + MethodEmitter checkcast(final Class clazz) { return checkcast(CompilerConstants.className(clazz)); } @@ -1150,7 +1144,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter newarray(final ArrayType arrayType) { + MethodEmitter newarray(final ArrayType arrayType) { debug("newarray ", "arrayType=" + arrayType); popType(Type.INT); //LENGTH pushType(arrayType.newarray(method)); @@ -1166,7 +1160,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter multinewarray(final ArrayType arrayType, final int dims) { + MethodEmitter multinewarray(final ArrayType arrayType, final int dims) { debug("multianewarray ", arrayType, dims); for (int i = 0; i < dims; i++) { popType(Type.INT); //LENGTH @@ -1200,7 +1194,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter invoke(final Call call) { + MethodEmitter invoke(final Call call) { return call.invoke(this); } @@ -1229,7 +1223,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter invokeSpecial(final String className, final String methodName, final String methodDescriptor) { + MethodEmitter invokespecial(final String className, final String methodName, final String methodDescriptor) { debug("invokespecial", className + "." + methodName + methodDescriptor); return invoke(INVOKESPECIAL, className, methodName, methodDescriptor, true); } @@ -1243,7 +1237,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter invokeVirtual(final String className, final String methodName, final String methodDescriptor) { + MethodEmitter invokevirtual(final String className, final String methodName, final String methodDescriptor) { debug("invokevirtual", className + "." + methodName + methodDescriptor + " " + stack); return invoke(INVOKEVIRTUAL, className, methodName, methodDescriptor, true); } @@ -1257,7 +1251,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter invokeStatic(final String className, final String methodName, final String methodDescriptor) { + MethodEmitter invokestatic(final String className, final String methodName, final String methodDescriptor) { debug("invokestatic", className + "." + methodName + methodDescriptor); invoke(INVOKESTATIC, className, methodName, methodDescriptor, false); return this; @@ -1274,8 +1268,8 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter invokeStatic(final String className, final String methodName, final String methodDescriptor, final Type returnType) { - invokeStatic(className, methodName, methodDescriptor); + MethodEmitter invokeStatic(final String className, final String methodName, final String methodDescriptor, final Type returnType) { + invokestatic(className, methodName, methodDescriptor); popType(); pushType(returnType); return this; @@ -1290,7 +1284,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter invokeInterface(final String className, final String methodName, final String methodDescriptor) { + MethodEmitter invokeinterface(final String className, final String methodName, final String methodDescriptor) { debug("invokeinterface", className + "." + methodName + methodDescriptor); return invoke(INVOKEINTERFACE, className, methodName, methodDescriptor, true); } @@ -1302,7 +1296,7 @@ public class MethodEmitter implements Emitter { * @param values case values for the table * @param table default label */ - public void lookupSwitch(final Label defaultLabel, final int[] values, final Label[] table) { + void lookupswitch(final Label defaultLabel, final int[] values, final Label[] table) { debug("lookupswitch", peekType()); popType(Type.INT); method.visitLookupSwitchInsn(defaultLabel, values, table); @@ -1315,7 +1309,7 @@ public class MethodEmitter implements Emitter { * @param defaultLabel default label * @param table label table */ - public void tableSwitch(final int lo, final int hi, final Label defaultLabel, final Label[] table) { + void tableswitch(final int lo, final int hi, final Label defaultLabel, final Label[] table) { debug("tableswitch", peekType()); popType(Type.INT); method.visitTableSwitchInsn(lo, hi, defaultLabel, table); @@ -1357,7 +1351,7 @@ public class MethodEmitter implements Emitter { * * @param type the type for the return */ - public void _return(final Type type) { + void _return(final Type type) { debug("return", type); assert stack.size() == 1 : "Only return value on stack allowed at return point - depth=" + stack.size() + " stack = " + stack; final Type stackType = peekType(); @@ -1371,14 +1365,14 @@ public class MethodEmitter implements Emitter { /** * Perform a return using the stack top value as the guide for the type */ - public void _return() { + void _return() { _return(peekType()); } /** * Perform a void return. */ - public void returnVoid() { + void returnVoid() { debug("return [void]"); assert stack.isEmpty() : stack; method.visitInsn(RETURN); @@ -1392,7 +1386,7 @@ public class MethodEmitter implements Emitter { * * @param label destination label */ - public void splitAwareGoto(final Label label) { + void splitAwareGoto(final Label label) { if (splitNode != null) { final int index = splitNode.getExternalTargets().indexOf(label); @@ -1418,7 +1412,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter cmp(final boolean isCmpG) { + MethodEmitter cmp(final boolean isCmpG) { pushType(get2n().cmp(method, isCmpG)); return this; } @@ -1443,7 +1437,7 @@ public class MethodEmitter implements Emitter { * * @param label label to true case */ - public void if_acmpeq(final Label label) { + void if_acmpeq(final Label label) { debug("if_acmpeq", label); jump(IF_ACMPEQ, label, 2); } @@ -1453,7 +1447,7 @@ public class MethodEmitter implements Emitter { * * @param label label to true case */ - public void if_acmpne(final Label label) { + void if_acmpne(final Label label) { debug("if_acmpne", label); jump(IF_ACMPNE, label, 2); } @@ -1463,7 +1457,7 @@ public class MethodEmitter implements Emitter { * * @param label label to true case */ - public void ifnull(final Label label) { + void ifnull(final Label label) { debug("ifnull", label); jump(IFNULL, label, 1); } @@ -1473,7 +1467,7 @@ public class MethodEmitter implements Emitter { * * @param label label to true case */ - public void ifnonnull(final Label label) { + void ifnonnull(final Label label) { debug("ifnonnull", label); jump(IFNONNULL, label, 1); } @@ -1483,7 +1477,7 @@ public class MethodEmitter implements Emitter { * * @param label label to true case */ - public void ifeq(final Label label) { + void ifeq(final Label label) { debug("ifeq ", label); jump(IFEQ, label, 1); } @@ -1493,7 +1487,7 @@ public class MethodEmitter implements Emitter { * * @param label label to true case */ - public void if_icmpeq(final Label label) { + void if_icmpeq(final Label label) { debug("if_icmpeq", label); jump(IF_ICMPEQ, label, 2); } @@ -1503,8 +1497,7 @@ public class MethodEmitter implements Emitter { * * @param label label to true case */ - - public void ifne(final Label label) { + void ifne(final Label label) { debug("ifne", label); jump(IFNE, label, 1); } @@ -1514,7 +1507,7 @@ public class MethodEmitter implements Emitter { * * @param label label to true case */ - public void if_icmpne(final Label label) { + void if_icmpne(final Label label) { debug("if_icmpne", label); jump(IF_ICMPNE, label, 2); } @@ -1524,7 +1517,7 @@ public class MethodEmitter implements Emitter { * * @param label label to true case */ - public void iflt(final Label label) { + void iflt(final Label label) { debug("iflt", label); jump(IFLT, label, 1); } @@ -1534,7 +1527,7 @@ public class MethodEmitter implements Emitter { * * @param label label to true case */ - public void ifle(final Label label) { + void ifle(final Label label) { debug("ifle", label); jump(IFLE, label, 1); } @@ -1544,7 +1537,7 @@ public class MethodEmitter implements Emitter { * * @param label label to true case */ - public void ifgt(final Label label) { + void ifgt(final Label label) { debug("ifgt", label); jump(IFGT, label, 1); } @@ -1554,7 +1547,7 @@ public class MethodEmitter implements Emitter { * * @param label label to true case */ - public void ifge(final Label label) { + void ifge(final Label label) { debug("ifge", label); jump(IFGE, label, 1); } @@ -1564,7 +1557,7 @@ public class MethodEmitter implements Emitter { * * @param label destination label */ - public void _goto(final Label label) { + void _goto(final Label label) { debug("goto", label); jump(GOTO, label, 0); stack = null; @@ -1617,7 +1610,7 @@ public class MethodEmitter implements Emitter { * * @param label the label */ - public void label(final Label label) { + void label(final Label label) { /* * If stack == null, this means that we came here not through a fallthrough. * E.g. a label after an athrow. Then we create a new stack if one doesn't exist @@ -1643,7 +1636,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter convert(final Type to) { + MethodEmitter convert(final Type to) { final Type type = peekType().convert(method, to); if (type != null) { if (peekType() != to) { @@ -1696,7 +1689,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter add() { + MethodEmitter add() { debug("add"); pushType(get2().add(method)); return this; @@ -1707,7 +1700,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter sub() { + MethodEmitter sub() { debug("sub"); pushType(get2n().sub(method)); return this; @@ -1718,7 +1711,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter mul() { + MethodEmitter mul() { debug("mul "); pushType(get2n().mul(method)); return this; @@ -1729,7 +1722,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter div() { + MethodEmitter div() { debug("div"); pushType(get2n().div(method)); return this; @@ -1740,7 +1733,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter rem() { + MethodEmitter rem() { debug("rem"); pushType(get2n().rem(method)); return this; @@ -1795,7 +1788,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter dynamicNew(final int argCount, final int flags) { + MethodEmitter dynamicNew(final int argCount, final int flags) { debug("dynamic_new", "argcount=" + argCount); final String signature = getDynamicSignature(Type.OBJECT, argCount); method.visitInvokeDynamicInsn("dyn:new", signature, LINKERBOOTSTRAP, flags); @@ -1812,7 +1805,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter dynamicCall(final Type returnType, final int argCount, final int flags) { + MethodEmitter dynamicCall(final Type returnType, final int argCount, final int flags) { debug("dynamic_call", "args=" + argCount, "returnType=" + returnType); final String signature = getDynamicSignature(returnType, argCount); // +1 because the function itself is the 1st parameter for dynamic calls (what you call - call target) debug(" signature", signature); @@ -1831,7 +1824,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter dynamicRuntimeCall(final String name, final Type returnType, final RuntimeNode.Request request) { + MethodEmitter dynamicRuntimeCall(final String name, final Type returnType, final RuntimeNode.Request request) { debug("dynamic_runtime_call", name, "args=" + request.getArity(), "returnType=" + returnType); final String signature = getDynamicSignature(returnType, request.getArity()); debug(" signature", signature); @@ -1851,7 +1844,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod) { + MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod) { debug("dynamic_get", name, valueType); Type type = valueType; @@ -1877,7 +1870,7 @@ public class MethodEmitter implements Emitter { * @param name name of property * @param flags call site flags */ - public void dynamicSet(final Type valueType, final String name, final int flags) { + void dynamicSet(final Type valueType, final String name, final int flags) { debug("dynamic_set", name, peekType()); Type type = valueType; @@ -1902,7 +1895,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter dynamicGetIndex(final Type result, final int flags, final boolean isMethod) { + MethodEmitter dynamicGetIndex(final Type result, final int flags, final boolean isMethod) { debug("dynamic_get_index", peekType(1) + "[" + peekType() + "]"); Type resultType = result; @@ -1938,7 +1931,7 @@ public class MethodEmitter implements Emitter { * * @param flags call site flags for setter */ - public void dynamicSetIndex(final int flags) { + void dynamicSetIndex(final int flags) { debug("dynamic_set_index", peekType(2) + "[" + peekType(1) + "] =", peekType()); Type value = peekType(); @@ -2015,7 +2008,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter getField(final FieldAccess fa) { + MethodEmitter getField(final FieldAccess fa) { return fa.get(this); } @@ -2024,7 +2017,7 @@ public class MethodEmitter implements Emitter { * * @param fa the field access */ - public void putField(final FieldAccess fa) { + void putField(final FieldAccess fa) { fa.put(this); } @@ -2038,7 +2031,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter getField(final String className, final String fieldName, final String fieldDescriptor) { + MethodEmitter getField(final String className, final String fieldName, final String fieldDescriptor) { debug("getfield", "receiver=" + peekType(), className + "." + fieldName + fieldDescriptor); final Type receiver = popType(); assert receiver.isObject(); @@ -2056,7 +2049,7 @@ public class MethodEmitter implements Emitter { * * @return the method emitter */ - public MethodEmitter getStatic(final String className, final String fieldName, final String fieldDescriptor) { + MethodEmitter getStatic(final String className, final String fieldName, final String fieldDescriptor) { debug("getstatic", className + "." + fieldName + "." + fieldDescriptor); method.visitFieldInsn(GETSTATIC, className, fieldName, fieldDescriptor); pushType(fieldType(fieldDescriptor)); @@ -2070,7 +2063,7 @@ public class MethodEmitter implements Emitter { * @param fieldName field name * @param fieldDescriptor field descriptor */ - public void putField(final String className, final String fieldName, final String fieldDescriptor) { + void putField(final String className, final String fieldName, final String fieldDescriptor) { debug("putfield", "receiver=" + peekType(1), "value=" + peekType()); popType(fieldType(fieldDescriptor)); popType(Type.OBJECT); @@ -2084,7 +2077,7 @@ public class MethodEmitter implements Emitter { * @param fieldName field name * @param fieldDescriptor field descriptor */ - public void putStatic(final String className, final String fieldName, final String fieldDescriptor) { + void putStatic(final String className, final String fieldName, final String fieldDescriptor) { debug("putfield", "value=" + peekType()); popType(fieldType(fieldDescriptor)); method.visitFieldInsn(PUTSTATIC, className, fieldName, fieldDescriptor); @@ -2096,7 +2089,7 @@ public class MethodEmitter implements Emitter { * @param line line number * @param label label */ - public void lineNumber(final int line, final Label label) { + void lineNumber(final int line, final Label label) { method.visitLineNumber(line, label); } @@ -2112,7 +2105,7 @@ public class MethodEmitter implements Emitter { /** * Emit a System.err.print statement of whatever is on top of the bytecode stack */ - public void print() { + void print() { getField(ERR_STREAM); swap(); convert(Type.OBJECT); @@ -2122,7 +2115,7 @@ public class MethodEmitter implements Emitter { /** * Emit a System.err.println statement of whatever is on top of the bytecode stack */ - public void println() { + void println() { getField(ERR_STREAM); swap(); convert(Type.OBJECT); @@ -2133,7 +2126,7 @@ public class MethodEmitter implements Emitter { * Emit a System.err.print statement * @param string string to print */ - public void print(final String string) { + void print(final String string) { getField(ERR_STREAM); load(string); invoke(PRINT); @@ -2143,7 +2136,7 @@ public class MethodEmitter implements Emitter { * Emit a System.err.println statement * @param string string to print */ - public void println(final String string) { + void println(final String string) { getField(ERR_STREAM); load(string); invoke(PRINTLN); @@ -2152,7 +2145,7 @@ public class MethodEmitter implements Emitter { /** * Print a stacktrace to S */ - public void stacktrace() { + void stacktrace() { _new(Throwable.class); dup(); invoke(constructorNoLookup(Throwable.class)); @@ -2254,130 +2247,11 @@ public class MethodEmitter implements Emitter { } } - - /** - * Abstraction for labels, separating a label from the underlying - * byte code emitter. Also augmenting label with e.g. a name - * for easier debugging and reading code - * - * see -Dnashorn.codegen.debug, --log=codegen - */ - public static class Label extends jdk.internal.org.objectweb.asm.Label { - /** Name of this label */ - private final String name; - - /** Type stack at this label */ - private ArrayDeque stack; - - /** - * Constructor - * - * @param name name of this label - */ - public Label(final String name) { - super(); - this.name = name; - } - - /** - * Copy constructor - * - * @param label a label to clone - */ - public Label(final Label label) { - super(); - name = label.name; - } - - ArrayDeque getStack() { - return stack; - } - - void setStack(final ArrayDeque stack) { - this.stack = stack; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(); - String s = super.toString(); - s = s.substring(1, s.length()); - sb.append(name).append('_').append(Long.toHexString(Long.parseLong(s))); - - return sb.toString(); - } - } - - /** - * Condition enum used for all kinds of jumps, regardless of type - */ - static enum Condition { - EQ, - NE, - LE, - LT, - GE, - GT; - - public static Condition forRuntimeRequest(final RuntimeNode.Request request) { - try { - final String reqString = request.toString().replace("_STRICT", ""); - return Condition.valueOf(reqString); - } catch (final IllegalArgumentException e) { - return null; - } - } - - public static int toUnary(final Condition c) { - switch (c) { - case EQ: - return IFEQ; - case NE: - return IFNE; - case LE: - return IFLE; - case LT: - return IFLT; - case GE: - return IFGE; - case GT: - return IFGT; - default: - assert false; - return -1; - } - } - - public static int toBinary(final Condition c) { - return toBinary(c, false); - } - - public static int toBinary(final Condition c, final boolean isObject) { - switch (c) { - case EQ: - return isObject ? IF_ACMPEQ : IF_ICMPEQ; - case NE: - return isObject ? IF_ACMPNE : IF_ICMPNE; - case LE: - return IF_ICMPLE; - case LT: - return IF_ICMPLT; - case GE: - return IF_ICMPGE; - case GT: - return IF_ICMPGT; - default: - assert false; - return -1; - } - } - } - /** * Set the current function node being emitted * @param functionNode the function node */ - public void setFunctionNode(final FunctionNode functionNode) { + void setFunctionNode(final FunctionNode functionNode) { this.functionNode = functionNode; } @@ -2387,7 +2261,7 @@ public class MethodEmitter implements Emitter { * * @return split node */ - public SplitNode getSplitNode() { + SplitNode getSplitNode() { return splitNode; } @@ -2395,7 +2269,7 @@ public class MethodEmitter implements Emitter { * Set the split node for this method emitter * @param splitNode split node */ - public void setSplitNode(final SplitNode splitNode) { + void setSplitNode(final SplitNode splitNode) { this.splitNode = splitNode; } } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectClassGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java similarity index 99% rename from nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectClassGenerator.java rename to nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java index 72f9181845d..25175db821a 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectClassGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.nashorn.internal.codegen.objects; +package jdk.nashorn.internal.codegen; import static jdk.nashorn.internal.codegen.Compiler.SCRIPTS_PACKAGE; import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE; @@ -45,9 +45,7 @@ import java.util.EnumSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import jdk.nashorn.internal.codegen.ClassEmitter; import jdk.nashorn.internal.codegen.ClassEmitter.Flag; -import jdk.nashorn.internal.codegen.MethodEmitter; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.runtime.AccessorProperty; import jdk.nashorn.internal.runtime.Context; @@ -67,7 +65,7 @@ public final class ObjectClassGenerator { /** * Marker for scope parameters. */ - public static final String SCOPE_MARKER = "P"; + static final String SCOPE_MARKER = "P"; /** * Debug field logger diff --git a/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java similarity index 94% rename from nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectCreator.java rename to nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java index 71c0b699da9..69a200d75a4 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/objects/ObjectCreator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java @@ -23,13 +23,9 @@ * questions. */ -package jdk.nashorn.internal.codegen.objects; +package jdk.nashorn.internal.codegen; import java.util.List; -import jdk.nashorn.internal.codegen.CodeGenerator; -import jdk.nashorn.internal.codegen.CompileUnit; -import jdk.nashorn.internal.codegen.Compiler; -import jdk.nashorn.internal.codegen.MethodEmitter; import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.PropertyMap; @@ -114,7 +110,7 @@ public abstract class ObjectCreator { * Generate code for making the object. * @param method Script method. */ - public abstract void makeObject(final MethodEmitter method); + protected abstract void makeObject(final MethodEmitter method); /** * Create a new MapCreator @@ -154,7 +150,7 @@ public abstract class ObjectCreator { * * @return script class name */ - public String getClassName() { + String getClassName() { return fieldObjectClassName; } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java b/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java index f8e26996298..588e2f4878e 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java @@ -48,7 +48,7 @@ import jdk.nashorn.internal.runtime.ScriptObject; *

      Scope calls must not be shared between normal callsites and callsites contained in a with * statement as this condition is not handled by current guards and will cause a runtime error.

      */ -public class SharedScopeCall { +class SharedScopeCall { /** Threshold for using shared scope calls with fast scope access. */ public static final int FAST_SCOPE_CALL_THRESHOLD = 4; @@ -118,7 +118,7 @@ public class SharedScopeCall { * @param method the method emitter */ public void generateInvoke(final MethodEmitter method) { - method.invokeStatic(compileUnit.getUnitClassName(), methodName, getStaticSignature()); + method.invokestatic(compileUnit.getUnitClassName(), methodName, getStaticSignature()); } /** @@ -138,8 +138,8 @@ public class SharedScopeCall { // Load correct scope by calling getProto() on the scope argument as often as specified // by the second argument. - final MethodEmitter.Label parentLoopStart = new MethodEmitter.Label("parent_loop_start"); - final MethodEmitter.Label parentLoopDone = new MethodEmitter.Label("parent_loop_done"); + final Label parentLoopStart = new Label("parent_loop_start"); + final Label parentLoopDone = new Label("parent_loop_done"); method.load(Type.OBJECT, 0); method.label(parentLoopStart); method.load(Type.INT, 1); diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java index d95fd4b6c37..de66869334a 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java @@ -396,7 +396,7 @@ final class Splitter extends NodeVisitor { * @param targetNode the jump target node. * @param targetLabel the jump target label. */ - private void searchJumpTarget(final Node targetNode, final MethodEmitter.Label targetLabel) { + private void searchJumpTarget(final Node targetNode, final Label targetLabel) { final SplitNode targetSplit = targetNodes.get(targetNode); // Note that targetSplit may be null, indicating that targetNode is in top level method. @@ -406,7 +406,7 @@ final class Splitter extends NodeVisitor { if (split == targetSplit) { break; } - final List externalTargets = split.getExternalTargets(); + final List