--- a/.hgtags Tue Sep 08 16:01:29 2015 +0400
+++ b/.hgtags Tue Sep 08 14:40:44 2015 -0700
@@ -322,3 +322,4 @@
c25e882cee9622ec75c4e9d60633539a2f0a8809 jdk9-b77
c8753d0be1778944dc512ec86a459941ea1ad2c3 jdk9-b78
3966bd3b8167419aa05c6718a4af1cf54b1e3c58 jdk9-b79
+3c9f5bd909ae7187f24622ee4b69f8a5756a9271 jdk9-b80
--- a/.hgtags-top-repo Tue Sep 08 16:01:29 2015 +0400
+++ b/.hgtags-top-repo Tue Sep 08 14:40:44 2015 -0700
@@ -322,3 +322,4 @@
7972dc8f2a47f0c4cd8f02fa5662af41f028aa14 jdk9-b77
8c40d4143ee13bdf8170c68cc384c36ab1e9fadb jdk9-b78
ba08a9f79b9849716bae1f39f71333d47f604012 jdk9-b79
+f7c5ae2933c0b8510a420d1713a955e4ffc7ad0b jdk9-b80
--- a/common/bin/logger.sh Tue Sep 08 16:01:29 2015 +0400
+++ b/common/bin/logger.sh Tue Sep 08 14:40:44 2015 -0700
@@ -41,5 +41,19 @@
trap "rm -rf \"$RCDIR\"" EXIT
LOGFILE=$1
shift
+
+# We need to handle command likes like "VAR1=val1 /usr/bin/cmd VAR2=val2".
+# Do this by shifting away prepended variable assignments, and export them
+# instead.
+is_prefix=true
+for opt; do
+ if [[ "$is_prefix" = true && "$opt" =~ ^.*=.*$ ]]; then
+ export $opt
+ shift
+ else
+ is_prefix=false
+ fi
+done
+
(exec 3>&1 ; ("$@" 2>&1 1>&3; echo $? > "$RCDIR/rc") | tee -a $LOGFILE 1>&2 ; exec 3>&-) | tee -a $LOGFILE
exit `cat "$RCDIR/rc"`
--- a/corba/.hgtags Tue Sep 08 16:01:29 2015 +0400
+++ b/corba/.hgtags Tue Sep 08 14:40:44 2015 -0700
@@ -322,3 +322,4 @@
8bb2441c0fec8b28f7bf11a0ca3ec1642e7ef457 jdk9-b77
182bb7accc5253bcfefd8edc1d4997ec8f9f8694 jdk9-b78
4ab250b8fac66ef8cd15ee78c40f0c651c96e16a jdk9-b79
+821a0373ef2d1642a9824facb938b901ad010413 jdk9-b80
--- a/hotspot/.hgtags Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/.hgtags Tue Sep 08 14:40:44 2015 -0700
@@ -482,3 +482,4 @@
e66c3813789debfc06f206afde1bf7a84cb08451 jdk9-b77
20dc06b04fe5ec373879414d60ef82ac70faef98 jdk9-b78
e9e63d93bbfe2c6c23447e2c1f5cc71c98671cba jdk9-b79
+8e8377739c06b99b9011c003c77e0bef84c91e09 jdk9-b80
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Address.java Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/Address.java Tue Sep 08 14:40:44 2015 -0700
@@ -209,4 +209,7 @@
returns the result as an Address. Returns null if the result was
zero. */
public Address xorWithMask(long mask) throws UnsupportedOperationException;
+
+ // return address as long integer.
+ public long asLongValue();
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdAddress.java Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdAddress.java Tue Sep 08 14:40:44 2015 -0700
@@ -288,7 +288,7 @@
return new BsdAddress(debugger, value);
}
-
+ public long asLongValue() { return addr; }
//--------------------------------------------------------------------------------
// Internals only below this point
//
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/dummy/DummyAddress.java Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/dummy/DummyAddress.java Tue Sep 08 14:40:44 2015 -0700
@@ -275,6 +275,7 @@
return new DummyAddress(debugger, value);
}
+ public long asLongValue() { return addr; }
//--------------------------------------------------------------------------------
// Internals only below this point
//
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxAddress.java Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxAddress.java Tue Sep 08 14:40:44 2015 -0700
@@ -288,6 +288,7 @@
return new LinuxAddress(debugger, value);
}
+ public long asLongValue() { return addr; }
//--------------------------------------------------------------------------------
// Internals only below this point
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcAddress.java Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcAddress.java Tue Sep 08 14:40:44 2015 -0700
@@ -283,7 +283,7 @@
return new ProcAddress(debugger, value);
}
-
+ public long asLongValue() { return addr; }
//--------------------------------------------------------------------------------
// Internals only below this point
//
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteAddress.java Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteAddress.java Tue Sep 08 14:40:44 2015 -0700
@@ -281,7 +281,7 @@
return new RemoteAddress(debugger, value);
}
-
+ public long asLongValue() { return addr; }
//--------------------------------------------------------------------------------
// Internals only below this point
//
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgAddress.java Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgAddress.java Tue Sep 08 14:40:44 2015 -0700
@@ -292,6 +292,7 @@
return new WindbgAddress(debugger, value);
}
+ public long asLongValue() { return addr; }
//--------------------------------------------------------------------------------
// Internals only below this point
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Symbol.java Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Symbol.java Tue Sep 08 14:40:44 2015 -0700
@@ -80,10 +80,19 @@
public byte getByteAt(long index) {
return addr.getJByteAt(baseOffset + index);
}
-
+ // _identity_hash is a short
private static CIntegerField idHash;
- public int identityHash() { return (int)idHash.getValue(this.addr); }
+ public int identityHash() {
+ long addr_value = getAddress().asLongValue();
+ int addr_bits = (int)(addr_value >> (VM.getVM().getLogMinObjAlignmentInBytes() + 3));
+ int length = (int)getLength();
+ int byte0 = getByteAt(0);
+ int byte1 = getByteAt(1);
+ int id_hash = (int)(0xffff & idHash.getValue(this.addr));
+ return id_hash |
+ ((addr_bits ^ (length << 8) ^ ((byte0 << 8) | byte1)) << 16);
+ }
public boolean equals(byte[] modUTF8Chars) {
int l = (int) getLength();
--- a/hotspot/src/cpu/aarch64/vm/aarch64.ad Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad Tue Sep 08 14:40:44 2015 -0700
@@ -1033,27 +1033,39 @@
};
// graph traversal helpers
- MemBarNode *has_parent_membar(const Node *n,
- ProjNode *&ctl, ProjNode *&mem);
- MemBarNode *has_child_membar(const MemBarNode *n,
- ProjNode *&ctl, ProjNode *&mem);
+
+ MemBarNode *parent_membar(const Node *n);
+ MemBarNode *child_membar(const MemBarNode *n);
+ bool leading_membar(const MemBarNode *barrier);
+
+ bool is_card_mark_membar(const MemBarNode *barrier);
+
+ MemBarNode *leading_to_normal(MemBarNode *leading);
+ MemBarNode *normal_to_leading(const MemBarNode *barrier);
+ MemBarNode *card_mark_to_trailing(const MemBarNode *barrier);
+ MemBarNode *trailing_to_card_mark(const MemBarNode *trailing);
+ MemBarNode *trailing_to_leading(const MemBarNode *trailing);
// predicates controlling emit of ldr<x>/ldar<x> and associated dmb
+
bool unnecessary_acquire(const Node *barrier);
bool needs_acquiring_load(const Node *load);
// predicates controlling emit of str<x>/stlr<x> and associated dmbs
+
bool unnecessary_release(const Node *barrier);
bool unnecessary_volatile(const Node *barrier);
bool needs_releasing_store(const Node *store);
- // Use barrier instructions for unsafe volatile gets rather than
- // trying to identify an exact signature for them
- const bool UseBarriersForUnsafeVolatileGet = false;
+ // predicate controlling translation of StoreCM
+ bool unnecessary_storestore(const Node *storecm);
%}
source %{
+ // Optimizaton of volatile gets and puts
+ // -------------------------------------
+ //
// AArch64 has ldar<x> and stlr<x> instructions which we can safely
// use to implement volatile reads and writes. For a volatile read
// we simply need
@@ -1102,15 +1114,19 @@
// A volatile write is translated to the node sequence
//
// MemBarRelease
- // StoreX[mo_release]
+ // StoreX[mo_release] {CardMark}-optional
// MemBarVolatile
//
// n.b. the above node patterns are generated with a strict
// 'signature' configuration of input and output dependencies (see
- // the predicates below for exact details). The two signatures are
- // unique to translated volatile reads/stores -- they will not
- // appear as a result of any other bytecode translation or inlining
- // nor as a consequence of optimizing transforms.
+ // the predicates below for exact details). The card mark may be as
+ // simple as a few extra nodes or, in a few GC configurations, may
+ // include more complex control flow between the leading and
+ // trailing memory barriers. However, whatever the card mark
+ // configuration these signatures are unique to translated volatile
+ // reads/stores -- they will not appear as a result of any other
+ // bytecode translation or inlining nor as a consequence of
+ // optimizing transforms.
//
// We also want to catch inlined unsafe volatile gets and puts and
// be able to implement them using either ldar<x>/stlr<x> or some
@@ -1122,7 +1138,7 @@
//
// MemBarRelease
// MemBarCPUOrder
- // StoreX[mo_release]
+ // StoreX[mo_release] {CardMark}-optional
// MemBarVolatile
//
// n.b. as an aside, the cpuorder membar is not itself subject to
@@ -1130,7 +1146,7 @@
// predicates need to detect its presence in order to correctly
// select the desired adlc rules.
//
- // Inlined unsafe volatiles gets manifest as a somewhat different
+ // Inlined unsafe volatile gets manifest as a somewhat different
// node sequence to a normal volatile get
//
// MemBarCPUOrder
@@ -1173,33 +1189,22 @@
// n.b. the translation rules below which rely on detection of the
// volatile signatures and insert ldar<x> or stlr<x> are failsafe.
// If we see anything other than the signature configurations we
- // always just translate the loads and stors to ldr<x> and str<x>
+ // always just translate the loads and stores to ldr<x> and str<x>
// and translate acquire, release and volatile membars to the
// relevant dmb instructions.
//
- // n.b.b as a case in point for the above comment, the current
- // predicates don't detect the precise signature for certain types
- // of volatile object stores (where the heap_base input type is not
- // known at compile-time to be non-NULL). In those cases the
- // MemBarRelease and MemBarVolatile bracket an if-then-else sequence
- // with a store in each branch (we need a different store depending
- // on whether heap_base is actually NULL). In such a case we will
- // just plant a dmb both before and after the branch/merge. The
- // predicate could (and probably should) be fixed later to also
- // detect this case.
-
- // graph traversal helpers
+
+ // graph traversal helpers used for volatile put/get optimization
+
+ // 1) general purpose helpers
// if node n is linked to a parent MemBarNode by an intervening
- // Control or Memory ProjNode return the MemBarNode otherwise return
+ // Control and Memory ProjNode return the MemBarNode otherwise return
// NULL.
//
// n may only be a Load or a MemBar.
- //
- // The ProjNode* references c and m are used to return the relevant
- // nodes.
-
- MemBarNode *has_parent_membar(const Node *n, ProjNode *&c, ProjNode *&m)
+
+ MemBarNode *parent_membar(const Node *n)
{
Node *ctl = NULL;
Node *mem = NULL;
@@ -1218,15 +1223,11 @@
if (!ctl || !mem || !ctl->is_Proj() || !mem->is_Proj())
return NULL;
- c = ctl->as_Proj();
-
membar = ctl->lookup(0);
if (!membar || !membar->is_MemBar())
return NULL;
- m = mem->as_Proj();
-
if (mem->lookup(0) != membar)
return NULL;
@@ -1235,12 +1236,8 @@
// if n is linked to a child MemBarNode by intervening Control and
// Memory ProjNodes return the MemBarNode otherwise return NULL.
- //
- // The ProjNode** arguments c and m are used to return pointers to
- // the relevant nodes. A null argument means don't don't return a
- // value.
-
- MemBarNode *has_child_membar(const MemBarNode *n, ProjNode *&c, ProjNode *&m)
+
+ MemBarNode *child_membar(const MemBarNode *n)
{
ProjNode *ctl = n->proj_out(TypeFunc::Control);
ProjNode *mem = n->proj_out(TypeFunc::Memory);
@@ -1249,9 +1246,6 @@
if (! ctl || ! mem)
return NULL;
- c = ctl;
- m = mem;
-
MemBarNode *child = NULL;
Node *x;
@@ -1279,9 +1273,838 @@
return NULL;
}
+ // helper predicate use to filter candidates for a leading memory
+ // barrier
+ //
+ // returns true if barrier is a MemBarRelease or a MemBarCPUOrder
+ // whose Ctl and Mem feeds come from a MemBarRelease otherwise false
+
+ bool leading_membar(const MemBarNode *barrier)
+ {
+ int opcode = barrier->Opcode();
+ // if this is a release membar we are ok
+ if (opcode == Op_MemBarRelease)
+ return true;
+ // if its a cpuorder membar . . .
+ if (opcode != Op_MemBarCPUOrder)
+ return false;
+ // then the parent has to be a release membar
+ MemBarNode *parent = parent_membar(barrier);
+ if (!parent)
+ return false;
+ opcode = parent->Opcode();
+ return opcode == Op_MemBarRelease;
+ }
+
+ // 2) card mark detection helper
+
+ // helper predicate which can be used to detect a volatile membar
+ // introduced as part of a conditional card mark sequence either by
+ // G1 or by CMS when UseCondCardMark is true.
+ //
+ // membar can be definitively determined to be part of a card mark
+ // sequence if and only if all the following hold
+ //
+ // i) it is a MemBarVolatile
+ //
+ // ii) either UseG1GC or (UseConcMarkSweepGC && UseCondCardMark) is
+ // true
+ //
+ // iii) the node's Mem projection feeds a StoreCM node.
+
+ bool is_card_mark_membar(const MemBarNode *barrier)
+ {
+ if (!UseG1GC && !(UseConcMarkSweepGC && UseCondCardMark))
+ return false;
+
+ if (barrier->Opcode() != Op_MemBarVolatile)
+ return false;
+
+ ProjNode *mem = barrier->proj_out(TypeFunc::Memory);
+
+ for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax ; i++) {
+ Node *y = mem->fast_out(i);
+ if (y->Opcode() == Op_StoreCM) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ // 3) helper predicates to traverse volatile put graphs which may
+ // contain GC barrier subgraphs
+
+ // Preamble
+ // --------
+ //
+ // for volatile writes we can omit generating barriers and employ a
+ // releasing store when we see a node sequence sequence with a
+ // leading MemBarRelease and a trailing MemBarVolatile as follows
+ //
+ // MemBarRelease
+ // { || } -- optional
+ // {MemBarCPUOrder}
+ // || \\
+ // || StoreX[mo_release]
+ // | \ /
+ // | MergeMem
+ // | /
+ // MemBarVolatile
+ //
+ // where
+ // || and \\ represent Ctl and Mem feeds via Proj nodes
+ // | \ and / indicate further routing of the Ctl and Mem feeds
+ //
+ // this is the graph we see for non-object stores. however, for a
+ // volatile Object store (StoreN/P) we may see other nodes below the
+ // leading membar because of the need for a GC pre- or post-write
+ // barrier.
+ //
+ // with most GC configurations we with see this simple variant which
+ // includes a post-write barrier card mark.
+ //
+ // MemBarRelease______________________________
+ // || \\ Ctl \ \\
+ // || StoreN/P[mo_release] CastP2X StoreB/CM
+ // | \ / . . . /
+ // | MergeMem
+ // | /
+ // || /
+ // MemBarVolatile
+ //
+ // i.e. the leading membar feeds Ctl to a CastP2X (which converts
+ // the object address to an int used to compute the card offset) and
+ // Ctl+Mem to a StoreB node (which does the actual card mark).
+ //
+ // n.b. a StoreCM node will only appear in this configuration when
+ // using CMS. StoreCM differs from a normal card mark write (StoreB)
+ // because it implies a requirement to order visibility of the card
+ // mark (StoreCM) relative to the object put (StoreP/N) using a
+ // StoreStore memory barrier (arguably this ought to be represented
+ // explicitly in the ideal graph but that is not how it works). This
+ // ordering is required for both non-volatile and volatile
+ // puts. Normally that means we need to translate a StoreCM using
+ // the sequence
+ //
+ // dmb ishst
+ // stlrb
+ //
+ // However, in the case of a volatile put if we can recognise this
+ // configuration and plant an stlr for the object write then we can
+ // omit the dmb and just plant an strb since visibility of the stlr
+ // is ordered before visibility of subsequent stores. StoreCM nodes
+ // also arise when using G1 or using CMS with conditional card
+ // marking. In these cases (as we shall see) we don't need to insert
+ // the dmb when translating StoreCM because there is already an
+ // intervening StoreLoad barrier between it and the StoreP/N.
+ //
+ // It is also possible to perform the card mark conditionally on it
+ // currently being unmarked in which case the volatile put graph
+ // will look slightly different
+ //
+ // MemBarRelease
+ // MemBarCPUOrder___________________________________________
+ // || \\ Ctl \ Ctl \ \\ Mem \
+ // || StoreN/P[mo_release] CastP2X If LoadB |
+ // | \ / \ |
+ // | MergeMem . . . StoreB
+ // | / /
+ // || /
+ // MemBarVolatile
+ //
+ // It is worth noting at this stage that both the above
+ // configurations can be uniquely identified by checking that the
+ // memory flow includes the following subgraph:
+ //
+ // MemBarRelease
+ // MemBarCPUOrder
+ // | \ . . .
+ // | StoreX[mo_release] . . .
+ // | /
+ // MergeMem
+ // |
+ // MemBarVolatile
+ //
+ // This is referred to as a *normal* subgraph. It can easily be
+ // detected starting from any candidate MemBarRelease,
+ // StoreX[mo_release] or MemBarVolatile.
+ //
+ // the code below uses two helper predicates, leading_to_normal and
+ // normal_to_leading to identify this configuration, one validating
+ // the layout starting from the top membar and searching down and
+ // the other validating the layout starting from the lower membar
+ // and searching up.
+ //
+ // There are two special case GC configurations when a normal graph
+ // may not be generated: when using G1 (which always employs a
+ // conditional card mark); and when using CMS with conditional card
+ // marking configured. These GCs are both concurrent rather than
+ // stop-the world GCs. So they introduce extra Ctl+Mem flow into the
+ // graph between the leading and trailing membar nodes, in
+ // particular enforcing stronger memory serialisation beween the
+ // object put and the corresponding conditional card mark. CMS
+ // employs a post-write GC barrier while G1 employs both a pre- and
+ // post-write GC barrier. Of course the extra nodes may be absent --
+ // they are only inserted for object puts. This significantly
+ // complicates the task of identifying whether a MemBarRelease,
+ // StoreX[mo_release] or MemBarVolatile forms part of a volatile put
+ // when using these GC configurations (see below).
+ //
+ // In both cases the post-write subtree includes an auxiliary
+ // MemBarVolatile (StoreLoad barrier) separating the object put and
+ // the read of the corresponding card. This poses two additional
+ // problems.
+ //
+ // Firstly, a card mark MemBarVolatile needs to be distinguished
+ // from a normal trailing MemBarVolatile. Resolving this first
+ // problem is straightforward: a card mark MemBarVolatile always
+ // projects a Mem feed to a StoreCM node and that is a unique marker
+ //
+ // MemBarVolatile (card mark)
+ // C | \ . . .
+ // | StoreCM . . .
+ // . . .
+ //
+ // The second problem is how the code generator is to translate the
+ // card mark barrier? It always needs to be translated to a "dmb
+ // ish" instruction whether or not it occurs as part of a volatile
+ // put. A StoreLoad barrier is needed after the object put to ensure
+ // i) visibility to GC threads of the object put and ii) visibility
+ // to the mutator thread of any card clearing write by a GC
+ // thread. Clearly a normal store (str) will not guarantee this
+ // ordering but neither will a releasing store (stlr). The latter
+ // guarantees that the object put is visible but does not guarantee
+ // that writes by other threads have also been observed.
+ //
+ // So, returning to the task of translating the object put and the
+ // leading/trailing membar nodes: what do the non-normal node graph
+ // look like for these 2 special cases? and how can we determine the
+ // status of a MemBarRelease, StoreX[mo_release] or MemBarVolatile
+ // in both normal and non-normal cases?
+ //
+ // A CMS GC post-barrier wraps its card write (StoreCM) inside an If
+ // which selects conditonal execution based on the value loaded
+ // (LoadB) from the card. Ctl and Mem are fed to the If via an
+ // intervening StoreLoad barrier (MemBarVolatile).
+ //
+ // So, with CMS we may see a node graph which looks like this
+ //
+ // MemBarRelease
+ // MemBarCPUOrder_(leading)__________________
+ // C | M \ \\ C \
+ // | \ StoreN/P[mo_release] CastP2X
+ // | Bot \ /
+ // | MergeMem
+ // | /
+ // MemBarVolatile (card mark)
+ // C | || M |
+ // | LoadB |
+ // | | |
+ // | Cmp |\
+ // | / | \
+ // If | \
+ // | \ | \
+ // IfFalse IfTrue | \
+ // \ / \ | \
+ // \ / StoreCM |
+ // \ / | |
+ // Region . . . |
+ // | \ /
+ // | . . . \ / Bot
+ // | MergeMem
+ // | |
+ // MemBarVolatile (trailing)
+ //
+ // The first MergeMem merges the AliasIdxBot Mem slice from the
+ // leading membar and the oopptr Mem slice from the Store into the
+ // card mark membar. The trailing MergeMem merges the AliasIdxBot
+ // Mem slice from the card mark membar and the AliasIdxRaw slice
+ // from the StoreCM into the trailing membar (n.b. the latter
+ // proceeds via a Phi associated with the If region).
+ //
+ // G1 is quite a lot more complicated. The nodes inserted on behalf
+ // of G1 may comprise: a pre-write graph which adds the old value to
+ // the SATB queue; the releasing store itself; and, finally, a
+ // post-write graph which performs a card mark.
+ //
+ // The pre-write graph may be omitted, but only when the put is
+ // writing to a newly allocated (young gen) object and then only if
+ // there is a direct memory chain to the Initialize node for the
+ // object allocation. This will not happen for a volatile put since
+ // any memory chain passes through the leading membar.
+ //
+ // The pre-write graph includes a series of 3 If tests. The outermost
+ // If tests whether SATB is enabled (no else case). The next If tests
+ // whether the old value is non-NULL (no else case). The third tests
+ // whether the SATB queue index is > 0, if so updating the queue. The
+ // else case for this third If calls out to the runtime to allocate a
+ // new queue buffer.
+ //
+ // So with G1 the pre-write and releasing store subgraph looks like
+ // this (the nested Ifs are omitted).
+ //
+ // MemBarRelease (leading)____________
+ // C | || M \ M \ M \ M \ . . .
+ // | LoadB \ LoadL LoadN \
+ // | / \ \
+ // If |\ \
+ // | \ | \ \
+ // IfFalse IfTrue | \ \
+ // | | | \ |
+ // | If | /\ |
+ // | | \ |
+ // | \ |
+ // | . . . \ |
+ // | / | / | |
+ // Region Phi[M] | |
+ // | \ | | |
+ // | \_____ | ___ | |
+ // C | C \ | C \ M | |
+ // | CastP2X | StoreN/P[mo_release] |
+ // | | | |
+ // C | M | M | M |
+ // \ | | /
+ // . . .
+ // (post write subtree elided)
+ // . . .
+ // C \ M /
+ // MemBarVolatile (trailing)
+ //
+ // n.b. the LoadB in this subgraph is not the card read -- it's a
+ // read of the SATB queue active flag.
+ //
+ // The G1 post-write subtree is also optional, this time when the
+ // new value being written is either null or can be identified as a
+ // newly allocated (young gen) object with no intervening control
+ // flow. The latter cannot happen but the former may, in which case
+ // the card mark membar is omitted and the memory feeds from the
+ // leading membar and the StoreN/P are merged direct into the
+ // trailing membar as per the normal subgraph. So, the only special
+ // case which arises is when the post-write subgraph is generated.
+ //
+ // The kernel of the post-write G1 subgraph is the card mark itself
+ // which includes a card mark memory barrier (MemBarVolatile), a
+ // card test (LoadB), and a conditional update (If feeding a
+ // StoreCM). These nodes are surrounded by a series of nested Ifs
+ // which try to avoid doing the card mark. The top level If skips if
+ // the object reference does not cross regions (i.e. it tests if
+ // (adr ^ val) >> log2(regsize) != 0) -- intra-region references
+ // need not be recorded. The next If, which skips on a NULL value,
+ // may be absent (it is not generated if the type of value is >=
+ // OopPtr::NotNull). The 3rd If skips writes to young regions (by
+ // checking if card_val != young). n.b. although this test requires
+ // a pre-read of the card it can safely be done before the StoreLoad
+ // barrier. However that does not bypass the need to reread the card
+ // after the barrier.
+ //
+ // (pre-write subtree elided)
+ // . . . . . . . . . . . .
+ // C | M | M | M |
+ // Region Phi[M] StoreN |
+ // | / \ | |
+ // / \_______ / \ | |
+ // C / C \ . . . \ | |
+ // If CastP2X . . . | | |
+ // / \ | | |
+ // / \ | | |
+ // IfFalse IfTrue | | |
+ // | | | | /|
+ // | If | | / |
+ // | / \ | | / |
+ // | / \ \ | / |
+ // | IfFalse IfTrue MergeMem |
+ // | . . . / \ / |
+ // | / \ / |
+ // | IfFalse IfTrue / |
+ // | . . . | / |
+ // | If / |
+ // | / \ / |
+ // | / \ / |
+ // | IfFalse IfTrue / |
+ // | . . . | / |
+ // | \ / |
+ // | \ / |
+ // | MemBarVolatile__(card mark) |
+ // | || C | M \ M \ |
+ // | LoadB If | | |
+ // | / \ | | |
+ // | . . . | | |
+ // | \ | | /
+ // | StoreCM | /
+ // | . . . | /
+ // | _________/ /
+ // | / _____________/
+ // | . . . . . . | / /
+ // | | | / _________/
+ // | | Phi[M] / /
+ // | | | / /
+ // | | | / /
+ // | Region . . . Phi[M] _____/
+ // | / | /
+ // | | /
+ // | . . . . . . | /
+ // | / | /
+ // Region | | Phi[M]
+ // | | | / Bot
+ // \ MergeMem
+ // \ /
+ // MemBarVolatile
+ //
+ // As with CMS the initial MergeMem merges the AliasIdxBot Mem slice
+ // from the leading membar and the oopptr Mem slice from the Store
+ // into the card mark membar i.e. the memory flow to the card mark
+ // membar still looks like a normal graph.
+ //
+ // The trailing MergeMem merges an AliasIdxBot Mem slice with other
+ // Mem slices (from the StoreCM and other card mark queue stores).
+ // However in this case the AliasIdxBot Mem slice does not come
+ // direct from the card mark membar. It is merged through a series
+ // of Phi nodes. These are needed to merge the AliasIdxBot Mem flow
+ // from the leading membar with the Mem feed from the card mark
+ // membar. Each Phi corresponds to one of the Ifs which may skip
+ // around the card mark membar. So when the If implementing the NULL
+ // value check has been elided the total number of Phis is 2
+ // otherwise it is 3.
+ //
+ // So, the upshot is that in all cases the volatile put graph will
+ // include a *normal* memory subgraph betwen the leading membar and
+ // its child membar. When that child is not a card mark membar then
+ // it marks the end of a volatile put subgraph. If the child is a
+ // card mark membar then the normal subgraph will form part of a
+ // volatile put subgraph if and only if the child feeds an
+ // AliasIdxBot Mem feed to a trailing barrier via a MergeMem. That
+ // feed is either direct (for CMS) or via 2 or 3 Phi nodes merging
+ // the leading barrier memory flow (for G1).
+ //
+ // The predicates controlling generation of instructions for store
+ // and barrier nodes employ a few simple helper functions (described
+ // below) which identify the presence or absence of these subgraph
+ // configurations and provide a means of traversing from one node in
+ // the subgraph to another.
+
+ // leading_to_normal
+ //
+ //graph traversal helper which detects the normal case Mem feed
+ // from a release membar (or, optionally, its cpuorder child) to a
+ // dependent volatile membar i.e. it ensures that the following Mem
+ // flow subgraph is present.
+ //
+ // MemBarRelease
+ // MemBarCPUOrder
+ // | \ . . .
+ // | StoreN/P[mo_release] . . .
+ // | /
+ // MergeMem
+ // |
+ // MemBarVolatile
+ //
+ // if the correct configuration is present returns the volatile
+ // membar otherwise NULL.
+ //
+ // the input membar is expected to be either a cpuorder membar or a
+ // release membar. in the latter case it should not have a cpu membar
+ // child.
+ //
+ // the returned membar may be a card mark membar rather than a
+ // trailing membar.
+
+ MemBarNode *leading_to_normal(MemBarNode *leading)
+ {
+ assert((leading->Opcode() == Op_MemBarRelease ||
+ leading->Opcode() == Op_MemBarCPUOrder),
+ "expecting a volatile or cpuroder membar!");
+
+ // check the mem flow
+ ProjNode *mem = leading->proj_out(TypeFunc::Memory);
+
+ if (!mem)
+ return NULL;
+
+ Node *x = NULL;
+ StoreNode * st = NULL;
+ MergeMemNode *mm = NULL;
+
+ for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) {
+ x = mem->fast_out(i);
+ if (x->is_MergeMem()) {
+ if (mm != NULL)
+ return NULL;
+ // two merge mems is one too many
+ mm = x->as_MergeMem();
+ } else if (x->is_Store() && x->as_Store()->is_release() && x->Opcode() != Op_StoreCM) {
+ // two releasing stores is one too many
+ if (st != NULL)
+ return NULL;
+ st = x->as_Store();
+ }
+ }
+
+ if (!mm || !st)
+ return NULL;
+
+ bool found = false;
+ // ensure the store feeds the merge
+ for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) {
+ if (st->fast_out(i) == mm) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return NULL;
+
+ MemBarNode *mbvol = NULL;
+ // ensure the merge feeds a volatile membar
+ for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) {
+ x = mm->fast_out(i);
+ if (x->is_MemBar() && x->Opcode() == Op_MemBarVolatile) {
+ mbvol = x->as_MemBar();
+ break;
+ }
+ }
+
+ return mbvol;
+ }
+
+ // normal_to_leading
+ //
+ // graph traversal helper which detects the normal case Mem feed
+ // from either a card mark or a trailing membar to a preceding
+ // release membar (optionally its cpuorder child) i.e. it ensures
+ // that the following Mem flow subgraph is present.
+ //
+ // MemBarRelease
+ // MemBarCPUOrder {leading}
+ // | \ . . .
+ // | StoreN/P[mo_release] . . .
+ // | /
+ // MergeMem
+ // |
+ // MemBarVolatile
+ //
+ // this predicate checks for the same flow as the previous predicate
+ // but starting from the bottom rather than the top.
+ //
+ // if the configuration is present returns the cpuorder member for
+ // preference or when absent the release membar otherwise NULL.
+ //
+ // n.b. the input membar is expected to be a MemBarVolatile but
+ // need not be a card mark membar.
+
+ MemBarNode *normal_to_leading(const MemBarNode *barrier)
+ {
+ // input must be a volatile membar
+ assert(barrier->Opcode() == Op_MemBarVolatile, "expecting a volatile membar");
+ Node *x;
+
+ // the Mem feed to the membar should be a merge
+ x = barrier->in(TypeFunc::Memory);
+ if (!x->is_MergeMem())
+ return NULL;
+
+ MergeMemNode *mm = x->as_MergeMem();
+
+ // the AliasIdxBot slice should be another MemBar projection
+ x = mm->in(Compile::AliasIdxBot);
+ // ensure this is a non control projection
+ if (!x->is_Proj() || x->is_CFG())
+ return NULL;
+ // if it is fed by a membar that's the one we want
+ x = x->in(0);
+
+ if (!x->is_MemBar())
+ return NULL;
+
+ MemBarNode *leading = x->as_MemBar();
+ // reject invalid candidates
+ if (!leading_membar(leading))
+ return NULL;
+
+ // ok, we have a leading ReleaseMembar, now for the sanity clauses
+
+ // the leading membar must feed Mem to a releasing store
+ ProjNode *mem = leading->proj_out(TypeFunc::Memory);
+ StoreNode *st = NULL;
+ for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) {
+ x = mem->fast_out(i);
+ if (x->is_Store() && x->as_Store()->is_release() && x->Opcode() != Op_StoreCM) {
+ st = x->as_Store();
+ break;
+ }
+ }
+ if (st == NULL)
+ return NULL;
+
+ // the releasing store has to feed the same merge
+ for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) {
+ if (st->fast_out(i) == mm)
+ return leading;
+ }
+
+ return NULL;
+ }
+
+ // card_mark_to_trailing
+ //
+ // graph traversal helper which detects extra, non-normal Mem feed
+ // from a card mark volatile membar to a trailing membar i.e. it
+ // ensures that one of the following three GC post-write Mem flow
+ // subgraphs is present.
+ //
+ // 1)
+ // . . .
+ // |
+ // MemBarVolatile (card mark)
+ // | |
+ // | StoreCM
+ // | |
+ // | . . .
+ // Bot | /
+ // MergeMem
+ // |
+ // MemBarVolatile (trailing)
+ //
+ //
+ // 2)
+ // MemBarRelease/CPUOrder (leading)
+ // |
+ // |
+ // |\ . . .
+ // | \ |
+ // | \ MemBarVolatile (card mark)
+ // | \ | |
+ // \ \ | StoreCM . . .
+ // \ \ |
+ // \ Phi
+ // \ /
+ // Phi . . .
+ // Bot | /
+ // MergeMem
+ // |
+ // MemBarVolatile (trailing)
+ //
+ // 3)
+ // MemBarRelease/CPUOrder (leading)
+ // |
+ // |\
+ // | \
+ // | \ . . .
+ // | \ |
+ // |\ \ MemBarVolatile (card mark)
+ // | \ \ | |
+ // | \ \ | StoreCM . . .
+ // | \ \ |
+ // \ \ Phi
+ // \ \ /
+ // \ Phi
+ // \ /
+ // Phi . . .
+ // Bot | /
+ // MergeMem
+ // |
+ // MemBarVolatile (trailing)
+ //
+ // configuration 1 is only valid if UseConcMarkSweepGC &&
+ // UseCondCardMark
+ //
+ // configurations 2 and 3 are only valid if UseG1GC.
+ //
+ // if a valid configuration is present returns the trailing membar
+ // otherwise NULL.
+ //
+ // n.b. the supplied membar is expected to be a card mark
+ // MemBarVolatile i.e. the caller must ensure the input node has the
+ // correct operand and feeds Mem to a StoreCM node
+
+ MemBarNode *card_mark_to_trailing(const MemBarNode *barrier)
+ {
+ // input must be a card mark volatile membar
+ assert(is_card_mark_membar(barrier), "expecting a card mark membar");
+
+ Node *feed = barrier->proj_out(TypeFunc::Memory);
+ Node *x;
+ MergeMemNode *mm = NULL;
+
+ const int MAX_PHIS = 3; // max phis we will search through
+ int phicount = 0; // current search count
+
+ bool retry_feed = true;
+ while (retry_feed) {
+ // see if we have a direct MergeMem feed
+ for (DUIterator_Fast imax, i = feed->fast_outs(imax); i < imax; i++) {
+ x = feed->fast_out(i);
+ // the correct Phi will be merging a Bot memory slice
+ if (x->is_MergeMem()) {
+ mm = x->as_MergeMem();
+ break;
+ }
+ }
+ if (mm) {
+ retry_feed = false;
+ } else if (UseG1GC & phicount++ < MAX_PHIS) {
+ // the barrier may feed indirectly via one or two Phi nodes
+ PhiNode *phi = NULL;
+ for (DUIterator_Fast imax, i = feed->fast_outs(imax); i < imax; i++) {
+ x = feed->fast_out(i);
+ // the correct Phi will be merging a Bot memory slice
+ if (x->is_Phi() && x->adr_type() == TypePtr::BOTTOM) {
+ phi = x->as_Phi();
+ break;
+ }
+ }
+ if (!phi)
+ return NULL;
+ // look for another merge below this phi
+ feed = phi;
+ } else {
+ // couldn't find a merge
+ return NULL;
+ }
+ }
+
+ // sanity check this feed turns up as the expected slice
+ assert(mm->as_MergeMem()->in(Compile::AliasIdxBot) == feed, "expecting membar to feed AliasIdxBot slice to Merge");
+
+ MemBarNode *trailing = NULL;
+ // be sure we have a volatile membar below the merge
+ for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) {
+ x = mm->fast_out(i);
+ if (x->is_MemBar() && x->Opcode() == Op_MemBarVolatile) {
+ trailing = x->as_MemBar();
+ break;
+ }
+ }
+
+ return trailing;
+ }
+
+ // trailing_to_card_mark
+ //
+ // graph traversal helper which detects extra, non-normal Mem feed
+ // from a trailing membar to a preceding card mark volatile membar
+ // i.e. it identifies whether one of the three possible extra GC
+ // post-write Mem flow subgraphs is present
+ //
+ // this predicate checks for the same flow as the previous predicate
+ // but starting from the bottom rather than the top.
+ //
+ // if the configurationis present returns the card mark membar
+ // otherwise NULL
+
+ MemBarNode *trailing_to_card_mark(const MemBarNode *trailing)
+ {
+ assert(!is_card_mark_membar(trailing), "not expecting a card mark membar");
+
+ Node *x = trailing->in(TypeFunc::Memory);
+ // the Mem feed to the membar should be a merge
+ if (!x->is_MergeMem())
+ return NULL;
+
+ MergeMemNode *mm = x->as_MergeMem();
+
+ x = mm->in(Compile::AliasIdxBot);
+ // with G1 we may possibly see a Phi or two before we see a Memory
+ // Proj from the card mark membar
+
+ const int MAX_PHIS = 3; // max phis we will search through
+ int phicount = 0; // current search count
+
+ bool retry_feed = !x->is_Proj();
+
+ while (retry_feed) {
+ if (UseG1GC && x->is_Phi() && phicount++ < MAX_PHIS) {
+ PhiNode *phi = x->as_Phi();
+ ProjNode *proj = NULL;
+ PhiNode *nextphi = NULL;
+ bool found_leading = false;
+ for (uint i = 1; i < phi->req(); i++) {
+ x = phi->in(i);
+ if (x->is_Phi()) {
+ nextphi = x->as_Phi();
+ } else if (x->is_Proj()) {
+ int opcode = x->in(0)->Opcode();
+ if (opcode == Op_MemBarVolatile) {
+ proj = x->as_Proj();
+ } else if (opcode == Op_MemBarRelease ||
+ opcode == Op_MemBarCPUOrder) {
+ // probably a leading membar
+ found_leading = true;
+ }
+ }
+ }
+ // if we found a correct looking proj then retry from there
+ // otherwise we must see a leading and a phi or this the
+ // wrong config
+ if (proj != NULL) {
+ x = proj;
+ retry_feed = false;
+ } else if (found_leading && nextphi != NULL) {
+ // retry from this phi to check phi2
+ x = nextphi;
+ } else {
+ // not what we were looking for
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+ }
+ // the proj has to come from the card mark membar
+ x = x->in(0);
+ if (!x->is_MemBar())
+ return NULL;
+
+ MemBarNode *card_mark_membar = x->as_MemBar();
+
+ if (!is_card_mark_membar(card_mark_membar))
+ return NULL;
+
+ return card_mark_membar;
+ }
+
+ // trailing_to_leading
+ //
+ // graph traversal helper which checks the Mem flow up the graph
+ // from a (non-card mark) volatile membar attempting to locate and
+ // return an associated leading membar. it first looks for a
+ // subgraph in the normal configuration (relying on helper
+ // normal_to_leading). failing that it then looks for one of the
+ // possible post-write card mark subgraphs linking the trailing node
+ // to a the card mark membar (relying on helper
+ // trailing_to_card_mark), and then checks that the card mark membar
+ // is fed by a leading membar (once again relying on auxiliary
+ // predicate normal_to_leading).
+ //
+ // if the configuration is valid returns the cpuorder member for
+ // preference or when absent the release membar otherwise NULL.
+ //
+ // n.b. the input membar is expected to be a volatile membar but
+ // must *not* be a card mark membar.
+
+ MemBarNode *trailing_to_leading(const MemBarNode *trailing)
+ {
+ assert(!is_card_mark_membar(trailing), "not expecting a card mark membar");
+
+ MemBarNode *leading = normal_to_leading(trailing);
+
+ if (leading)
+ return leading;
+
+ MemBarNode *card_mark_membar = trailing_to_card_mark(trailing);
+
+ if (!card_mark_membar)
+ return NULL;
+
+ return normal_to_leading(card_mark_membar);
+ }
+
// predicates controlling emit of ldr<x>/ldar<x> and associated dmb
-bool unnecessary_acquire(const Node *barrier) {
+bool unnecessary_acquire(const Node *barrier)
+{
// assert barrier->is_MemBar();
if (UseBarriersForVolatile)
// we need to plant a dmb
@@ -1323,13 +2146,11 @@
return (x->is_Load() && x->as_Load()->is_acquire());
}
- // only continue if we want to try to match unsafe volatile gets
- if (UseBarriersForUnsafeVolatileGet)
- return false;
+ // now check for an unsafe volatile get
// need to check for
//
- // MemBarCPUOrder
+ // MemBarCPUOrder
// || \\
// MemBarAcquire* LoadX[mo_acquire]
// ||
@@ -1341,9 +2162,13 @@
// check for a parent MemBarCPUOrder
ProjNode *ctl;
ProjNode *mem;
- MemBarNode *parent = has_parent_membar(barrier, ctl, mem);
+ MemBarNode *parent = parent_membar(barrier);
if (!parent || parent->Opcode() != Op_MemBarCPUOrder)
return false;
+ ctl = parent->proj_out(TypeFunc::Control);
+ mem = parent->proj_out(TypeFunc::Memory);
+ if (!ctl || !mem)
+ return false;
// ensure the proj nodes both feed a LoadX[mo_acquire]
LoadNode *ld = NULL;
for (DUIterator_Fast imax, i = ctl->fast_outs(imax); i < imax; i++) {
@@ -1369,7 +2194,7 @@
if (ld)
return false;
// check for a child cpuorder membar
- MemBarNode *child = has_child_membar(barrier->as_MemBar(), ctl, mem);
+ MemBarNode *child = child_membar(barrier->as_MemBar());
if (!child || child->Opcode() != Op_MemBarCPUOrder)
return false;
@@ -1422,9 +2247,7 @@
return true;
}
- // only continue if we want to try to match unsafe volatile gets
- if (UseBarriersForUnsafeVolatileGet)
- return false;
+ // now check for an unsafe volatile get
// check if Ctl and Proj feed comes from a MemBarCPUOrder
//
@@ -1435,22 +2258,20 @@
// MemBarCPUOrder
MemBarNode *membar;
- ProjNode *ctl;
- ProjNode *mem;
-
- membar = has_parent_membar(ld, ctl, mem);
+
+ membar = parent_membar(ld);
if (!membar || !membar->Opcode() == Op_MemBarCPUOrder)
return false;
// ensure that there is a CPUOrder->Acquire->CPUOrder membar chain
- membar = has_child_membar(membar, ctl, mem);
+ membar = child_membar(membar);
if (!membar || !membar->Opcode() == Op_MemBarAcquire)
return false;
- membar = has_child_membar(membar, ctl, mem);
+ membar = child_membar(membar);
if (!membar || !membar->Opcode() == Op_MemBarCPUOrder)
return false;
@@ -1458,194 +2279,81 @@
return true;
}
-bool unnecessary_release(const Node *n) {
+bool unnecessary_release(const Node *n)
+{
+ assert((n->is_MemBar() &&
+ n->Opcode() == Op_MemBarRelease),
+ "expecting a release membar");
+
+ if (UseBarriersForVolatile)
+ // we need to plant a dmb
+ return false;
+
+ // if there is a dependent CPUOrder barrier then use that as the
+ // leading
+
+ MemBarNode *barrier = n->as_MemBar();
+ // check for an intervening cpuorder membar
+ MemBarNode *b = child_membar(barrier);
+ if (b && b->Opcode() == Op_MemBarCPUOrder) {
+ // ok, so start the check from the dependent cpuorder barrier
+ barrier = b;
+ }
+
+ // must start with a normal feed
+ MemBarNode *child_barrier = leading_to_normal(barrier);
+
+ if (!child_barrier)
+ return false;
+
+ if (!is_card_mark_membar(child_barrier))
+ // this is the trailing membar and we are done
+ return true;
+
+ // must be sure this card mark feeds a trailing membar
+ MemBarNode *trailing = card_mark_to_trailing(child_barrier);
+ return (trailing != NULL);
+}
+
+bool unnecessary_volatile(const Node *n)
+{
// assert n->is_MemBar();
if (UseBarriersForVolatile)
// we need to plant a dmb
return false;
- // ok, so we can omit this release barrier if it has been inserted
- // as part of a volatile store sequence
- //
- // MemBarRelease
- // { || }
- // {MemBarCPUOrder} -- optional
- // || \\
- // || StoreX[mo_release]
- // | \ /
- // | MergeMem
- // | /
- // MemBarVolatile
- //
- // where
- // || and \\ represent Ctl and Mem feeds via Proj nodes
- // | \ and / indicate further routing of the Ctl and Mem feeds
- //
- // so we need to check that
- //
- // ia) the release membar (or its dependent cpuorder membar) feeds
- // control to a store node (via a Control project node)
- //
- // ii) the store is ordered release
- //
- // iii) the release membar (or its dependent cpuorder membar) feeds
- // control to a volatile membar (via the same Control project node)
- //
- // iv) the release membar feeds memory to a merge mem and to the
- // same store (both via a single Memory proj node)
- //
- // v) the store outputs to the merge mem
- //
- // vi) the merge mem outputs to the same volatile membar
- //
- // n.b. if this is an inlined unsafe node then the release membar
- // may feed its control and memory links via an intervening cpuorder
- // membar. this case can be dealt with when we check the release
- // membar projections. if they both feed a single cpuorder membar
- // node continue to make the same checks as above but with the
- // cpuorder membar substituted for the release membar. if they don't
- // both feed a cpuorder membar then the check fails.
- //
- // n.b.b. for an inlined unsafe store of an object in the case where
- // !TypePtr::NULL_PTR->higher_equal(type(heap_base_oop)) we may see
- // an embedded if then else where we expect the store. this is
- // needed to do the right type of store depending on whether
- // heap_base is NULL. We could check for that but for now we can
- // just take the hit of on inserting a redundant dmb for this
- // redundant volatile membar
-
- MemBarNode *barrier = n->as_MemBar();
- ProjNode *ctl;
- ProjNode *mem;
- // check for an intervening cpuorder membar
- MemBarNode *b = has_child_membar(barrier, ctl, mem);
- if (b && b->Opcode() == Op_MemBarCPUOrder) {
- // ok, so start form the dependent cpuorder barrier
- barrier = b;
- }
- // check the ctl and mem flow
- ctl = barrier->proj_out(TypeFunc::Control);
- mem = barrier->proj_out(TypeFunc::Memory);
-
- // the barrier needs to have both a Ctl and Mem projection
- if (! ctl || ! mem)
+ MemBarNode *mbvol = n->as_MemBar();
+
+ // first we check if this is part of a card mark. if so then we have
+ // to generate a StoreLoad barrier
+
+ if (is_card_mark_membar(mbvol))
+ return false;
+
+ // ok, if it's not a card mark then we still need to check if it is
+ // a trailing membar of a volatile put hgraph.
+
+ return (trailing_to_leading(mbvol) != NULL);
+}
+
+// predicates controlling emit of str<x>/stlr<x> and associated dmbs
+
+bool needs_releasing_store(const Node *n)
+{
+ // assert n->is_Store();
+ if (UseBarriersForVolatile)
+ // we use a normal store and dmb combination
return false;
- Node *x = NULL;
- Node *mbvol = NULL;
- StoreNode * st = NULL;
-
- // For a normal volatile write the Ctl ProjNode should have output
- // to a MemBarVolatile and a Store marked as releasing
- //
- // n.b. for an inlined unsafe store of an object in the case where
- // !TypePtr::NULL_PTR->higher_equal(type(heap_base_oop)) we may see
- // an embedded if then else where we expect the store. this is
- // needed to do the right type of store depending on whether
- // heap_base is NULL. We could check for that case too but for now
- // we can just take the hit of inserting a dmb and a non-volatile
- // store to implement the volatile store
-
- for (DUIterator_Fast imax, i = ctl->fast_outs(imax); i < imax; i++) {
- x = ctl->fast_out(i);
- if (x->is_MemBar() && x->Opcode() == Op_MemBarVolatile) {
- if (mbvol) {
- return false;
- }
- mbvol = x;
- } else if (x->is_Store()) {
- st = x->as_Store();
- if (! st->is_release()) {
- return false;
- }
- } else if (!x->is_Mach()) {
- // we may see mach nodes added during matching but nothing else
- return false;
- }
- }
-
- if (!mbvol || !st)
- return false;
-
- // the Mem ProjNode should output to a MergeMem and the same Store
- Node *mm = NULL;
- for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) {
- x = mem->fast_out(i);
- if (!mm && x->is_MergeMem()) {
- mm = x;
- } else if (x != st && !x->is_Mach()) {
- // we may see mach nodes added during matching but nothing else
- return false;
- }
- }
-
- if (!mm)
+ StoreNode *st = n->as_Store();
+
+ // the store must be marked as releasing
+ if (!st->is_release())
return false;
- // the MergeMem should output to the MemBarVolatile
- for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) {
- x = mm->fast_out(i);
- if (x != mbvol && !x->is_Mach()) {
- // we may see mach nodes added during matching but nothing else
- return false;
- }
- }
-
- return true;
-}
-
-bool unnecessary_volatile(const Node *n) {
- // assert n->is_MemBar();
- if (UseBarriersForVolatile)
- // we need to plant a dmb
- return false;
-
- // ok, so we can omit this volatile barrier if it has been inserted
- // as part of a volatile store sequence
- //
- // MemBarRelease
- // { || }
- // {MemBarCPUOrder} -- optional
- // || \\
- // || StoreX[mo_release]
- // | \ /
- // | MergeMem
- // | /
- // MemBarVolatile
- //
- // where
- // || and \\ represent Ctl and Mem feeds via Proj nodes
- // | \ and / indicate further routing of the Ctl and Mem feeds
- //
- // we need to check that
- //
- // i) the volatile membar gets its control feed from a release
- // membar (or its dependent cpuorder membar) via a Control project
- // node
- //
- // ii) the release membar (or its dependent cpuorder membar) also
- // feeds control to a store node via the same proj node
- //
- // iii) the store is ordered release
- //
- // iv) the release membar (or its dependent cpuorder membar) feeds
- // memory to a merge mem and to the same store (both via a single
- // Memory proj node)
- //
- // v) the store outputs to the merge mem
- //
- // vi) the merge mem outputs to the volatile membar
- //
- // n.b. for an inlined unsafe store of an object in the case where
- // !TypePtr::NULL_PTR->higher_equal(type(heap_base_oop)) we may see
- // an embedded if then else where we expect the store. this is
- // needed to do the right type of store depending on whether
- // heap_base is NULL. We could check for that but for now we can
- // just take the hit of on inserting a redundant dmb for this
- // redundant volatile membar
-
- MemBarNode *mbvol = n->as_MemBar();
- Node *x = n->lookup(TypeFunc::Control);
+ // the store must be fed by a membar
+
+ Node *x = st->lookup(StoreNode::Memory);
if (! x || !x->is_Proj())
return false;
@@ -1659,200 +2367,78 @@
MemBarNode *barrier = x->as_MemBar();
- // if the barrier is a release membar we have what we want. if it is
- // a cpuorder membar then we need to ensure that it is fed by a
- // release membar in which case we proceed to check the graph below
- // this cpuorder membar as the feed
-
- if (x->Opcode() != Op_MemBarRelease) {
- if (x->Opcode() != Op_MemBarCPUOrder)
- return false;
- ProjNode *ctl;
- ProjNode *mem;
- MemBarNode *b = has_parent_membar(x, ctl, mem);
- if (!b || !b->Opcode() == Op_MemBarRelease)
- return false;
- }
-
- ProjNode *ctl = barrier->proj_out(TypeFunc::Control);
- ProjNode *mem = barrier->proj_out(TypeFunc::Memory);
-
- // barrier needs to have both a Ctl and Mem projection
- // and we need to have reached it via the Ctl projection
- if (! ctl || ! mem || ctl != proj)
- return false;
-
- StoreNode * st = NULL;
-
- // The Ctl ProjNode should have output to a MemBarVolatile and
- // a Store marked as releasing
- for (DUIterator_Fast imax, i = ctl->fast_outs(imax); i < imax; i++) {
- x = ctl->fast_out(i);
- if (x->is_MemBar() && x->Opcode() == Op_MemBarVolatile) {
- if (x != mbvol) {
- return false;
- }
- } else if (x->is_Store()) {
- st = x->as_Store();
- if (! st->is_release()) {
- return false;
- }
- } else if (!x->is_Mach()){
- // we may see mach nodes added during matching but nothing else
- return false;
- }
- }
-
- if (!st)
- return false;
-
- // the Mem ProjNode should output to a MergeMem and the same Store
- Node *mm = NULL;
- for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) {
- x = mem->fast_out(i);
- if (!mm && x->is_MergeMem()) {
- mm = x;
- } else if (x != st && !x->is_Mach()) {
- // we may see mach nodes added during matching but nothing else
- return false;
- }
- }
-
- if (!mm)
- return false;
-
- // the MergeMem should output to the MemBarVolatile
- for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) {
- x = mm->fast_out(i);
- if (x != mbvol && !x->is_Mach()) {
- // we may see mach nodes added during matching but nothing else
- return false;
- }
- }
-
- return true;
-}
-
-
-
-bool needs_releasing_store(const Node *n)
-{
- // assert n->is_Store();
- if (UseBarriersForVolatile)
- // we use a normal store and dmb combination
+ // if the barrier is a release membar or a cpuorder mmebar fed by a
+ // release membar then we need to check whether that forms part of a
+ // volatile put graph.
+
+ // reject invalid candidates
+ if (!leading_membar(barrier))
return false;
- StoreNode *st = n->as_Store();
-
- if (!st->is_release())
- return false;
-
- // check if this store is bracketed by a release (or its dependent
- // cpuorder membar) and a volatile membar
- //
- // MemBarRelease
- // { || }
- // {MemBarCPUOrder} -- optional
- // || \\
- // || StoreX[mo_release]
- // | \ /
- // | MergeMem
- // | /
- // MemBarVolatile
- //
- // where
- // || and \\ represent Ctl and Mem feeds via Proj nodes
- // | \ and / indicate further routing of the Ctl and Mem feeds
- //
-
-
- Node *x = st->lookup(TypeFunc::Control);
-
- if (! x || !x->is_Proj())
- return false;
-
- ProjNode *proj = x->as_Proj();
-
- x = proj->lookup(0);
-
- if (!x || !x->is_MemBar())
- return false;
-
- MemBarNode *barrier = x->as_MemBar();
-
- // if the barrier is a release membar we have what we want. if it is
- // a cpuorder membar then we need to ensure that it is fed by a
- // release membar in which case we proceed to check the graph below
- // this cpuorder membar as the feed
-
- if (x->Opcode() != Op_MemBarRelease) {
- if (x->Opcode() != Op_MemBarCPUOrder)
- return false;
- Node *ctl = x->lookup(TypeFunc::Control);
- Node *mem = x->lookup(TypeFunc::Memory);
- if (!ctl || !ctl->is_Proj() || !mem || !mem->is_Proj())
- return false;
- x = ctl->lookup(0);
- if (!x || !x->is_MemBar() || !x->Opcode() == Op_MemBarRelease)
- return false;
- Node *y = mem->lookup(0);
- if (!y || y != x)
- return false;
- }
-
- ProjNode *ctl = barrier->proj_out(TypeFunc::Control);
- ProjNode *mem = barrier->proj_out(TypeFunc::Memory);
-
- // MemBarRelease needs to have both a Ctl and Mem projection
- // and we need to have reached it via the Ctl projection
- if (! ctl || ! mem || ctl != proj)
- return false;
-
- MemBarNode *mbvol = NULL;
-
- // The Ctl ProjNode should have output to a MemBarVolatile and
- // a Store marked as releasing
- for (DUIterator_Fast imax, i = ctl->fast_outs(imax); i < imax; i++) {
- x = ctl->fast_out(i);
- if (x->is_MemBar() && x->Opcode() == Op_MemBarVolatile) {
- mbvol = x->as_MemBar();
- } else if (x->is_Store()) {
- if (x != st) {
- return false;
- }
- } else if (!x->is_Mach()){
- return false;
- }
- }
+ // does this lead a normal subgraph?
+ MemBarNode *mbvol = leading_to_normal(barrier);
if (!mbvol)
return false;
- // the Mem ProjNode should output to a MergeMem and the same Store
- Node *mm = NULL;
- for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) {
- x = mem->fast_out(i);
- if (!mm && x->is_MergeMem()) {
- mm = x;
- } else if (x != st && !x->is_Mach()) {
- return false;
- }
- }
-
- if (!mm)
+ // all done unless this is a card mark
+ if (!is_card_mark_membar(mbvol))
+ return true;
+
+ // we found a card mark -- just make sure we have a trailing barrier
+
+ return (card_mark_to_trailing(mbvol) != NULL);
+}
+
+// predicate controlling translation of StoreCM
+//
+// returns true if a StoreStore must precede the card write otherwise
+// false
+
+bool unnecessary_storestore(const Node *storecm)
+{
+ assert(storecm->Opcode() == Op_StoreCM, "expecting a StoreCM");
+
+ // we only ever need to generate a dmb ishst between an object put
+ // and the associated card mark when we are using CMS without
+ // conditional card marking
+
+ if (!UseConcMarkSweepGC || UseCondCardMark)
+ return true;
+
+ // if we are implementing volatile puts using barriers then the
+ // object put as an str so we must insert the dmb ishst
+
+ if (UseBarriersForVolatile)
return false;
- // the MergeMem should output to the MemBarVolatile
- for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) {
- x = mm->fast_out(i);
- if (x != mbvol && !x->is_Mach()) {
- return false;
- }
- }
-
- return true;
-}
-
+ // we can omit the dmb ishst if this StoreCM is part of a volatile
+ // put because in thta case the put will be implemented by stlr
+ //
+ // we need to check for a normal subgraph feeding this StoreCM.
+ // that means the StoreCM must be fed Memory from a leading membar,
+ // either a MemBarRelease or its dependent MemBarCPUOrder, and the
+ // leading membar must be part of a normal subgraph
+
+ Node *x = storecm->in(StoreNode::Memory);
+
+ if (!x->is_Proj())
+ return false;
+
+ x = x->in(0);
+
+ if (!x->is_MemBar())
+ return false;
+
+ MemBarNode *leading = x->as_MemBar();
+
+ // reject invalid candidates
+ if (!leading_membar(leading))
+ return false;
+
+ // we can omit the StoreStore if it is the head of a normal subgraph
+ return (leading_to_normal(leading) != NULL);
+}
#define __ _masm.
@@ -2944,6 +3530,13 @@
as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
%}
+ enc_class aarch64_enc_strb0_ordered(memory mem) %{
+ MacroAssembler _masm(&cbuf);
+ __ membar(Assembler::StoreStore);
+ loadStore(_masm, &MacroAssembler::strb, zr, $mem->opcode(),
+ as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
+ %}
+
enc_class aarch64_enc_strh(iRegI src, memory mem) %{
Register src_reg = as_Register($src$$reg);
loadStore(MacroAssembler(&cbuf), &MacroAssembler::strh, src_reg, $mem->opcode(),
@@ -6613,6 +7206,7 @@
instruct storeimmCM0(immI0 zero, memory mem)
%{
match(Set mem (StoreCM mem zero));
+ predicate(unnecessary_storestore(n));
ins_cost(INSN_COST);
format %{ "strb zr, $mem\t# byte" %}
@@ -6622,6 +7216,21 @@
ins_pipe(istore_mem);
%}
+// Store CMS card-mark Immediate with intervening StoreStore
+// needed when using CMS with no conditional card marking
+instruct storeimmCM0_ordered(immI0 zero, memory mem)
+%{
+ match(Set mem (StoreCM mem zero));
+
+ ins_cost(INSN_COST * 2);
+ format %{ "dmb ishst"
+ "\n\tstrb zr, $mem\t# byte" %}
+
+ ins_encode(aarch64_enc_strb0_ordered(mem));
+
+ ins_pipe(istore_mem);
+%}
+
// Store Byte
instruct storeB(iRegIorL2I src, memory mem)
%{
@@ -6643,7 +7252,7 @@
predicate(!needs_releasing_store(n));
ins_cost(INSN_COST);
- format %{ "strb zr, $mem\t# byte" %}
+ format %{ "strb rscractch2, $mem\t# byte" %}
ins_encode(aarch64_enc_strb0(mem));
@@ -7396,6 +8005,7 @@
format %{ "membar_acquire" %}
ins_encode %{
+ __ block_comment("membar_acquire");
__ membar(Assembler::LoadLoad|Assembler::LoadStore);
%}
@@ -7448,6 +8058,7 @@
format %{ "membar_release" %}
ins_encode %{
+ __ block_comment("membar_release");
__ membar(Assembler::LoadStore|Assembler::StoreStore);
%}
ins_pipe(pipe_serial);
@@ -7499,6 +8110,7 @@
format %{ "membar_volatile" %}
ins_encode %{
+ __ block_comment("membar_volatile");
__ membar(Assembler::StoreLoad);
%}
@@ -9429,7 +10041,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -9465,7 +10077,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::ASR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -9501,7 +10113,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSL,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -9537,7 +10149,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -9573,7 +10185,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::ASR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -9609,7 +10221,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSL,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -9645,7 +10257,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -9681,7 +10293,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::ASR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -9717,7 +10329,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSL,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -9754,7 +10366,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -9792,7 +10404,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::ASR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -9830,7 +10442,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSL,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -9868,7 +10480,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -9906,7 +10518,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::ASR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -9944,7 +10556,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSL,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -9982,7 +10594,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -10020,7 +10632,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::ASR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -10058,7 +10670,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSL,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -10096,7 +10708,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -10134,7 +10746,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::ASR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -10172,7 +10784,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSL,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -10210,7 +10822,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -10248,7 +10860,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::ASR,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
@@ -10286,7 +10898,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::LSL,
- $src3$$constant & 0x3f);
+ $src3$$constant & 0x1f);
%}
ins_pipe(ialu_reg_reg_shift);
--- a/hotspot/src/cpu/aarch64/vm/aarch64_ad.m4 Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/aarch64/vm/aarch64_ad.m4 Tue Sep 08 14:40:44 2015 -0700
@@ -42,7 +42,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::$5,
- $src3$$constant & 0x3f);
+ $src3$$constant & ifelse($1,I,0x1f,0x3f));
%}
ins_pipe(ialu_reg_reg_shift);
@@ -87,7 +87,7 @@
as_Register($src1$$reg),
as_Register($src2$$reg),
Assembler::$5,
- $src3$$constant & 0x3f);
+ $src3$$constant & ifelse($1,I,0x1f,0x3f));
%}
ins_pipe(ialu_reg_reg_shift);
--- a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -268,7 +268,7 @@
__ ldar(r21, r28); // ldar x21, [x28]
// LoadStoreExclusiveOp
- __ stxrw(r24, r24, r7); // stxr w24, w24, [x7]
+ __ stxrw(r21, r24, r7); // stxr w21, w24, [x7]
__ stlxrw(r21, r26, r28); // stlxr w21, w26, [x28]
__ ldxrw(r21, r6); // ldxr w21, [x6]
__ ldaxrw(r15, r30); // ldaxr w15, [x30]
@@ -299,7 +299,7 @@
// LoadStoreExclusiveOp
__ ldxpw(r25, r4, r22); // ldxp w25, w4, [x22]
- __ ldaxpw(r14, r14, r15); // ldaxp w14, w14, [x15]
+ __ ldaxpw(r13, r14, r15); // ldaxp w13, w14, [x15]
__ stxpw(r20, r26, r8, r10); // stxp w20, w26, w8, [x10]
__ stlxpw(r23, r18, r18, r18); // stlxp w23, w18, w18, [x18]
@@ -773,7 +773,7 @@
260: c85fffbb ldaxr x27, [x29]
264: c89fffa0 stlr x0, [x29]
268: c8dfff95 ldar x21, [x28]
- 26c: 88187cf8 stxr w24, w24, [x7]
+ 26c: 88157cf8 stxr w21, w24, [x7]
270: 8815ff9a stlxr w21, w26, [x28]
274: 885f7cd5 ldxr w21, [x6]
278: 885fffcf ldaxr w15, [x30]
@@ -796,7 +796,7 @@
2bc: c82870bb stxp w8, x27, x28, [x5]
2c0: c825b8c8 stlxp w5, x8, x14, [x6]
2c4: 887f12d9 ldxp w25, w4, [x22]
- 2c8: 887fb9ee ldaxp w14, w14, [x15]
+ 2c8: 887fb9ed ldaxp w13, w14, [x15]
2cc: 8834215a stxp w20, w26, w8, [x10]
2d0: 8837ca52 stlxp w23, w18, w18, [x18]
2d4: f806317e str x30, [x11,#99]
@@ -1085,13 +1085,13 @@
0xd444c320, 0xd503201f, 0xd69f03e0, 0xd6bf03e0,
0xd5033fdf, 0xd5033f9f, 0xd5033abf, 0xd61f0040,
0xd63f00a0, 0xc8147c55, 0xc805fcfd, 0xc85f7e05,
- 0xc85fffbb, 0xc89fffa0, 0xc8dfff95, 0x88187cf8,
+ 0xc85fffbb, 0xc89fffa0, 0xc8dfff95, 0x88157cf8,
0x8815ff9a, 0x885f7cd5, 0x885fffcf, 0x889ffc73,
0x88dffc56, 0x48127c0f, 0x480bff85, 0x485f7cdd,
0x485ffcf2, 0x489fff99, 0x48dffe62, 0x080a7c3e,
0x0814fed5, 0x085f7c59, 0x085ffcb8, 0x089ffc70,
0x08dfffb6, 0xc87f0a68, 0xc87fcdc7, 0xc82870bb,
- 0xc825b8c8, 0x887f12d9, 0x887fb9ee, 0x8834215a,
+ 0xc825b8c8, 0x887f12d9, 0x887fb9ed, 0x8834215a,
0x8837ca52, 0xf806317e, 0xb81b3337, 0x39000dc2,
0x78005149, 0xf84391f4, 0xb85b220c, 0x385fd356,
0x785d127e, 0x389f4149, 0x79801e3c, 0x79c014a3,
--- a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -1106,13 +1106,13 @@
#define INSN4(NAME, sz, op, o0) /* Four registers */ \
void NAME(Register Rs, Register Rt1, Register Rt2, Register Rn) { \
- assert(Rs != Rn, "unpredictable instruction"); \
+ guarantee(Rs != Rn && Rs != Rt1 && Rs != Rt2, "unpredictable instruction"); \
load_store_exclusive(Rs, Rt1, Rt2, Rn, sz, op, o0); \
}
#define INSN3(NAME, sz, op, o0) /* Three registers */ \
void NAME(Register Rs, Register Rt, Register Rn) { \
- assert(Rs != Rn, "unpredictable instruction"); \
+ guarantee(Rs != Rn && Rs != Rt, "unpredictable instruction"); \
load_store_exclusive(Rs, Rt, (Register)0b11111, Rn, sz, op, o0); \
}
@@ -1124,6 +1124,7 @@
#define INSN_FOO(NAME, sz, op, o0) /* Three registers, encoded differently */ \
void NAME(Register Rt1, Register Rt2, Register Rn) { \
+ guarantee(Rt1 != Rt2, "unpredictable instruction"); \
load_store_exclusive((Register)0b11111, Rt1, Rt2, Rn, sz, op, o0); \
}
--- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -611,6 +611,7 @@
Label done;
const Register swap_reg = r0;
+ const Register tmp = c_rarg2;
const Register obj_reg = c_rarg3; // Will contain the oop
const int obj_offset = BasicObjectLock::obj_offset_in_bytes();
@@ -624,7 +625,7 @@
ldr(obj_reg, Address(lock_reg, obj_offset));
if (UseBiasedLocking) {
- biased_locking_enter(lock_reg, obj_reg, swap_reg, rscratch2, false, done, &slow_case);
+ biased_locking_enter(lock_reg, obj_reg, swap_reg, tmp, false, done, &slow_case);
}
// Load (object->mark() | 1) into swap_reg
@@ -643,7 +644,7 @@
cmpxchgptr(swap_reg, lock_reg, obj_reg, rscratch1, fast, &fail);
bind(fast);
atomic_incw(Address((address)BiasedLocking::fast_path_entry_count_addr()),
- rscratch2, rscratch1);
+ rscratch2, rscratch1, tmp);
b(done);
bind(fail);
} else {
@@ -671,7 +672,7 @@
if (PrintBiasedLockingStatistics) {
br(Assembler::NE, slow_case);
atomic_incw(Address((address)BiasedLocking::fast_path_entry_count_addr()),
- rscratch2, rscratch1);
+ rscratch2, rscratch1, tmp);
}
br(Assembler::EQ, done);
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -34,6 +34,7 @@
#include "memory/resourceArea.hpp"
#include "nativeInst_aarch64.hpp"
#include "oops/klass.inline.hpp"
+#include "oops/oop.inline.hpp"
#include "opto/compile.hpp"
#include "opto/node.hpp"
#include "runtime/biasedLocking.hpp"
@@ -398,11 +399,7 @@
if (PrintBiasedLockingStatistics && counters == NULL)
counters = BiasedLocking::counters();
- bool need_tmp_reg = false;
- if (tmp_reg == noreg) {
- tmp_reg = rscratch2;
- }
- assert_different_registers(lock_reg, obj_reg, swap_reg, tmp_reg, rscratch1);
+ assert_different_registers(lock_reg, obj_reg, swap_reg, tmp_reg, rscratch1, rscratch2, noreg);
assert(markOopDesc::age_shift == markOopDesc::lock_bits + markOopDesc::biased_lock_bits, "biased locking makes assumptions about bit layout");
Address mark_addr (obj_reg, oopDesc::mark_offset_in_bytes());
Address klass_addr (obj_reg, oopDesc::klass_offset_in_bytes());
@@ -432,7 +429,7 @@
if (counters != NULL) {
Label around;
cbnz(tmp_reg, around);
- atomic_incw(Address((address)counters->biased_lock_entry_count_addr()), tmp_reg, rscratch1);
+ atomic_incw(Address((address)counters->biased_lock_entry_count_addr()), tmp_reg, rscratch1, rscratch2);
b(done);
bind(around);
} else {
@@ -485,7 +482,7 @@
bind(here);
if (counters != NULL) {
atomic_incw(Address((address)counters->anonymously_biased_lock_entry_count_addr()),
- tmp_reg, rscratch1);
+ tmp_reg, rscratch1, rscratch2);
}
}
b(done);
@@ -511,7 +508,7 @@
bind(here);
if (counters != NULL) {
atomic_incw(Address((address)counters->rebiased_lock_entry_count_addr()),
- tmp_reg, rscratch1);
+ tmp_reg, rscratch1, rscratch2);
}
}
b(done);
@@ -539,7 +536,7 @@
// removing the bias bit from the object's header.
if (counters != NULL) {
atomic_incw(Address((address)counters->revoked_lock_entry_count_addr()), tmp_reg,
- rscratch1);
+ rscratch1, rscratch2);
}
bind(nope);
}
@@ -1640,15 +1637,15 @@
return Address(Rd);
}
-void MacroAssembler::atomic_incw(Register counter_addr, Register tmp) {
+void MacroAssembler::atomic_incw(Register counter_addr, Register tmp, Register tmp2) {
Label retry_load;
bind(retry_load);
// flush and load exclusive from the memory location
ldxrw(tmp, counter_addr);
addw(tmp, tmp, 1);
// if we store+flush with no intervening write tmp wil be zero
- stxrw(tmp, tmp, counter_addr);
- cbnzw(tmp, retry_load);
+ stxrw(tmp2, tmp, counter_addr);
+ cbnzw(tmp2, retry_load);
}
@@ -2021,6 +2018,14 @@
}
}
+void MacroAssembler::subw(Register Rd, Register Rn, RegisterOrConstant decrement) {
+ if (decrement.is_register()) {
+ subw(Rd, Rn, decrement.as_register());
+ } else {
+ subw(Rd, Rn, decrement.as_constant());
+ }
+}
+
void MacroAssembler::reinit_heapbase()
{
if (UseCompressedOops) {
@@ -2110,7 +2115,7 @@
return a != b.as_register() && a != c && b.as_register() != c;
}
-#define ATOMIC_OP(LDXR, OP, STXR) \
+#define ATOMIC_OP(LDXR, OP, IOP, STXR) \
void MacroAssembler::atomic_##OP(Register prev, RegisterOrConstant incr, Register addr) { \
Register result = rscratch2; \
if (prev->is_valid()) \
@@ -2120,14 +2125,15 @@
bind(retry_load); \
LDXR(result, addr); \
OP(rscratch1, result, incr); \
- STXR(rscratch1, rscratch1, addr); \
- cbnzw(rscratch1, retry_load); \
- if (prev->is_valid() && prev != result) \
- mov(prev, result); \
+ STXR(rscratch2, rscratch1, addr); \
+ cbnzw(rscratch2, retry_load); \
+ if (prev->is_valid() && prev != result) { \
+ IOP(prev, rscratch1, incr); \
+ } \
}
-ATOMIC_OP(ldxr, add, stxr)
-ATOMIC_OP(ldxrw, addw, stxrw)
+ATOMIC_OP(ldxr, add, sub, stxr)
+ATOMIC_OP(ldxrw, addw, subw, stxrw)
#undef ATOMIC_OP
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -107,9 +107,7 @@
// Biased locking support
// lock_reg and obj_reg must be loaded up with the appropriate values.
// swap_reg is killed.
- // tmp_reg is optional. If it is supplied (i.e., != noreg) it will
- // be killed; if not supplied, push/pop will be used internally to
- // allocate a temporary (inefficient, avoid if possible).
+ // tmp_reg must be supplied and must not be rscratch1 or rscratch2
// Optional slow case is for implementations (interpreter and C1) which branch to
// slow case directly. Leaves condition codes set for C2's Fast_Lock node.
// Returns offset of first potentially-faulting instruction for null
@@ -126,10 +124,10 @@
// Helper functions for statistics gathering.
// Unconditional atomic increment.
- void atomic_incw(Register counter_addr, Register tmp);
- void atomic_incw(Address counter_addr, Register tmp1, Register tmp2) {
+ void atomic_incw(Register counter_addr, Register tmp, Register tmp2);
+ void atomic_incw(Address counter_addr, Register tmp1, Register tmp2, Register tmp3) {
lea(tmp1, counter_addr);
- atomic_incw(tmp1, tmp2);
+ atomic_incw(tmp1, tmp2, tmp3);
}
// Load Effective Address
void lea(Register r, const Address &a) {
@@ -1057,6 +1055,7 @@
void add(Register Rd, Register Rn, RegisterOrConstant increment);
void addw(Register Rd, Register Rn, RegisterOrConstant increment);
void sub(Register Rd, Register Rn, RegisterOrConstant decrement);
+ void subw(Register Rd, Register Rn, RegisterOrConstant decrement);
void adrp(Register reg1, const Address &dest, unsigned long &byte_offset);
--- a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -1774,6 +1774,7 @@
const Register obj_reg = r19; // Will contain the oop
const Register lock_reg = r13; // Address of compiler lock object (BasicLock)
const Register old_hdr = r13; // value of old header at unlock time
+ const Register tmp = c_rarg3;
Label slow_path_lock;
Label lock_done;
@@ -1795,7 +1796,7 @@
__ ldr(obj_reg, Address(oop_handle_reg, 0));
if (UseBiasedLocking) {
- __ biased_locking_enter(lock_reg, obj_reg, swap_reg, rscratch2, false, lock_done, &slow_path_lock);
+ __ biased_locking_enter(lock_reg, obj_reg, swap_reg, tmp, false, lock_done, &slow_path_lock);
}
// Load (object->mark() | 1) into swap_reg %r0
--- a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -1913,15 +1913,18 @@
}
void TemplateInterpreterGenerator::count_bytecode() {
+ Register rscratch3 = r0;
__ push(rscratch1);
__ push(rscratch2);
+ __ push(rscratch3);
Label L;
__ mov(rscratch2, (address) &BytecodeCounter::_counter_value);
__ bind(L);
__ ldxr(rscratch1, rscratch2);
__ add(rscratch1, rscratch1, 1);
- __ stxr(rscratch1, rscratch1, rscratch2);
- __ cbnzw(rscratch1, L);
+ __ stxr(rscratch3, rscratch1, rscratch2);
+ __ cbnzw(rscratch3, L);
+ __ pop(rscratch3);
__ pop(rscratch2);
__ pop(rscratch1);
}
--- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -1674,6 +1674,13 @@
emit_simd_arith(0x2A, dst, src, VEX_SIMD_F3, true);
}
+void Assembler::cvtsi2ssq(XMMRegister dst, Register src) {
+ NOT_LP64(assert(VM_Version::supports_sse(), ""));
+ int encode = simd_prefix_and_encode_q(dst, dst, src, VEX_SIMD_F3, true);
+ emit_int8(0x2A);
+ emit_int8((unsigned char)(0xC0 | encode));
+}
+
void Assembler::cvtss2sd(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
emit_simd_arith(0x5A, dst, src, VEX_SIMD_F3);
@@ -6604,13 +6611,6 @@
emit_operand(dst, src);
}
-void Assembler::cvtsi2ssq(XMMRegister dst, Register src) {
- NOT_LP64(assert(VM_Version::supports_sse(), ""));
- int encode = simd_prefix_and_encode_q(dst, dst, src, VEX_SIMD_F3, true);
- emit_int8(0x2A);
- emit_int8((unsigned char)(0xC0 | encode));
-}
-
void Assembler::cvtsi2ssq(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
if (VM_Version::supports_evex()) {
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -355,8 +355,8 @@
case ctos: // fall through
case stos: // fall through
case itos: movl(rax, val_addr); break;
- case ftos: movflt(xmm0, val_addr); break;
- case dtos: movdbl(xmm0, val_addr); break;
+ case ftos: load_float(val_addr); break;
+ case dtos: load_double(val_addr); break;
case vtos: /* nothing to do */ break;
default : ShouldNotReachHere();
}
@@ -376,8 +376,8 @@
case ctos: // fall through
case stos: // fall through
case itos: movl(rax, val_addr); break;
- case ftos: fld_s(val_addr); break;
- case dtos: fld_d(val_addr); break;
+ case ftos: load_float(val_addr); break;
+ case dtos: load_double(val_addr); break;
case vtos: /* nothing to do */ break;
default : ShouldNotReachHere();
}
@@ -578,6 +578,26 @@
push(r);
}
+void InterpreterMacroAssembler::push_f(XMMRegister r) {
+ subptr(rsp, wordSize);
+ movflt(Address(rsp, 0), r);
+}
+
+void InterpreterMacroAssembler::pop_f(XMMRegister r) {
+ movflt(r, Address(rsp, 0));
+ addptr(rsp, wordSize);
+}
+
+void InterpreterMacroAssembler::push_d(XMMRegister r) {
+ subptr(rsp, 2 * wordSize);
+ movdbl(Address(rsp, 0), r);
+}
+
+void InterpreterMacroAssembler::pop_d(XMMRegister r) {
+ movdbl(r, Address(rsp, 0));
+ addptr(rsp, 2 * Interpreter::stackElementSize);
+}
+
#ifdef _LP64
void InterpreterMacroAssembler::pop_i(Register r) {
// XXX can't use pop currently, upper half non clean
@@ -590,31 +610,11 @@
addptr(rsp, 2 * Interpreter::stackElementSize);
}
-void InterpreterMacroAssembler::pop_f(XMMRegister r) {
- movflt(r, Address(rsp, 0));
- addptr(rsp, wordSize);
-}
-
-void InterpreterMacroAssembler::pop_d(XMMRegister r) {
- movdbl(r, Address(rsp, 0));
- addptr(rsp, 2 * Interpreter::stackElementSize);
-}
-
void InterpreterMacroAssembler::push_l(Register r) {
subptr(rsp, 2 * wordSize);
movq(Address(rsp, 0), r);
}
-void InterpreterMacroAssembler::push_f(XMMRegister r) {
- subptr(rsp, wordSize);
- movflt(Address(rsp, 0), r);
-}
-
-void InterpreterMacroAssembler::push_d(XMMRegister r) {
- subptr(rsp, 2 * wordSize);
- movdbl(Address(rsp, 0), r);
-}
-
void InterpreterMacroAssembler::pop(TosState state) {
switch (state) {
case atos: pop_ptr(); break;
@@ -623,8 +623,8 @@
case stos:
case itos: pop_i(); break;
case ltos: pop_l(); break;
- case ftos: pop_f(); break;
- case dtos: pop_d(); break;
+ case ftos: pop_f(xmm0); break;
+ case dtos: pop_d(xmm0); break;
case vtos: /* nothing to do */ break;
default: ShouldNotReachHere();
}
@@ -640,8 +640,8 @@
case stos:
case itos: push_i(); break;
case ltos: push_l(); break;
- case ftos: push_f(); break;
- case dtos: push_d(); break;
+ case ftos: push_f(xmm0); break;
+ case dtos: push_d(xmm0); break;
case vtos: /* nothing to do */ break;
default : ShouldNotReachHere();
}
@@ -675,8 +675,20 @@
case stos: // fall through
case itos: pop_i(rax); break;
case ltos: pop_l(rax, rdx); break;
- case ftos: pop_f(); break;
- case dtos: pop_d(); break;
+ case ftos:
+ if (UseSSE >= 1) {
+ pop_f(xmm0);
+ } else {
+ pop_f();
+ }
+ break;
+ case dtos:
+ if (UseSSE >= 2) {
+ pop_d(xmm0);
+ } else {
+ pop_d();
+ }
+ break;
case vtos: /* nothing to do */ break;
default : ShouldNotReachHere();
}
@@ -695,7 +707,7 @@
fstp_s(Address(rsp, 0));
}
-void InterpreterMacroAssembler::push_d(Register r) {
+void InterpreterMacroAssembler::push_d() {
// Do not schedule for no AGI! Never write beyond rsp!
subptr(rsp, 2 * wordSize);
fstp_d(Address(rsp, 0));
@@ -711,8 +723,20 @@
case stos: // fall through
case itos: push_i(rax); break;
case ltos: push_l(rax, rdx); break;
- case ftos: push_f(); break;
- case dtos: push_d(rax); break;
+ case ftos:
+ if (UseSSE >= 1) {
+ push_f(xmm0);
+ } else {
+ push_f();
+ }
+ break;
+ case dtos:
+ if (UseSSE >= 2) {
+ push_d(xmm0);
+ } else {
+ push_d();
+ }
+ break;
case vtos: /* nothing to do */ break;
default : ShouldNotReachHere();
}
@@ -995,22 +1019,6 @@
leave(); // remove frame anchor
pop(ret_addr); // get return address
mov(rsp, rbx); // set sp to sender sp
-#ifndef _LP64
- if (UseSSE) {
- // float and double are returned in xmm register in SSE-mode
- if (state == ftos && UseSSE >= 1) {
- subptr(rsp, wordSize);
- fstp_s(Address(rsp, 0));
- movflt(xmm0, Address(rsp, 0));
- addptr(rsp, wordSize);
- } else if (state == dtos && UseSSE >= 2) {
- subptr(rsp, 2*wordSize);
- fstp_d(Address(rsp, 0));
- movdbl(xmm0, Address(rsp, 0));
- addptr(rsp, 2*wordSize);
- }
- }
-#endif // _LP64
}
#endif // !CC_INTERP
@@ -1783,7 +1791,10 @@
void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) {
#ifndef _LP64
- if (state == ftos || state == dtos) MacroAssembler::verify_FPU(stack_depth);
+ if ((state == ftos && UseSSE < 1) ||
+ (state == dtos && UseSSE < 2)) {
+ MacroAssembler::verify_FPU(stack_depth);
+ }
#endif
}
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -140,20 +140,20 @@
void push_ptr(Register r = rax);
void push_i(Register r = rax);
+ void push_f(XMMRegister r);
+ void pop_f(XMMRegister r);
+ void pop_d(XMMRegister r);
+ void push_d(XMMRegister r);
#ifdef _LP64
void pop_l(Register r = rax);
- void pop_f(XMMRegister r = xmm0);
- void pop_d(XMMRegister r = xmm0);
void push_l(Register r = rax);
- void push_f(XMMRegister r = xmm0);
- void push_d(XMMRegister r = xmm0);
#else
void pop_l(Register lo = rax, Register hi = rdx);
void pop_f();
void pop_d();
void push_l(Register lo = rax, Register hi = rdx);
- void push_d(Register r = rax);
+ void push_d();
void push_f();
#endif // _LP64
--- a/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -42,6 +42,12 @@
address generate_Reference_get_entry();
address generate_CRC32_update_entry();
address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind);
+#ifndef _LP64
+ address generate_Float_intBitsToFloat_entry();
+ address generate_Float_floatToRawIntBits_entry();
+ address generate_Double_longBitsToDouble_entry();
+ address generate_Double_doubleToRawLongBits_entry();
+#endif
void lock_method(void);
void generate_stack_overflow_check(void);
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -3314,6 +3314,42 @@
fincstp();
}
+void MacroAssembler::load_float(Address src) {
+ if (UseSSE >= 1) {
+ movflt(xmm0, src);
+ } else {
+ LP64_ONLY(ShouldNotReachHere());
+ NOT_LP64(fld_s(src));
+ }
+}
+
+void MacroAssembler::store_float(Address dst) {
+ if (UseSSE >= 1) {
+ movflt(dst, xmm0);
+ } else {
+ LP64_ONLY(ShouldNotReachHere());
+ NOT_LP64(fstp_s(dst));
+ }
+}
+
+void MacroAssembler::load_double(Address src) {
+ if (UseSSE >= 2) {
+ movdbl(xmm0, src);
+ } else {
+ LP64_ONLY(ShouldNotReachHere());
+ NOT_LP64(fld_d(src));
+ }
+}
+
+void MacroAssembler::store_double(Address dst) {
+ if (UseSSE >= 2) {
+ movdbl(dst, xmm0);
+ } else {
+ LP64_ONLY(ShouldNotReachHere());
+ NOT_LP64(fstp_d(dst));
+ }
+}
+
void MacroAssembler::fremr(Register tmp) {
save_rax(tmp);
{ Label L;
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -471,6 +471,22 @@
// Pop ST (ffree & fincstp combined)
void fpop();
+ // Load float value from 'address'. If UseSSE >= 1, the value is loaded into
+ // register xmm0. Otherwise, the value is loaded onto the FPU stack.
+ void load_float(Address src);
+
+ // Store float value to 'address'. If UseSSE >= 1, the value is stored
+ // from register xmm0. Otherwise, the value is stored from the FPU stack.
+ void store_float(Address dst);
+
+ // Load double value from 'address'. If UseSSE >= 2, the value is loaded into
+ // register xmm0. Otherwise, the value is loaded onto the FPU stack.
+ void load_double(Address src);
+
+ // Store double value to 'address'. If UseSSE >= 2, the value is stored
+ // from register xmm0. Otherwise, the value is stored from the FPU stack.
+ void store_double(Address dst);
+
// pushes double TOS element of FPU stack on CPU stack; pops from FPU stack
void push_fTOS();
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -170,22 +170,12 @@
__ MacroAssembler::verify_FPU(0, "generate_return_entry_for compiled");
}
- // In SSE mode, interpreter returns FP results in xmm0 but they need
- // to end up back on the FPU so it can operate on them.
- if (state == ftos && UseSSE >= 1) {
- __ subptr(rsp, wordSize);
- __ movflt(Address(rsp, 0), xmm0);
- __ fld_s(Address(rsp, 0));
- __ addptr(rsp, wordSize);
- } else if (state == dtos && UseSSE >= 2) {
- __ subptr(rsp, 2*wordSize);
- __ movdbl(Address(rsp, 0), xmm0);
- __ fld_d(Address(rsp, 0));
- __ addptr(rsp, 2*wordSize);
+ if (state == ftos) {
+ __ MacroAssembler::verify_FPU(UseSSE >= 1 ? 0 : 1, "generate_return_entry_for in interpreter");
+ } else if (state == dtos) {
+ __ MacroAssembler::verify_FPU(UseSSE >= 2 ? 0 : 1, "generate_return_entry_for in interpreter");
}
- __ MacroAssembler::verify_FPU(state == ftos || state == dtos ? 1 : 0, "generate_return_entry_for in interpreter");
-
// Restore stack bottom in case i2c adjusted stack
__ movptr(rsp, Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize));
// and NULL it as marker that rsp is now tos until next java call
@@ -217,21 +207,12 @@
address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) {
address entry = __ pc();
- // In SSE mode, FP results are in xmm0
- if (state == ftos && UseSSE > 0) {
- __ subptr(rsp, wordSize);
- __ movflt(Address(rsp, 0), xmm0);
- __ fld_s(Address(rsp, 0));
- __ addptr(rsp, wordSize);
- } else if (state == dtos && UseSSE >= 2) {
- __ subptr(rsp, 2*wordSize);
- __ movdbl(Address(rsp, 0), xmm0);
- __ fld_d(Address(rsp, 0));
- __ addptr(rsp, 2*wordSize);
+ if (state == ftos) {
+ __ MacroAssembler::verify_FPU(UseSSE >= 1 ? 0 : 1, "generate_deopt_entry_for in interpreter");
+ } else if (state == dtos) {
+ __ MacroAssembler::verify_FPU(UseSSE >= 2 ? 0 : 1, "generate_deopt_entry_for in interpreter");
}
- __ MacroAssembler::verify_FPU(state == ftos || state == dtos ? 1 : 0, "generate_deopt_entry_for in interpreter");
-
// The stack is not extended by deopt but we must NULL last_sp as this
// entry is like a "return".
__ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD);
@@ -735,7 +716,7 @@
if (UseCRC32Intrinsics) {
address entry = __ pc();
- // rbx,: Method*
+ // rbx: Method*
// rsi: senderSP must preserved for slow path, set SP to it on fast path
// rdx: scratch
// rdi: scratch
@@ -841,6 +822,124 @@
return generate_native_entry(false);
}
+/**
+ * Method entry for static native method:
+ * java.lang.Float.intBitsToFloat(int bits)
+ */
+address InterpreterGenerator::generate_Float_intBitsToFloat_entry() {
+ address entry;
+
+ if (UseSSE >= 1) {
+ entry = __ pc();
+
+ // rsi: the sender's SP
+
+ // Skip safepoint check (compiler intrinsic versions of this method
+ // do not perform safepoint checks either).
+
+ // Load 'bits' into xmm0 (interpreter returns results in xmm0)
+ __ movflt(xmm0, Address(rsp, wordSize));
+
+ // Return
+ __ pop(rdi); // get return address
+ __ mov(rsp, rsi); // set rsp to the sender's SP
+ __ jmp(rdi);
+ } else {
+ entry = generate_native_entry(false);
+ }
+
+ return entry;
+}
+
+/**
+ * Method entry for static native method:
+ * java.lang.Float.floatToRawIntBits(float value)
+ */
+address InterpreterGenerator::generate_Float_floatToRawIntBits_entry() {
+ address entry;
+
+ if (UseSSE >= 1) {
+ entry = __ pc();
+
+ // rsi: the sender's SP
+
+ // Skip safepoint check (compiler intrinsic versions of this method
+ // do not perform safepoint checks either).
+
+ // Load the parameter (a floating-point value) into rax.
+ __ movl(rax, Address(rsp, wordSize));
+
+ // Return
+ __ pop(rdi); // get return address
+ __ mov(rsp, rsi); // set rsp to the sender's SP
+ __ jmp(rdi);
+ } else {
+ entry = generate_native_entry(false);
+ }
+
+ return entry;
+}
+
+
+/**
+ * Method entry for static native method:
+ * java.lang.Double.longBitsToDouble(long bits)
+ */
+address InterpreterGenerator::generate_Double_longBitsToDouble_entry() {
+ address entry;
+
+ if (UseSSE >= 2) {
+ entry = __ pc();
+
+ // rsi: the sender's SP
+
+ // Skip safepoint check (compiler intrinsic versions of this method
+ // do not perform safepoint checks either).
+
+ // Load 'bits' into xmm0 (interpreter returns results in xmm0)
+ __ movdbl(xmm0, Address(rsp, wordSize));
+
+ // Return
+ __ pop(rdi); // get return address
+ __ mov(rsp, rsi); // set rsp to the sender's SP
+ __ jmp(rdi);
+ } else {
+ entry = generate_native_entry(false);
+ }
+
+ return entry;
+}
+
+/**
+ * Method entry for static native method:
+ * java.lang.Double.doubleToRawLongBits(double value)
+ */
+address InterpreterGenerator::generate_Double_doubleToRawLongBits_entry() {
+ address entry;
+
+ if (UseSSE >= 2) {
+ entry = __ pc();
+
+ // rsi: the sender's SP
+
+ // Skip safepoint check (compiler intrinsic versions of this method
+ // do not perform safepoint checks either).
+
+ // Load the parameter (a floating-point value) into rax.
+ __ movl(rdx, Address(rsp, 2*wordSize));
+ __ movl(rax, Address(rsp, wordSize));
+
+ // Return
+ __ pop(rdi); // get return address
+ __ mov(rsp, rsi); // set rsp to the sender's SP
+ __ jmp(rdi);
+ } else {
+ entry = generate_native_entry(false);
+ }
+
+ return entry;
+}
+
//
// Interpreter stub for calling a native method. (asm interpreter)
// This sets up a somewhat different looking stack for calling the native method
@@ -1090,7 +1189,7 @@
double_handler.addr());
__ jcc(Assembler::notEqual, L);
__ bind(push_double);
- __ push(dtos);
+ __ push_d(); // FP values are returned using the FPU, so push FPU contents (even if UseSSE > 0).
__ bind(L);
}
__ push(ltos);
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -1707,10 +1707,10 @@
address& vep) {
assert(t->is_valid() && t->tos_in() == vtos, "illegal template");
Label L;
- aep = __ pc(); __ push_ptr(); __ jmp(L);
- fep = __ pc(); __ push_f(); __ jmp(L);
- dep = __ pc(); __ push_d(); __ jmp(L);
- lep = __ pc(); __ push_l(); __ jmp(L);
+ aep = __ pc(); __ push_ptr(); __ jmp(L);
+ fep = __ pc(); __ push_f(xmm0); __ jmp(L);
+ dep = __ pc(); __ push_d(xmm0); __ jmp(L);
+ lep = __ pc(); __ push_l(); __ jmp(L);
bep = cep = sep =
iep = __ pc(); __ push_i();
vep = __ pc();
--- a/hotspot/src/cpu/x86/vm/templateTable_x86.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -349,53 +349,60 @@
void TemplateTable::fconst(int value) {
transition(vtos, ftos);
+ if (UseSSE >= 1) {
+ static float one = 1.0f, two = 2.0f;
+ switch (value) {
+ case 0:
+ __ xorps(xmm0, xmm0);
+ break;
+ case 1:
+ __ movflt(xmm0, ExternalAddress((address) &one));
+ break;
+ case 2:
+ __ movflt(xmm0, ExternalAddress((address) &two));
+ break;
+ default:
+ ShouldNotReachHere();
+ break;
+ }
+ } else {
#ifdef _LP64
- static float one = 1.0f, two = 2.0f;
- switch (value) {
- case 0:
- __ xorps(xmm0, xmm0);
- break;
- case 1:
- __ movflt(xmm0, ExternalAddress((address) &one));
- break;
- case 2:
- __ movflt(xmm0, ExternalAddress((address) &two));
- break;
- default:
ShouldNotReachHere();
- break;
+#else
+ if (value == 0) { __ fldz();
+ } else if (value == 1) { __ fld1();
+ } else if (value == 2) { __ fld1(); __ fld1(); __ faddp(); // should do a better solution here
+ } else { ShouldNotReachHere();
+ }
+#endif // _LP64
}
-#else
- if (value == 0) { __ fldz();
- } else if (value == 1) { __ fld1();
- } else if (value == 2) { __ fld1(); __ fld1(); __ faddp(); // should do a better solution here
- } else { ShouldNotReachHere();
- }
-#endif
}
void TemplateTable::dconst(int value) {
transition(vtos, dtos);
+ if (UseSSE >= 2) {
+ static double one = 1.0;
+ switch (value) {
+ case 0:
+ __ xorpd(xmm0, xmm0);
+ break;
+ case 1:
+ __ movdbl(xmm0, ExternalAddress((address) &one));
+ break;
+ default:
+ ShouldNotReachHere();
+ break;
+ }
+ } else {
#ifdef _LP64
- static double one = 1.0;
- switch (value) {
- case 0:
- __ xorpd(xmm0, xmm0);
- break;
- case 1:
- __ movdbl(xmm0, ExternalAddress((address) &one));
- break;
- default:
ShouldNotReachHere();
- break;
+#else
+ if (value == 0) { __ fldz();
+ } else if (value == 1) { __ fld1();
+ } else { ShouldNotReachHere();
+ }
+#endif
}
-
-#else
- if (value == 0) { __ fldz();
- } else if (value == 1) { __ fld1();
- } else { ShouldNotReachHere();
- }
-#endif
}
void TemplateTable::bipush() {
@@ -454,8 +461,7 @@
__ jccb(Assembler::notEqual, notFloat);
// ftos
- LP64_ONLY(__ movflt(xmm0, Address(rcx, rbx, Address::times_8, base_offset)));
- NOT_LP64(__ fld_s( Address(rcx, rbx, Address::times_ptr, base_offset)));
+ __ load_float(Address(rcx, rbx, Address::times_ptr, base_offset));
__ push(ftos);
__ jmp(Done);
@@ -522,8 +528,7 @@
__ jccb(Assembler::notEqual, Long);
// dtos
- LP64_ONLY(__ movdbl(xmm0, Address(rcx, rbx, Address::times_8, base_offset)));
- NOT_LP64(__ fld_d( Address(rcx, rbx, Address::times_ptr, base_offset)));
+ __ load_double(Address(rcx, rbx, Address::times_ptr, base_offset));
__ push(dtos);
__ jmpb(Done);
@@ -617,15 +622,13 @@
void TemplateTable::fload() {
transition(vtos, ftos);
locals_index(rbx);
- LP64_ONLY(__ movflt(xmm0, faddress(rbx)));
- NOT_LP64(__ fld_s(faddress(rbx)));
+ __ load_float(faddress(rbx));
}
void TemplateTable::dload() {
transition(vtos, dtos);
locals_index(rbx);
- LP64_ONLY(__ movdbl(xmm0, daddress(rbx)));
- NOT_LP64(__ fld_d(daddress(rbx)));
+ __ load_double(daddress(rbx));
}
void TemplateTable::aload() {
@@ -657,15 +660,13 @@
void TemplateTable::wide_fload() {
transition(vtos, ftos);
locals_index_wide(rbx);
- LP64_ONLY(__ movflt(xmm0, faddress(rbx)));
- NOT_LP64(__ fld_s(faddress(rbx)));
+ __ load_float(faddress(rbx));
}
void TemplateTable::wide_dload() {
transition(vtos, dtos);
locals_index_wide(rbx);
- LP64_ONLY(__ movdbl(xmm0, daddress(rbx)));
- NOT_LP64(__ fld_d(daddress(rbx)));
+ __ load_double(daddress(rbx));
}
void TemplateTable::wide_aload() {
@@ -726,10 +727,9 @@
// rax: index
// rdx: array
index_check(rdx, rax); // kills rbx
- LP64_ONLY(__ movflt(xmm0, Address(rdx, rax,
- Address::times_4,
- arrayOopDesc::base_offset_in_bytes(T_FLOAT))));
- NOT_LP64(__ fld_s(Address(rdx, rax, Address::times_4, arrayOopDesc::base_offset_in_bytes(T_FLOAT))));
+ __ load_float(Address(rdx, rax,
+ Address::times_4,
+ arrayOopDesc::base_offset_in_bytes(T_FLOAT)));
}
void TemplateTable::daload() {
@@ -737,10 +737,9 @@
// rax: index
// rdx: array
index_check(rdx, rax); // kills rbx
- LP64_ONLY(__ movdbl(xmm0, Address(rdx, rax,
- Address::times_8,
- arrayOopDesc::base_offset_in_bytes(T_DOUBLE))));
- NOT_LP64(__ fld_d(Address(rdx, rax, Address::times_8, arrayOopDesc::base_offset_in_bytes(T_DOUBLE))));
+ __ load_double(Address(rdx, rax,
+ Address::times_8,
+ arrayOopDesc::base_offset_in_bytes(T_DOUBLE)));
}
void TemplateTable::aaload() {
@@ -807,14 +806,12 @@
void TemplateTable::fload(int n) {
transition(vtos, ftos);
- LP64_ONLY(__ movflt(xmm0, faddress(n)));
- NOT_LP64(__ fld_s(faddress(n)));
+ __ load_float(faddress(n));
}
void TemplateTable::dload(int n) {
transition(vtos, dtos);
- LP64_ONLY(__ movdbl(xmm0, daddress(n)));
- NOT_LP64(__ fld_d(daddress(n)));
+ __ load_double(daddress(n));
}
void TemplateTable::aload(int n) {
@@ -919,15 +916,13 @@
void TemplateTable::fstore() {
transition(ftos, vtos);
locals_index(rbx);
- LP64_ONLY(__ movflt(faddress(rbx), xmm0));
- NOT_LP64(__ fstp_s(faddress(rbx)));
+ __ store_float(faddress(rbx));
}
void TemplateTable::dstore() {
transition(dtos, vtos);
locals_index(rbx);
- LP64_ONLY(__ movdbl(daddress(rbx), xmm0));
- NOT_LP64(__ fstp_d(daddress(rbx)));
+ __ store_double(daddress(rbx));
}
void TemplateTable::astore() {
@@ -956,7 +951,7 @@
void TemplateTable::wide_fstore() {
#ifdef _LP64
transition(vtos, vtos);
- __ pop_f();
+ __ pop_f(xmm0);
locals_index_wide(rbx);
__ movflt(faddress(rbx), xmm0);
#else
@@ -967,7 +962,7 @@
void TemplateTable::wide_dstore() {
#ifdef _LP64
transition(vtos, vtos);
- __ pop_d();
+ __ pop_d(xmm0);
locals_index_wide(rbx);
__ movdbl(daddress(rbx), xmm0);
#else
@@ -1011,29 +1006,21 @@
void TemplateTable::fastore() {
transition(ftos, vtos);
__ pop_i(rbx);
- // xmm0: value
+ // value is in UseSSE >= 1 ? xmm0 : ST(0)
// rbx: index
// rdx: array
index_check(rdx, rbx); // prefer index in rbx
- LP64_ONLY(__ movflt(Address(rdx, rbx,
- Address::times_4,
- arrayOopDesc::base_offset_in_bytes(T_FLOAT)),
- xmm0));
- NOT_LP64(__ fstp_s(Address(rdx, rbx, Address::times_4, arrayOopDesc::base_offset_in_bytes(T_FLOAT))));
+ __ store_float(Address(rdx, rbx, Address::times_4, arrayOopDesc::base_offset_in_bytes(T_FLOAT)));
}
void TemplateTable::dastore() {
transition(dtos, vtos);
__ pop_i(rbx);
- // xmm0: value
+ // value is in UseSSE >= 2 ? xmm0 : ST(0)
// rbx: index
// rdx: array
index_check(rdx, rbx); // prefer index in rbx
- LP64_ONLY(__ movdbl(Address(rdx, rbx,
- Address::times_8,
- arrayOopDesc::base_offset_in_bytes(T_DOUBLE)),
- xmm0));
- NOT_LP64(__ fstp_d(Address(rdx, rbx, Address::times_8, arrayOopDesc::base_offset_in_bytes(T_DOUBLE))));
+ __ store_double(Address(rdx, rbx, Address::times_8, arrayOopDesc::base_offset_in_bytes(T_DOUBLE)));
}
void TemplateTable::aastore() {
@@ -1134,14 +1121,12 @@
void TemplateTable::fstore(int n) {
transition(ftos, vtos);
- LP64_ONLY(__ movflt(faddress(n), xmm0));
- NOT_LP64(__ fstp_s(faddress(n)));
+ __ store_float(faddress(n));
}
void TemplateTable::dstore(int n) {
transition(dtos, vtos);
- LP64_ONLY(__ movdbl(daddress(n), xmm0));
- NOT_LP64(__ fstp_d(daddress(n)));
+ __ store_double(daddress(n));
}
@@ -1425,82 +1410,127 @@
void TemplateTable::fop2(Operation op) {
transition(ftos, ftos);
+
+ if (UseSSE >= 1) {
+ switch (op) {
+ case add:
+ __ addss(xmm0, at_rsp());
+ __ addptr(rsp, Interpreter::stackElementSize);
+ break;
+ case sub:
+ __ movflt(xmm1, xmm0);
+ __ pop_f(xmm0);
+ __ subss(xmm0, xmm1);
+ break;
+ case mul:
+ __ mulss(xmm0, at_rsp());
+ __ addptr(rsp, Interpreter::stackElementSize);
+ break;
+ case div:
+ __ movflt(xmm1, xmm0);
+ __ pop_f(xmm0);
+ __ divss(xmm0, xmm1);
+ break;
+ case rem:
+ // On x86_64 platforms the SharedRuntime::frem method is called to perform the
+ // modulo operation. The frem method calls the function
+ // double fmod(double x, double y) in math.h. The documentation of fmod states:
+ // "If x or y is a NaN, a NaN is returned." without specifying what type of NaN
+ // (signalling or quiet) is returned.
+ //
+ // On x86_32 platforms the FPU is used to perform the modulo operation. The
+ // reason is that on 32-bit Windows the sign of modulo operations diverges from
+ // what is considered the standard (e.g., -0.0f % -3.14f is 0.0f (and not -0.0f).
+ // The fprem instruction used on x86_32 is functionally equivalent to
+ // SharedRuntime::frem in that it returns a NaN.
#ifdef _LP64
- switch (op) {
- case add:
- __ addss(xmm0, at_rsp());
- __ addptr(rsp, Interpreter::stackElementSize);
- break;
- case sub:
- __ movflt(xmm1, xmm0);
- __ pop_f(xmm0);
- __ subss(xmm0, xmm1);
- break;
- case mul:
- __ mulss(xmm0, at_rsp());
- __ addptr(rsp, Interpreter::stackElementSize);
- break;
- case div:
- __ movflt(xmm1, xmm0);
- __ pop_f(xmm0);
- __ divss(xmm0, xmm1);
- break;
- case rem:
- __ movflt(xmm1, xmm0);
- __ pop_f(xmm0);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::frem), 2);
- break;
- default:
+ __ movflt(xmm1, xmm0);
+ __ pop_f(xmm0);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::frem), 2);
+#else
+ __ push_f(xmm0);
+ __ pop_f();
+ __ fld_s(at_rsp());
+ __ fremr(rax);
+ __ f2ieee();
+ __ pop(rax); // pop second operand off the stack
+ __ push_f();
+ __ pop_f(xmm0);
+#endif
+ break;
+ default:
+ ShouldNotReachHere();
+ break;
+ }
+ } else {
+#ifdef _LP64
ShouldNotReachHere();
- break;
- }
#else
- switch (op) {
+ switch (op) {
case add: __ fadd_s (at_rsp()); break;
case sub: __ fsubr_s(at_rsp()); break;
case mul: __ fmul_s (at_rsp()); break;
case div: __ fdivr_s(at_rsp()); break;
case rem: __ fld_s (at_rsp()); __ fremr(rax); break;
default : ShouldNotReachHere();
+ }
+ __ f2ieee();
+ __ pop(rax); // pop second operand off the stack
+#endif // _LP64
}
- __ f2ieee();
- __ pop(rax); // pop float thing off
-#endif
}
void TemplateTable::dop2(Operation op) {
transition(dtos, dtos);
+ if (UseSSE >= 2) {
+ switch (op) {
+ case add:
+ __ addsd(xmm0, at_rsp());
+ __ addptr(rsp, 2 * Interpreter::stackElementSize);
+ break;
+ case sub:
+ __ movdbl(xmm1, xmm0);
+ __ pop_d(xmm0);
+ __ subsd(xmm0, xmm1);
+ break;
+ case mul:
+ __ mulsd(xmm0, at_rsp());
+ __ addptr(rsp, 2 * Interpreter::stackElementSize);
+ break;
+ case div:
+ __ movdbl(xmm1, xmm0);
+ __ pop_d(xmm0);
+ __ divsd(xmm0, xmm1);
+ break;
+ case rem:
+ // Similar to fop2(), the modulo operation is performed using the
+ // SharedRuntime::drem method (on x86_64 platforms) or using the
+ // FPU (on x86_32 platforms) for the same reasons as mentioned in fop2().
#ifdef _LP64
- switch (op) {
- case add:
- __ addsd(xmm0, at_rsp());
- __ addptr(rsp, 2 * Interpreter::stackElementSize);
- break;
- case sub:
- __ movdbl(xmm1, xmm0);
- __ pop_d(xmm0);
- __ subsd(xmm0, xmm1);
- break;
- case mul:
- __ mulsd(xmm0, at_rsp());
- __ addptr(rsp, 2 * Interpreter::stackElementSize);
- break;
- case div:
- __ movdbl(xmm1, xmm0);
- __ pop_d(xmm0);
- __ divsd(xmm0, xmm1);
- break;
- case rem:
- __ movdbl(xmm1, xmm0);
- __ pop_d(xmm0);
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::drem), 2);
- break;
- default:
+ __ movdbl(xmm1, xmm0);
+ __ pop_d(xmm0);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::drem), 2);
+#else
+ __ push_d(xmm0);
+ __ pop_d();
+ __ fld_d(at_rsp());
+ __ fremr(rax);
+ __ d2ieee();
+ __ pop(rax);
+ __ pop(rdx);
+ __ push_d();
+ __ pop_d(xmm0);
+#endif
+ break;
+ default:
+ ShouldNotReachHere();
+ break;
+ }
+ } else {
+#ifdef _LP64
ShouldNotReachHere();
- break;
- }
#else
- switch (op) {
+ switch (op) {
case add: __ fadd_d (at_rsp()); break;
case sub: __ fsubr_d(at_rsp()); break;
case mul: {
@@ -1543,12 +1573,13 @@
}
case rem: __ fld_d (at_rsp()); __ fremr(rax); break;
default : ShouldNotReachHere();
+ }
+ __ d2ieee();
+ // Pop double precision number from rsp.
+ __ pop(rax);
+ __ pop(rdx);
+#endif
}
- __ d2ieee();
- // Pop double precision number from rsp.
- __ pop(rax);
- __ pop(rdx);
-#endif
}
void TemplateTable::ineg() {
@@ -1562,7 +1593,6 @@
NOT_LP64(__ lneg(rdx, rax));
}
-#ifdef _LP64
// Note: 'double' and 'long long' have 32-bits alignment on x86.
static jlong* double_quadword(jlong *adr, jlong lo, jlong hi) {
// Use the expression (adr)&(~0xF) to provide 128-bits aligned address
@@ -1577,26 +1607,30 @@
// Buffer for 128-bits masks used by SSE instructions.
static jlong float_signflip_pool[2*2];
static jlong double_signflip_pool[2*2];
-#endif
void TemplateTable::fneg() {
transition(ftos, ftos);
-#ifdef _LP64
- static jlong *float_signflip = double_quadword(&float_signflip_pool[1], 0x8000000080000000, 0x8000000080000000);
- __ xorps(xmm0, ExternalAddress((address) float_signflip));
-#else
- __ fchs();
-#endif
+ if (UseSSE >= 1) {
+ static jlong *float_signflip = double_quadword(&float_signflip_pool[1], 0x8000000080000000, 0x8000000080000000);
+ __ xorps(xmm0, ExternalAddress((address) float_signflip));
+ } else {
+ LP64_ONLY(ShouldNotReachHere());
+ NOT_LP64(__ fchs());
+ }
}
void TemplateTable::dneg() {
transition(dtos, dtos);
+ if (UseSSE >= 2) {
+ static jlong *double_signflip = double_quadword(&double_signflip_pool[1], 0x8000000000000000, 0x8000000000000000);
+ __ xorpd(xmm0, ExternalAddress((address) double_signflip));
+ } else {
#ifdef _LP64
- static jlong *double_signflip = double_quadword(&double_signflip_pool[1], 0x8000000000000000, 0x8000000000000000);
- __ xorpd(xmm0, ExternalAddress((address) double_signflip));
+ ShouldNotReachHere();
#else
- __ fchs();
+ __ fchs();
#endif
+ }
}
void TemplateTable::iinc() {
@@ -1798,18 +1832,26 @@
__ extend_sign(rdx, rax);
break;
case Bytecodes::_i2f:
- __ push(rax); // store int on tos
- __ fild_s(at_rsp()); // load int to ST0
- __ f2ieee(); // truncate to float size
- __ pop(rcx); // adjust rsp
+ if (UseSSE >= 1) {
+ __ cvtsi2ssl(xmm0, rax);
+ } else {
+ __ push(rax); // store int on tos
+ __ fild_s(at_rsp()); // load int to ST0
+ __ f2ieee(); // truncate to float size
+ __ pop(rcx); // adjust rsp
+ }
break;
case Bytecodes::_i2d:
+ if (UseSSE >= 2) {
+ __ cvtsi2sdl(xmm0, rax);
+ } else {
__ push(rax); // add one slot for d2ieee()
__ push(rax); // store int on tos
__ fild_s(at_rsp()); // load int to ST0
__ d2ieee(); // truncate to double size
__ pop(rcx); // adjust rsp
__ pop(rcx);
+ }
break;
case Bytecodes::_i2b:
__ shll(rax, 24); // truncate upper 24 bits
@@ -1829,50 +1871,102 @@
/* nothing to do */
break;
case Bytecodes::_l2f:
+ // On 64-bit platforms, the cvtsi2ssq instruction is used to convert
+ // 64-bit long values to floats. On 32-bit platforms it is not possible
+ // to use that instruction with 64-bit operands, therefore the FPU is
+ // used to perform the conversion.
__ push(rdx); // store long on tos
__ push(rax);
__ fild_d(at_rsp()); // load long to ST0
__ f2ieee(); // truncate to float size
__ pop(rcx); // adjust rsp
__ pop(rcx);
+ if (UseSSE >= 1) {
+ __ push_f();
+ __ pop_f(xmm0);
+ }
break;
case Bytecodes::_l2d:
+ // On 32-bit platforms the FPU is used for conversion because on
+ // 32-bit platforms it is not not possible to use the cvtsi2sdq
+ // instruction with 64-bit operands.
__ push(rdx); // store long on tos
__ push(rax);
__ fild_d(at_rsp()); // load long to ST0
__ d2ieee(); // truncate to double size
__ pop(rcx); // adjust rsp
__ pop(rcx);
+ if (UseSSE >= 2) {
+ __ push_d();
+ __ pop_d(xmm0);
+ }
break;
case Bytecodes::_f2i:
- __ push(rcx); // reserve space for argument
- __ fstp_s(at_rsp()); // pass float argument on stack
+ // SharedRuntime::f2i does not differentiate between sNaNs and qNaNs
+ // as it returns 0 for any NaN.
+ if (UseSSE >= 1) {
+ __ push_f(xmm0);
+ } else {
+ __ push(rcx); // reserve space for argument
+ __ fstp_s(at_rsp()); // pass float argument on stack
+ }
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::f2i), 1);
break;
case Bytecodes::_f2l:
- __ push(rcx); // reserve space for argument
- __ fstp_s(at_rsp()); // pass float argument on stack
+ // SharedRuntime::f2l does not differentiate between sNaNs and qNaNs
+ // as it returns 0 for any NaN.
+ if (UseSSE >= 1) {
+ __ push_f(xmm0);
+ } else {
+ __ push(rcx); // reserve space for argument
+ __ fstp_s(at_rsp()); // pass float argument on stack
+ }
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::f2l), 1);
break;
case Bytecodes::_f2d:
- /* nothing to do */
+ if (UseSSE < 1) {
+ /* nothing to do */
+ } else if (UseSSE == 1) {
+ __ push_f(xmm0);
+ __ pop_f();
+ } else { // UseSSE >= 2
+ __ cvtss2sd(xmm0, xmm0);
+ }
break;
case Bytecodes::_d2i:
- __ push(rcx); // reserve space for argument
- __ push(rcx);
- __ fstp_d(at_rsp()); // pass double argument on stack
+ if (UseSSE >= 2) {
+ __ push_d(xmm0);
+ } else {
+ __ push(rcx); // reserve space for argument
+ __ push(rcx);
+ __ fstp_d(at_rsp()); // pass double argument on stack
+ }
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::d2i), 2);
break;
case Bytecodes::_d2l:
- __ push(rcx); // reserve space for argument
- __ push(rcx);
- __ fstp_d(at_rsp()); // pass double argument on stack
+ if (UseSSE >= 2) {
+ __ push_d(xmm0);
+ } else {
+ __ push(rcx); // reserve space for argument
+ __ push(rcx);
+ __ fstp_d(at_rsp()); // pass double argument on stack
+ }
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::d2l), 2);
break;
case Bytecodes::_d2f:
- __ push(rcx); // reserve space for f2ieee()
- __ f2ieee(); // truncate to float size
- __ pop(rcx); // adjust rsp
+ if (UseSSE <= 1) {
+ __ push(rcx); // reserve space for f2ieee()
+ __ f2ieee(); // truncate to float size
+ __ pop(rcx); // adjust rsp
+ if (UseSSE == 1) {
+ // The cvtsd2ss instruction is not available if UseSSE==1, therefore
+ // the conversion is performed using the FPU in this case.
+ __ push_f();
+ __ pop_f(xmm0);
+ }
+ } else { // UseSSE >= 2
+ __ cvtsd2ss(xmm0, xmm0);
+ }
break;
default :
ShouldNotReachHere();
@@ -1901,42 +1995,47 @@
}
void TemplateTable::float_cmp(bool is_float, int unordered_result) {
-#ifdef _LP64
- Label done;
- if (is_float) {
- // XXX get rid of pop here, use ... reg, mem32
- __ pop_f(xmm1);
- __ ucomiss(xmm1, xmm0);
- } else {
- // XXX get rid of pop here, use ... reg, mem64
- __ pop_d(xmm1);
- __ ucomisd(xmm1, xmm0);
- }
- if (unordered_result < 0) {
- __ movl(rax, -1);
- __ jccb(Assembler::parity, done);
- __ jccb(Assembler::below, done);
- __ setb(Assembler::notEqual, rdx);
- __ movzbl(rax, rdx);
+ if ((is_float && UseSSE >= 1) ||
+ (!is_float && UseSSE >= 2)) {
+ Label done;
+ if (is_float) {
+ // XXX get rid of pop here, use ... reg, mem32
+ __ pop_f(xmm1);
+ __ ucomiss(xmm1, xmm0);
+ } else {
+ // XXX get rid of pop here, use ... reg, mem64
+ __ pop_d(xmm1);
+ __ ucomisd(xmm1, xmm0);
+ }
+ if (unordered_result < 0) {
+ __ movl(rax, -1);
+ __ jccb(Assembler::parity, done);
+ __ jccb(Assembler::below, done);
+ __ setb(Assembler::notEqual, rdx);
+ __ movzbl(rax, rdx);
+ } else {
+ __ movl(rax, 1);
+ __ jccb(Assembler::parity, done);
+ __ jccb(Assembler::above, done);
+ __ movl(rax, 0);
+ __ jccb(Assembler::equal, done);
+ __ decrementl(rax);
+ }
+ __ bind(done);
} else {
- __ movl(rax, 1);
- __ jccb(Assembler::parity, done);
- __ jccb(Assembler::above, done);
- __ movl(rax, 0);
- __ jccb(Assembler::equal, done);
- __ decrementl(rax);
- }
- __ bind(done);
+#ifdef _LP64
+ ShouldNotReachHere();
#else
- if (is_float) {
- __ fld_s(at_rsp());
- } else {
- __ fld_d(at_rsp());
- __ pop(rdx);
+ if (is_float) {
+ __ fld_s(at_rsp());
+ } else {
+ __ fld_d(at_rsp());
+ __ pop(rdx);
+ }
+ __ pop(rcx);
+ __ fcmp2int(rax, unordered_result < 0);
+#endif // _LP64
}
- __ pop(rcx);
- __ fcmp2int(rax, unordered_result < 0);
-#endif
}
void TemplateTable::branch(bool is_jsr, bool is_wide) {
@@ -2014,6 +2113,7 @@
__ pop(rcx);
__ pop(rdx);
__ movptr(rax, Address(rcx, Method::method_counters_offset()));
+ __ testptr(rax, rax);
__ jcc(Assembler::zero, dispatch);
__ bind(has_counters);
@@ -2747,8 +2847,7 @@
__ jcc(Assembler::notEqual, notFloat);
// ftos
- LP64_ONLY(__ movflt(xmm0, field));
- NOT_LP64(__ fld_s(field));
+ __ load_float(field);
__ push(ftos);
// Rewrite bytecode to be faster
if (!is_static && rc == may_rewrite) {
@@ -2762,8 +2861,7 @@
__ jcc(Assembler::notEqual, notDouble);
#endif
// dtos
- LP64_ONLY(__ movdbl(xmm0, field));
- NOT_LP64(__ fld_d(field));
+ __ load_double(field);
__ push(dtos);
// Rewrite bytecode to be faster
if (!is_static && rc == may_rewrite) {
@@ -3045,8 +3143,7 @@
{
__ pop(ftos);
if (!is_static) pop_and_check_object(obj);
- NOT_LP64( __ fstp_s(field);)
- LP64_ONLY( __ movflt(field, xmm0);)
+ __ store_float(field);
if (!is_static && rc == may_rewrite) {
patch_bytecode(Bytecodes::_fast_fputfield, bc, rbx, true, byte_no);
}
@@ -3063,8 +3160,7 @@
{
__ pop(dtos);
if (!is_static) pop_and_check_object(obj);
- NOT_LP64( __ fstp_d(field);)
- LP64_ONLY( __ movdbl(field, xmm0);)
+ __ store_double(field);
if (!is_static && rc == may_rewrite) {
patch_bytecode(Bytecodes::_fast_dputfield, bc, rbx, true, byte_no);
}
@@ -3122,8 +3218,8 @@
case Bytecodes::_fast_sputfield: // fall through
case Bytecodes::_fast_cputfield: // fall through
case Bytecodes::_fast_iputfield: __ push_i(rax); break;
- case Bytecodes::_fast_dputfield: __ push_d(); break;
- case Bytecodes::_fast_fputfield: __ push_f(); break;
+ case Bytecodes::_fast_dputfield: __ push(dtos); break;
+ case Bytecodes::_fast_fputfield: __ push(ftos); break;
case Bytecodes::_fast_lputfield: __ push_l(rax); break;
default:
@@ -3146,8 +3242,8 @@
case Bytecodes::_fast_sputfield: // fall through
case Bytecodes::_fast_cputfield: // fall through
case Bytecodes::_fast_iputfield: __ pop_i(rax); break;
- case Bytecodes::_fast_dputfield: __ pop_d(); break;
- case Bytecodes::_fast_fputfield: __ pop_f(); break;
+ case Bytecodes::_fast_dputfield: __ pop(dtos); break;
+ case Bytecodes::_fast_fputfield: __ pop(ftos); break;
case Bytecodes::_fast_lputfield: __ pop_l(rax); break;
}
__ bind(L2);
@@ -3211,12 +3307,10 @@
__ movw(field, rax);
break;
case Bytecodes::_fast_fputfield:
- NOT_LP64( __ fstp_s(field); )
- LP64_ONLY( __ movflt(field, xmm0);)
+ __ store_float(field);
break;
case Bytecodes::_fast_dputfield:
- NOT_LP64( __ fstp_d(field); )
- LP64_ONLY( __ movdbl(field, xmm0);)
+ __ store_double(field);
break;
default:
ShouldNotReachHere();
@@ -3301,12 +3395,10 @@
__ load_unsigned_short(rax, field);
break;
case Bytecodes::_fast_fgetfield:
- LP64_ONLY(__ movflt(xmm0, field));
- NOT_LP64(__ fld_s(field));
+ __ load_float(field);
break;
case Bytecodes::_fast_dgetfield:
- LP64_ONLY(__ movdbl(xmm0, field));
- NOT_LP64(__ fld_d(field));
+ __ load_double(field);
break;
default:
ShouldNotReachHere();
@@ -3346,8 +3438,7 @@
__ verify_oop(rax);
break;
case ftos:
- LP64_ONLY(__ movflt(xmm0, field));
- NOT_LP64(__ fld_s(field));
+ __ load_float(field);
break;
default:
ShouldNotReachHere();
--- a/hotspot/src/os/aix/vm/perfMemory_aix.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/os/aix/vm/perfMemory_aix.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012, 2013 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -454,13 +454,27 @@
*saved_cwd_fd = result;
}
- // Set the current directory to dirname by using the fd of the directory.
+ // Set the current directory to dirname by using the fd of the directory and
+ // handle errors, otherwise shared memory files will be created in cwd.
result = fchdir(fd);
-
- return dirp;
+ if (result == OS_ERR) {
+ if (PrintMiscellaneous && Verbose) {
+ warning("could not change to directory %s", dirname);
+ }
+ if (*saved_cwd_fd != -1) {
+ ::close(*saved_cwd_fd);
+ *saved_cwd_fd = -1;
+ }
+ // Close the directory.
+ os::closedir(dirp);
+ return NULL;
+ } else {
+ return dirp;
+ }
}
// Close the directory and restore the current working directory.
+//
static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) {
int result;
--- a/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -375,10 +375,23 @@
*saved_cwd_fd = result;
}
- // Set the current directory to dirname by using the fd of the directory.
+ // Set the current directory to dirname by using the fd of the directory and
+ // handle errors, otherwise shared memory files will be created in cwd.
result = fchdir(fd);
-
- return dirp;
+ if (result == OS_ERR) {
+ if (PrintMiscellaneous && Verbose) {
+ warning("could not change to directory %s", dirname);
+ }
+ if (*saved_cwd_fd != -1) {
+ ::close(*saved_cwd_fd);
+ *saved_cwd_fd = -1;
+ }
+ // Close the directory.
+ os::closedir(dirp);
+ return NULL;
+ } else {
+ return dirp;
+ }
}
// Close the directory and restore the current working directory.
--- a/hotspot/src/os/linux/vm/os_linux.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -5785,9 +5785,11 @@
status = pthread_mutex_unlock(_mutex);
assert(status == 0, "invariant");
} else {
+ // must capture correct index before unlocking
+ int index = _cur_index;
status = pthread_mutex_unlock(_mutex);
assert(status == 0, "invariant");
- status = pthread_cond_signal(&_cond[_cur_index]);
+ status = pthread_cond_signal(&_cond[index]);
assert(status == 0, "invariant");
}
} else {
--- a/hotspot/src/os/linux/vm/perfMemory_linux.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/os/linux/vm/perfMemory_linux.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -374,10 +374,23 @@
*saved_cwd_fd = result;
}
- // Set the current directory to dirname by using the fd of the directory.
+ // Set the current directory to dirname by using the fd of the directory and
+ // handle errors, otherwise shared memory files will be created in cwd.
result = fchdir(fd);
-
- return dirp;
+ if (result == OS_ERR) {
+ if (PrintMiscellaneous && Verbose) {
+ warning("could not change to directory %s", dirname);
+ }
+ if (*saved_cwd_fd != -1) {
+ ::close(*saved_cwd_fd);
+ *saved_cwd_fd = -1;
+ }
+ // Close the directory.
+ os::closedir(dirp);
+ return NULL;
+ } else {
+ return dirp;
+ }
}
// Close the directory and restore the current working directory.
--- a/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -377,10 +377,23 @@
*saved_cwd_fd = result;
}
- // Set the current directory to dirname by using the fd of the directory.
+ // Set the current directory to dirname by using the fd of the directory and
+ // handle errors, otherwise shared memory files will be created in cwd.
result = fchdir(fd);
-
- return dirp;
+ if (result == OS_ERR) {
+ if (PrintMiscellaneous && Verbose) {
+ warning("could not change to directory %s", dirname);
+ }
+ if (*saved_cwd_fd != -1) {
+ ::close(*saved_cwd_fd);
+ *saved_cwd_fd = -1;
+ }
+ // Close the directory.
+ os::closedir(dirp);
+ return NULL;
+ } else {
+ return dirp;
+ }
}
// Close the directory and restore the current working directory.
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -2680,187 +2680,3 @@
#endif // INCLUDE_TRACE
}
-#ifndef PRODUCT
-
-// statistics code
-class ClassStatistics: AllStatic {
- private:
- static int nclasses; // number of classes
- static int nmethods; // number of methods
- static int nmethoddata; // number of methodData
- static int class_size; // size of class objects in words
- static int method_size; // size of method objects in words
- static int debug_size; // size of debug info in methods
- static int methoddata_size; // size of methodData objects in words
-
- static void do_class(Klass* k) {
- nclasses++;
- class_size += k->size();
- if (k->oop_is_instance()) {
- InstanceKlass* ik = (InstanceKlass*)k;
- class_size += ik->methods()->size();
- class_size += ik->constants()->size();
- class_size += ik->local_interfaces()->size();
- class_size += ik->transitive_interfaces()->size();
- // We do not have to count implementors, since we only store one!
- // SSS: How should these be accounted now that they have moved?
- // class_size += ik->fields()->length();
- }
- }
-
- static void do_method(Method* m) {
- nmethods++;
- method_size += m->size();
- // class loader uses same objArray for empty vectors, so don't count these
- if (m->has_stackmap_table()) {
- method_size += m->stackmap_data()->size();
- }
-
- MethodData* mdo = m->method_data();
- if (mdo != NULL) {
- nmethoddata++;
- methoddata_size += mdo->size();
- }
- }
-
- public:
- static void print() {
- SystemDictionary::classes_do(do_class);
- SystemDictionary::methods_do(do_method);
- tty->print_cr("Class statistics:");
- tty->print_cr("%d classes (%d bytes)", nclasses, class_size * oopSize);
- tty->print_cr("%d methods (%d bytes = %d base + %d debug info)", nmethods,
- (method_size + debug_size) * oopSize, method_size * oopSize, debug_size * oopSize);
- tty->print_cr("%d methoddata (%d bytes)", nmethoddata, methoddata_size * oopSize);
- }
-};
-
-
-int ClassStatistics::nclasses = 0;
-int ClassStatistics::nmethods = 0;
-int ClassStatistics::nmethoddata = 0;
-int ClassStatistics::class_size = 0;
-int ClassStatistics::method_size = 0;
-int ClassStatistics::debug_size = 0;
-int ClassStatistics::methoddata_size = 0;
-
-void SystemDictionary::print_class_statistics() {
- ResourceMark rm;
- ClassStatistics::print();
-}
-
-
-class MethodStatistics: AllStatic {
- public:
- enum {
- max_parameter_size = 10
- };
- private:
-
- static int _number_of_methods;
- static int _number_of_final_methods;
- static int _number_of_static_methods;
- static int _number_of_native_methods;
- static int _number_of_synchronized_methods;
- static int _number_of_profiled_methods;
- static int _number_of_bytecodes;
- static int _parameter_size_profile[max_parameter_size];
- static int _bytecodes_profile[Bytecodes::number_of_java_codes];
-
- static void initialize() {
- _number_of_methods = 0;
- _number_of_final_methods = 0;
- _number_of_static_methods = 0;
- _number_of_native_methods = 0;
- _number_of_synchronized_methods = 0;
- _number_of_profiled_methods = 0;
- _number_of_bytecodes = 0;
- for (int i = 0; i < max_parameter_size ; i++) _parameter_size_profile[i] = 0;
- for (int j = 0; j < Bytecodes::number_of_java_codes; j++) _bytecodes_profile [j] = 0;
- };
-
- static void do_method(Method* m) {
- _number_of_methods++;
- // collect flag info
- if (m->is_final() ) _number_of_final_methods++;
- if (m->is_static() ) _number_of_static_methods++;
- if (m->is_native() ) _number_of_native_methods++;
- if (m->is_synchronized()) _number_of_synchronized_methods++;
- if (m->method_data() != NULL) _number_of_profiled_methods++;
- // collect parameter size info (add one for receiver, if any)
- _parameter_size_profile[MIN2(m->size_of_parameters() + (m->is_static() ? 0 : 1), max_parameter_size - 1)]++;
- // collect bytecodes info
- {
- Thread *thread = Thread::current();
- HandleMark hm(thread);
- BytecodeStream s(methodHandle(thread, m));
- Bytecodes::Code c;
- while ((c = s.next()) >= 0) {
- _number_of_bytecodes++;
- _bytecodes_profile[c]++;
- }
- }
- }
-
- public:
- static void print() {
- initialize();
- SystemDictionary::methods_do(do_method);
- // generate output
- tty->cr();
- tty->print_cr("Method statistics (static):");
- // flag distribution
- tty->cr();
- tty->print_cr("%6d final methods %6.1f%%", _number_of_final_methods , _number_of_final_methods * 100.0F / _number_of_methods);
- tty->print_cr("%6d static methods %6.1f%%", _number_of_static_methods , _number_of_static_methods * 100.0F / _number_of_methods);
- tty->print_cr("%6d native methods %6.1f%%", _number_of_native_methods , _number_of_native_methods * 100.0F / _number_of_methods);
- tty->print_cr("%6d synchronized methods %6.1f%%", _number_of_synchronized_methods, _number_of_synchronized_methods * 100.0F / _number_of_methods);
- tty->print_cr("%6d profiled methods %6.1f%%", _number_of_profiled_methods, _number_of_profiled_methods * 100.0F / _number_of_methods);
- // parameter size profile
- tty->cr();
- { int tot = 0;
- int avg = 0;
- for (int i = 0; i < max_parameter_size; i++) {
- int n = _parameter_size_profile[i];
- tot += n;
- avg += n*i;
- tty->print_cr("parameter size = %1d: %6d methods %5.1f%%", i, n, n * 100.0F / _number_of_methods);
- }
- assert(tot == _number_of_methods, "should be the same");
- tty->print_cr(" %6d methods 100.0%%", _number_of_methods);
- tty->print_cr("(average parameter size = %3.1f including receiver, if any)", (float)avg / _number_of_methods);
- }
- // bytecodes profile
- tty->cr();
- { int tot = 0;
- for (int i = 0; i < Bytecodes::number_of_java_codes; i++) {
- if (Bytecodes::is_defined(i)) {
- Bytecodes::Code c = Bytecodes::cast(i);
- int n = _bytecodes_profile[c];
- tot += n;
- tty->print_cr("%9d %7.3f%% %s", n, n * 100.0F / _number_of_bytecodes, Bytecodes::name(c));
- }
- }
- assert(tot == _number_of_bytecodes, "should be the same");
- tty->print_cr("%9d 100.000%%", _number_of_bytecodes);
- }
- tty->cr();
- }
-};
-
-int MethodStatistics::_number_of_methods;
-int MethodStatistics::_number_of_final_methods;
-int MethodStatistics::_number_of_static_methods;
-int MethodStatistics::_number_of_native_methods;
-int MethodStatistics::_number_of_synchronized_methods;
-int MethodStatistics::_number_of_profiled_methods;
-int MethodStatistics::_number_of_bytecodes;
-int MethodStatistics::_parameter_size_profile[MethodStatistics::max_parameter_size];
-int MethodStatistics::_bytecodes_profile[Bytecodes::number_of_java_codes];
-
-
-void SystemDictionary::print_method_statistics() {
- MethodStatistics::print();
-}
-
-#endif // PRODUCT
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -366,8 +366,6 @@
// Printing
static void print(bool details = true);
static void print_shared(bool details = true);
- static void print_class_statistics() PRODUCT_RETURN;
- static void print_method_statistics() PRODUCT_RETURN;
// Number of contained klasses
// This is both fully loaded classes and classes in the process
--- a/hotspot/src/share/vm/code/codeCache.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/code/codeCache.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -746,14 +746,17 @@
void CodeCache::gc_epilogue() {
assert_locked_or_safepoint(CodeCache_lock);
NMethodIterator iter;
- while(iter.next_alive()) {
+ while(iter.next()) {
nmethod* nm = iter.method();
- assert(!nm->is_unloaded(), "Tautology");
- if (needs_cache_clean()) {
- nm->cleanup_inline_caches();
+ if (!nm->is_zombie()) {
+ if (needs_cache_clean()) {
+ // Clean ICs of unloaded nmethods as well because they may reference other
+ // unloaded nmethods that may be flushed earlier in the sweeper cycle.
+ nm->cleanup_inline_caches();
+ }
+ DEBUG_ONLY(nm->verify());
+ DEBUG_ONLY(nm->verify_oop_relocations());
}
- DEBUG_ONLY(nm->verify());
- DEBUG_ONLY(nm->verify_oop_relocations());
}
set_needs_cache_clean(false);
prune_scavenge_root_nmethods();
@@ -993,29 +996,6 @@
return number_of_marked_CodeBlobs;
}
-void CodeCache::make_marked_nmethods_zombies() {
- assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
- NMethodIterator iter;
- while(iter.next_alive()) {
- nmethod* nm = iter.method();
- if (nm->is_marked_for_deoptimization()) {
-
- // If the nmethod has already been made non-entrant and it can be converted
- // then zombie it now. Otherwise make it non-entrant and it will eventually
- // be zombied when it is no longer seen on the stack. Note that the nmethod
- // might be "entrant" and not on the stack and so could be zombied immediately
- // but we can't tell because we don't track it on stack until it becomes
- // non-entrant.
-
- if (nm->is_not_entrant() && nm->can_not_entrant_be_converted()) {
- nm->make_zombie();
- } else {
- nm->make_not_entrant();
- }
- }
- }
-}
-
void CodeCache::make_marked_nmethods_not_entrant() {
assert_locked_or_safepoint(CodeCache_lock);
NMethodIterator iter;
@@ -1072,7 +1052,7 @@
// Deoptimize all activations depending on marked nmethods
Deoptimization::deoptimize_dependents();
- // Make the dependent methods not entrant (in VM_Deoptimize they are made zombies)
+ // Make the dependent methods not entrant
make_marked_nmethods_not_entrant();
}
}
@@ -1102,7 +1082,7 @@
// Deoptimize all activations depending on marked nmethods
Deoptimization::deoptimize_dependents();
- // Make the dependent methods not entrant (in VM_Deoptimize they are made zombies)
+ // Make the dependent methods not entrant
make_marked_nmethods_not_entrant();
}
}
--- a/hotspot/src/share/vm/code/codeCache.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/code/codeCache.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -225,7 +225,6 @@
public:
static void mark_all_nmethods_for_deoptimization();
static int mark_for_deoptimization(Method* dependee);
- static void make_marked_nmethods_zombies();
static void make_marked_nmethods_not_entrant();
// Flushing and deoptimization
--- a/hotspot/src/share/vm/code/compiledIC.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/code/compiledIC.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -343,8 +343,8 @@
// Kill any leftover stub we might have too
clear_ic_stub();
if (is_optimized()) {
- set_ic_destination(entry);
- } else {
+ set_ic_destination(entry);
+ } else {
set_ic_destination_and_value(entry, (void*)NULL);
}
} else {
--- a/hotspot/src/share/vm/code/compiledIC.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/code/compiledIC.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -214,7 +214,7 @@
//
// They all takes a TRAP argument, since they can cause a GC if the inline-cache buffer is full.
//
- void set_to_clean(); // Can only be called during a safepoint operation
+ void set_to_clean();
void set_to_monomorphic(CompiledICInfo& info);
void clear_ic_stub();
--- a/hotspot/src/share/vm/code/nmethod.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/code/nmethod.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -1021,7 +1021,6 @@
void nmethod::cleanup_inline_caches() {
-
assert_locked_or_safepoint(CompiledIC_lock);
// If the method is not entrant or zombie then a JMP is plastered over the
@@ -1037,7 +1036,8 @@
// In fact, why are we bothering to look at oops in a non-entrant method??
}
- // Find all calls in an nmethod, and clear the ones that points to zombie methods
+ // Find all calls in an nmethod and clear the ones that point to non-entrant,
+ // zombie and unloaded nmethods.
ResourceMark rm;
RelocIterator iter(this, low_boundary);
while(iter.next()) {
@@ -1049,7 +1049,7 @@
CodeBlob *cb = CodeCache::find_blob_unsafe(ic->ic_destination());
if( cb != NULL && cb->is_nmethod() ) {
nmethod* nm = (nmethod*)cb;
- // Clean inline caches pointing to both zombie and not_entrant methods
+ // Clean inline caches pointing to zombie, non-entrant and unloaded methods
if (!nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean();
}
break;
@@ -1059,7 +1059,7 @@
CodeBlob *cb = CodeCache::find_blob_unsafe(csc->destination());
if( cb != NULL && cb->is_nmethod() ) {
nmethod* nm = (nmethod*)cb;
- // Clean inline caches pointing to both zombie and not_entrant methods
+ // Clean inline caches pointing to zombie, non-entrant and unloaded methods
if (!nm->is_in_use() || (nm->method()->code() != nm)) csc->set_to_clean();
}
break;
@@ -2529,7 +2529,7 @@
// Hmm. OSR methods can be deopted but not marked as zombie or not_entrant
// seems odd.
- if( is_zombie() || is_not_entrant() )
+ if (is_zombie() || is_not_entrant() || is_unloaded())
return;
// Make sure all the entry points are correctly aligned for patching.
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -1399,6 +1399,28 @@
// do the compilation
if (method->is_native()) {
if (!PreferInterpreterNativeStubs || method->is_method_handle_intrinsic()) {
+ // The following native methods:
+ //
+ // java.lang.Float.intBitsToFloat
+ // java.lang.Float.floatToRawIntBits
+ // java.lang.Double.longBitsToDouble
+ // java.lang.Double.doubleToRawLongBits
+ //
+ // are called through the interpreter even if interpreter native stubs
+ // are not preferred (i.e., calling through adapter handlers is preferred).
+ // The reason is that on x86_32 signaling NaNs (sNaNs) are not preserved
+ // if the version of the methods from the native libraries is called.
+ // As the interpreter and the C2-intrinsified version of the methods preserves
+ // sNaNs, that would result in an inconsistent way of handling of sNaNs.
+ if ((UseSSE >= 1 &&
+ (method->intrinsic_id() == vmIntrinsics::_intBitsToFloat ||
+ method->intrinsic_id() == vmIntrinsics::_floatToRawIntBits)) ||
+ (UseSSE >= 2 &&
+ (method->intrinsic_id() == vmIntrinsics::_longBitsToDouble ||
+ method->intrinsic_id() == vmIntrinsics::_doubleToRawLongBits))) {
+ return NULL;
+ }
+
// To properly handle the appendix argument for out-of-line calls we are using a small trampoline that
// pops off the appendix argument and jumps to the target (see gen_special_dispatch in SharedRuntime).
//
--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -620,7 +620,7 @@
// Support for parallelizing survivor space rescan
if ((CMSParallelRemarkEnabled && CMSParallelSurvivorRemarkEnabled) || CMSParallelInitialMarkEnabled) {
const size_t max_plab_samples =
- _young_gen->max_survivor_size() / (ThreadLocalAllocBuffer::min_size() * HeapWordSize);
+ _young_gen->max_survivor_size() / (PLAB::min_size() * HeapWordSize);
_survivor_plab_array = NEW_C_HEAP_ARRAY(ChunkArray, ParallelGCThreads, mtGC);
_survivor_chunk_array = NEW_C_HEAP_ARRAY(HeapWord*, max_plab_samples, mtGC);
@@ -3005,7 +3005,7 @@
COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;)
if (CMSParallelInitialMarkEnabled) {
// The parallel version.
- FlexibleWorkGang* workers = gch->workers();
+ WorkGang* workers = gch->workers();
assert(workers != NULL, "Need parallel worker threads.");
uint n_workers = workers->active_workers();
@@ -4488,7 +4488,7 @@
// workers to be taken from the active workers in the work gang.
CMSParRemarkTask(CMSCollector* collector,
CompactibleFreeListSpace* cms_space,
- uint n_workers, FlexibleWorkGang* workers,
+ uint n_workers, WorkGang* workers,
OopTaskQueueSet* task_queues,
StrongRootsScope* strong_roots_scope):
CMSParMarkTask("Rescan roots and grey objects in parallel",
@@ -5061,7 +5061,7 @@
// Parallel version of remark
void CMSCollector::do_remark_parallel() {
GenCollectedHeap* gch = GenCollectedHeap::heap();
- FlexibleWorkGang* workers = gch->workers();
+ WorkGang* workers = gch->workers();
assert(workers != NULL, "Need parallel worker threads.");
// Choose to use the number of GC workers most recently set
// into "active_workers".
@@ -5236,6 +5236,16 @@
////////////////////////////////////////////////////////
// Parallel Reference Processing Task Proxy Class
////////////////////////////////////////////////////////
+class AbstractGangTaskWOopQueues : public AbstractGangTask {
+ OopTaskQueueSet* _queues;
+ ParallelTaskTerminator _terminator;
+ public:
+ AbstractGangTaskWOopQueues(const char* name, OopTaskQueueSet* queues, uint n_threads) :
+ AbstractGangTask(name), _queues(queues), _terminator(n_threads, _queues) {}
+ ParallelTaskTerminator* terminator() { return &_terminator; }
+ OopTaskQueueSet* queues() { return _queues; }
+};
+
class CMSRefProcTaskProxy: public AbstractGangTaskWOopQueues {
typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
CMSCollector* _collector;
@@ -5372,7 +5382,7 @@
void CMSRefProcTaskExecutor::execute(ProcessTask& task)
{
GenCollectedHeap* gch = GenCollectedHeap::heap();
- FlexibleWorkGang* workers = gch->workers();
+ WorkGang* workers = gch->workers();
assert(workers != NULL, "Need parallel worker threads.");
CMSRefProcTaskProxy rp_task(task, &_collector,
_collector.ref_processor()->span(),
@@ -5385,7 +5395,7 @@
{
GenCollectedHeap* gch = GenCollectedHeap::heap();
- FlexibleWorkGang* workers = gch->workers();
+ WorkGang* workers = gch->workers();
assert(workers != NULL, "Need parallel worker threads.");
CMSRefEnqueueTaskProxy enq_task(task);
workers->run_task(&enq_task);
@@ -5419,7 +5429,7 @@
// balance_all_queues() and balance_queues()).
GenCollectedHeap* gch = GenCollectedHeap::heap();
uint active_workers = ParallelGCThreads;
- FlexibleWorkGang* workers = gch->workers();
+ WorkGang* workers = gch->workers();
if (workers != NULL) {
active_workers = workers->active_workers();
// The expectation is that active_workers will have already
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -25,7 +25,7 @@
#include "precompiled.hpp"
#include "gc/cms/compactibleFreeListSpace.hpp"
#include "gc/cms/concurrentMarkSweepGeneration.hpp"
-#include "gc/cms/parNewGeneration.hpp"
+#include "gc/cms/parNewGeneration.inline.hpp"
#include "gc/cms/parOopClosures.inline.hpp"
#include "gc/serial/defNewGeneration.inline.hpp"
#include "gc/shared/adaptiveSizePolicy.hpp"
@@ -248,8 +248,7 @@
}
}
if (buf_space != NULL) {
- plab->set_word_size(buf_size);
- plab->set_buf(buf_space);
+ plab->set_buf(buf_space, buf_size);
record_survivor_plab(buf_space, buf_size);
obj = plab->allocate_aligned(word_sz, SurvivorAlignmentInBytes);
// Note that we cannot compare buf_size < word_sz below
@@ -803,7 +802,7 @@
void ParNewRefProcTaskExecutor::execute(ProcessTask& task)
{
GenCollectedHeap* gch = GenCollectedHeap::heap();
- FlexibleWorkGang* workers = gch->workers();
+ WorkGang* workers = gch->workers();
assert(workers != NULL, "Need parallel worker threads.");
_state_set.reset(workers->active_workers(), _young_gen.promotion_failed());
ParNewRefProcTaskProxy rp_task(task, _young_gen, _old_gen,
@@ -816,7 +815,7 @@
void ParNewRefProcTaskExecutor::execute(EnqueueTask& task)
{
GenCollectedHeap* gch = GenCollectedHeap::heap();
- FlexibleWorkGang* workers = gch->workers();
+ WorkGang* workers = gch->workers();
assert(workers != NULL, "Need parallel worker threads.");
ParNewRefEnqueueTaskProxy enq_task(task);
workers->run_task(&enq_task);
@@ -890,7 +889,7 @@
_gc_timer->register_gc_start();
AdaptiveSizePolicy* size_policy = gch->gen_policy()->size_policy();
- FlexibleWorkGang* workers = gch->workers();
+ WorkGang* workers = gch->workers();
assert(workers != NULL, "Need workgang for parallel work");
uint active_workers =
AdaptiveSizePolicy::calc_active_workers(workers->total_workers(),
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -169,11 +169,7 @@
// Allocate a to-space block of size "sz", or else return NULL.
HeapWord* alloc_in_to_space_slow(size_t word_sz);
- HeapWord* alloc_in_to_space(size_t word_sz) {
- HeapWord* obj = to_space_alloc_buffer()->allocate_aligned(word_sz, SurvivorAlignmentInBytes);
- if (obj != NULL) return obj;
- else return alloc_in_to_space_slow(word_sz);
- }
+ inline HeapWord* alloc_in_to_space(size_t word_sz);
HeapWord* young_old_boundary() { return _young_old_boundary; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.inline.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_GC_CMS_PARNEWGENERATION_INLINE_HPP
+#define SHARE_VM_GC_CMS_PARNEWGENERATION_INLINE_HPP
+
+#include "gc/cms/parNewGeneration.hpp"
+#include "gc/shared/plab.inline.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+inline HeapWord* ParScanThreadState::alloc_in_to_space(size_t word_sz) {
+ HeapWord* obj = to_space_alloc_buffer()->allocate_aligned(word_sz, SurvivorAlignmentInBytes);
+ if (obj != NULL) return obj;
+ else return alloc_in_to_space_slow(word_sz);
+}
+#endif // SHARE_VM_GC_CMS_PARNEWGENERATION_INLINE_HPP
--- a/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -26,20 +26,45 @@
#include "gc/cms/yieldingWorkgroup.hpp"
#include "utilities/macros.hpp"
-// Forward declaration of classes declared here.
-
-class GangWorker;
-class WorkData;
+YieldingFlexibleGangWorker::YieldingFlexibleGangWorker(YieldingFlexibleWorkGang* gang, int id)
+ : AbstractGangWorker(gang, id) {}
YieldingFlexibleWorkGang::YieldingFlexibleWorkGang(
- const char* name, uint workers, bool are_GC_task_threads) :
- FlexibleWorkGang(name, workers, are_GC_task_threads, false),
- _yielded_workers(0) {}
+ const char* name, uint workers, bool are_GC_task_threads) :
+ AbstractWorkGang(name, workers, are_GC_task_threads, false),
+ _yielded_workers(0),
+ _started_workers(0),
+ _finished_workers(0),
+ _sequence_number(0),
+ _task(NULL) {
+
+ // Other initialization.
+ _monitor = new Monitor(/* priority */ Mutex::leaf,
+ /* name */ "WorkGroup monitor",
+ /* allow_vm_block */ are_GC_task_threads,
+ Monitor::_safepoint_check_sometimes);
+
+ assert(monitor() != NULL, "Failed to allocate monitor");
+}
-GangWorker* YieldingFlexibleWorkGang::allocate_worker(uint which) {
- YieldingFlexibleGangWorker* new_member =
- new YieldingFlexibleGangWorker(this, which);
- return (YieldingFlexibleGangWorker*) new_member;
+AbstractGangWorker* YieldingFlexibleWorkGang::allocate_worker(uint which) {
+ return new YieldingFlexibleGangWorker(this, which);
+}
+
+void YieldingFlexibleWorkGang::internal_worker_poll(YieldingWorkData* data) const {
+ assert(data != NULL, "worker data is null");
+ data->set_task(task());
+ data->set_sequence_number(sequence_number());
+}
+
+void YieldingFlexibleWorkGang::internal_note_start() {
+ assert(monitor()->owned_by_self(), "note_finish is an internal method");
+ _started_workers += 1;
+}
+
+void YieldingFlexibleWorkGang::internal_note_finish() {
+ assert(monitor()->owned_by_self(), "note_finish is an internal method");
+ _finished_workers += 1;
}
// Run a task; returns when the task is done, or the workers yield,
@@ -292,37 +317,37 @@
///////////////////////////////
void YieldingFlexibleGangWorker::loop() {
int previous_sequence_number = 0;
- Monitor* gang_monitor = gang()->monitor();
+ Monitor* gang_monitor = yf_gang()->monitor();
MutexLockerEx ml(gang_monitor, Mutex::_no_safepoint_check_flag);
- WorkData data;
+ YieldingWorkData data;
int id;
while (true) {
// Check if there is work to do.
- gang()->internal_worker_poll(&data);
+ yf_gang()->internal_worker_poll(&data);
if (data.task() != NULL && data.sequence_number() != previous_sequence_number) {
// There is work to be done.
// First check if we need to become active or if there
// are already the requisite number of workers
- if (gang()->started_workers() == yf_gang()->active_workers()) {
+ if (yf_gang()->started_workers() == yf_gang()->active_workers()) {
// There are already enough workers, we do not need to
// to run; fall through and wait on monitor.
} else {
// We need to pitch in and do the work.
- assert(gang()->started_workers() < yf_gang()->active_workers(),
+ assert(yf_gang()->started_workers() < yf_gang()->active_workers(),
"Unexpected state");
- id = gang()->started_workers();
- gang()->internal_note_start();
+ id = yf_gang()->started_workers();
+ yf_gang()->internal_note_start();
// Now, release the gang mutex and do the work.
{
MutexUnlockerEx mul(gang_monitor, Mutex::_no_safepoint_check_flag);
data.task()->work(id); // This might include yielding
}
// Reacquire monitor and note completion of this worker
- gang()->internal_note_finish();
+ yf_gang()->internal_note_finish();
// Update status of task based on whether all workers have
// finished or some have yielded
- assert(data.task() == gang()->task(), "Confused task binding");
- if (gang()->finished_workers() == yf_gang()->active_workers()) {
+ assert(data.task() == yf_gang()->task(), "Confused task binding");
+ if (yf_gang()->finished_workers() == yf_gang()->active_workers()) {
switch (data.yf_task()->status()) {
case ABORTING: {
data.yf_task()->set_status(ABORTED);
@@ -338,7 +363,7 @@
}
gang_monitor->notify_all(); // Notify overseer
} else { // at least one worker is still working or yielded
- assert(gang()->finished_workers() < yf_gang()->active_workers(),
+ assert(yf_gang()->finished_workers() < yf_gang()->active_workers(),
"Counts inconsistent");
switch (data.yf_task()->status()) {
case ACTIVE: {
@@ -347,7 +372,7 @@
break;
}
case YIELDING: {
- if (gang()->finished_workers() + yf_gang()->yielded_workers()
+ if (yf_gang()->finished_workers() + yf_gang()->yielded_workers()
== yf_gang()->active_workers()) {
data.yf_task()->set_status(YIELDED);
gang_monitor->notify_all(); // notify overseer
--- a/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -29,6 +29,7 @@
#include "utilities/macros.hpp"
// Forward declarations
+class YieldingFlexibleGangTask;
class YieldingFlexibleWorkGang;
// Status of tasks
@@ -43,13 +44,32 @@
COMPLETED
};
+class YieldingWorkData: public StackObj {
+ // This would be a struct, but I want accessor methods.
+private:
+ AbstractGangTask* _task;
+ int _sequence_number;
+public:
+ // Constructor and destructor
+ YieldingWorkData() : _task(NULL), _sequence_number(0) {}
+ ~YieldingWorkData() {}
+
+ // Accessors and modifiers
+ AbstractGangTask* task() const { return _task; }
+ void set_task(AbstractGangTask* value) { _task = value; }
+ int sequence_number() const { return _sequence_number; }
+ void set_sequence_number(int value) { _sequence_number = value; }
+
+ YieldingFlexibleGangTask* yf_task() const {
+ return (YieldingFlexibleGangTask*)_task;
+ }
+};
+
// Class YieldingFlexibleGangWorker:
// Several instances of this class run in parallel as workers for a gang.
-class YieldingFlexibleGangWorker: public GangWorker {
+class YieldingFlexibleGangWorker: public AbstractGangWorker {
public:
- // Ctor
- YieldingFlexibleGangWorker(AbstractWorkGang* gang, int id) :
- GangWorker(gang, id) { }
+ YieldingFlexibleGangWorker(YieldingFlexibleWorkGang* gang, int id);
public:
YieldingFlexibleWorkGang* yf_gang() const
@@ -108,9 +128,6 @@
friend class YieldingFlexibleWorkGang;
friend class YieldingFlexibleGangWorker;
- NOT_PRODUCT(virtual bool is_YieldingFlexibleGang_task() const {
- return true;
- })
void set_status(Status s) {
_status = s;
@@ -160,7 +177,7 @@
// YieldingGangWorkers, and provides infrastructure
// supporting yielding to the "GangOverseer",
// being the thread that orchestrates the WorkGang via run_task().
-class YieldingFlexibleWorkGang: public FlexibleWorkGang {
+class YieldingFlexibleWorkGang: public AbstractWorkGang {
// Here's the public interface to this class.
public:
// Constructor and destructor.
@@ -168,12 +185,10 @@
bool are_GC_task_threads);
YieldingFlexibleGangTask* yielding_task() const {
- assert(task() == NULL || task()->is_YieldingFlexibleGang_task(),
- "Incorrect cast");
- return (YieldingFlexibleGangTask*)task();
+ return task();
}
// Allocate a worker and return a pointer to it.
- GangWorker* allocate_worker(uint which);
+ AbstractGangWorker* allocate_worker(uint which);
// Run a task; returns when the task is done, or the workers yield,
// or the task is aborted.
@@ -216,6 +231,42 @@
private:
friend class YieldingFlexibleGangWorker;
void reset(); // NYI
+
+
+ // The monitor which protects these data,
+ // and notifies of changes in it.
+ Monitor* _monitor;
+ // Accessors for fields
+ Monitor* monitor() const {
+ return _monitor;
+ }
+
+ // The number of started workers.
+ uint _started_workers;
+ // The number of finished workers.
+ uint _finished_workers;
+
+ uint started_workers() const {
+ return _started_workers;
+ }
+ uint finished_workers() const {
+ return _finished_workers;
+ }
+
+ // A sequence number for the current task.
+ int _sequence_number;
+ int sequence_number() const {
+ return _sequence_number;
+ }
+
+ YieldingFlexibleGangTask* _task;
+ YieldingFlexibleGangTask* task() const {
+ return _task;
+ }
+
+ void internal_worker_poll(YieldingWorkData* data) const;
+ void internal_note_start();
+ void internal_note_finish();
};
#endif // SHARE_VM_GC_CMS_YIELDINGWORKGROUP_HPP
--- a/hotspot/src/share/vm/gc/g1/concurrentMark.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/concurrentMark.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -629,7 +629,7 @@
gclog_or_tty->print_cr("CL Sleep Factor %1.4lf", cleanup_sleep_factor());
#endif
- _parallel_workers = new FlexibleWorkGang("G1 Marker",
+ _parallel_workers = new WorkGang("G1 Marker",
_max_parallel_marking_threads, false, true);
if (_parallel_workers == NULL) {
vm_exit_during_initialization("Failed necessary allocation.");
@@ -3088,29 +3088,6 @@
}
#endif
-template<bool scan>
-inline void CMTask::process_grey_object(oop obj) {
- assert(scan || obj->is_typeArray(), "Skipping scan of grey non-typeArray");
- assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant");
-
- if (_cm->verbose_high()) {
- gclog_or_tty->print_cr("[%u] processing grey object " PTR_FORMAT,
- _worker_id, p2i((void*) obj));
- }
-
- size_t obj_size = obj->size();
- _words_scanned += obj_size;
-
- if (scan) {
- obj->oop_iterate(_cm_oop_closure);
- }
- statsOnly( ++_objs_scanned );
- check_limits();
-}
-
-template void CMTask::process_grey_object<true>(oop);
-template void CMTask::process_grey_object<false>(oop);
-
// Closure for iteration over bitmaps
class CMBitMapClosure : public BitMapClosure {
private:
--- a/hotspot/src/share/vm/gc/g1/concurrentMark.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/concurrentMark.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -451,7 +451,7 @@
double* _accum_task_vtime; // Accumulated task vtime
- FlexibleWorkGang* _parallel_workers;
+ WorkGang* _parallel_workers;
ForceOverflowSettings _force_overflow_conc;
ForceOverflowSettings _force_overflow_stw;
@@ -1126,7 +1126,7 @@
inline void deal_with_reference(oop obj);
// It scans an object and visits its children.
- void scan_object(oop obj) { process_grey_object<true>(obj); }
+ inline void scan_object(oop obj);
// It pushes an object on the local queue.
inline void push(oop obj);
--- a/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -232,6 +232,9 @@
}
}
+// It scans an object and visits its children.
+inline void CMTask::scan_object(oop obj) { process_grey_object<true>(obj); }
+
inline void CMTask::push(oop obj) {
HeapWord* objAddr = (HeapWord*) obj;
assert(_g1h->is_in_g1_reserved(objAddr), "invariant");
@@ -299,6 +302,28 @@
return objAddr < global_finger;
}
+template<bool scan>
+inline void CMTask::process_grey_object(oop obj) {
+ assert(scan || obj->is_typeArray(), "Skipping scan of grey non-typeArray");
+ assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant");
+
+ if (_cm->verbose_high()) {
+ gclog_or_tty->print_cr("[%u] processing grey object " PTR_FORMAT,
+ _worker_id, p2i((void*) obj));
+ }
+
+ size_t obj_size = obj->size();
+ _words_scanned += obj_size;
+
+ if (scan) {
+ obj->oop_iterate(_cm_oop_closure);
+ }
+ statsOnly( ++_objs_scanned );
+ check_limits();
+}
+
+
+
inline void CMTask::make_reference_grey(oop obj, HeapRegion* hr) {
if (_cm->par_mark_and_count(obj, hr, _marked_bytes_array, _card_bm)) {
--- a/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -46,10 +46,11 @@
_dummy_region = dummy_region;
}
-void G1AllocRegion::fill_up_remaining_space(HeapRegion* alloc_region,
- bool bot_updates) {
+size_t G1AllocRegion::fill_up_remaining_space(HeapRegion* alloc_region,
+ bool bot_updates) {
assert(alloc_region != NULL && alloc_region != _dummy_region,
"pre-condition");
+ size_t result = 0;
// Other threads might still be trying to allocate using a CAS out
// of the region we are trying to retire, as they can do so without
@@ -73,6 +74,7 @@
// If the allocation was successful we should fill in the space.
CollectedHeap::fill_with_object(dummy, free_word_size);
alloc_region->set_pre_dummy_top(dummy);
+ result += free_word_size * HeapWordSize;
break;
}
@@ -81,13 +83,18 @@
// allocation and they fill up the region. In that case, we can
// just get out of the loop.
}
+ result += alloc_region->free();
+
assert(alloc_region->free() / HeapWordSize < min_word_size_to_fill,
"post-condition");
+ return result;
}
-void G1AllocRegion::retire(bool fill_up) {
+size_t G1AllocRegion::retire(bool fill_up) {
assert(_alloc_region != NULL, ar_ext_msg(this, "not initialized properly"));
+ size_t result = 0;
+
trace("retiring");
HeapRegion* alloc_region = _alloc_region;
if (alloc_region != _dummy_region) {
@@ -98,7 +105,7 @@
ar_ext_msg(this, "the alloc region should never be empty"));
if (fill_up) {
- fill_up_remaining_space(alloc_region, _bot_updates);
+ result = fill_up_remaining_space(alloc_region, _bot_updates);
}
assert(alloc_region->used() >= _used_bytes_before,
@@ -109,6 +116,8 @@
_alloc_region = _dummy_region;
}
trace("retired");
+
+ return result;
}
HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size,
@@ -196,11 +205,11 @@
}
#if G1_ALLOC_REGION_TRACING
-void G1AllocRegion::trace(const char* str, size_t word_size, HeapWord* result) {
+void G1AllocRegion::trace(const char* str, size_t min_word_size, size_t desired_word_size, size_t actual_word_size, HeapWord* result) {
// All the calls to trace that set either just the size or the size
// and the result are considered part of level 2 tracing and are
// skipped during level 1 tracing.
- if ((word_size == 0 && result == NULL) || (G1_ALLOC_REGION_TRACING > 1)) {
+ if ((actual_word_size == 0 && result == NULL) || (G1_ALLOC_REGION_TRACING > 1)) {
const size_t buffer_length = 128;
char hr_buffer[buffer_length];
char rest_buffer[buffer_length];
@@ -217,10 +226,10 @@
if (G1_ALLOC_REGION_TRACING > 1) {
if (result != NULL) {
- jio_snprintf(rest_buffer, buffer_length, SIZE_FORMAT " " PTR_FORMAT,
- word_size, result);
- } else if (word_size != 0) {
- jio_snprintf(rest_buffer, buffer_length, SIZE_FORMAT, word_size);
+ jio_snprintf(rest_buffer, buffer_length, "min " SIZE_FORMAT " desired " SIZE_FORMAT " actual " SIZE_FORMAT " " PTR_FORMAT,
+ min_word_size, desired_word_size, actual_word_size, result);
+ } else if (min_word_size != 0) {
+ jio_snprintf(rest_buffer, buffer_length, "min " SIZE_FORMAT " desired " SIZE_FORMAT, min_word_size, desired_word_size);
} else {
jio_snprintf(rest_buffer, buffer_length, "");
}
@@ -251,26 +260,25 @@
_g1h->retire_mutator_alloc_region(alloc_region, allocated_bytes);
}
-HeapRegion* SurvivorGCAllocRegion::allocate_new_region(size_t word_size,
- bool force) {
+HeapRegion* G1GCAllocRegion::allocate_new_region(size_t word_size,
+ bool force) {
assert(!force, "not supported for GC alloc regions");
- return _g1h->new_gc_alloc_region(word_size, count(), InCSetState::Young);
+ return _g1h->new_gc_alloc_region(word_size, count(), _purpose);
}
-void SurvivorGCAllocRegion::retire_region(HeapRegion* alloc_region,
- size_t allocated_bytes) {
- _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, InCSetState::Young);
+void G1GCAllocRegion::retire_region(HeapRegion* alloc_region,
+ size_t allocated_bytes) {
+ _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, _purpose);
}
-HeapRegion* OldGCAllocRegion::allocate_new_region(size_t word_size,
- bool force) {
- assert(!force, "not supported for GC alloc regions");
- return _g1h->new_gc_alloc_region(word_size, count(), InCSetState::Old);
-}
-
-void OldGCAllocRegion::retire_region(HeapRegion* alloc_region,
- size_t allocated_bytes) {
- _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, InCSetState::Old);
+size_t G1GCAllocRegion::retire(bool fill_up) {
+ HeapRegion* retired = get();
+ size_t end_waste = G1AllocRegion::retire(fill_up);
+ // Do not count retirement of the dummy allocation region.
+ if (retired != NULL) {
+ _stats->add_region_end_waste(end_waste / HeapWordSize);
+ }
+ return end_waste;
}
HeapRegion* OldGCAllocRegion::release() {
--- a/hotspot/src/share/vm/gc/g1/g1AllocRegion.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1AllocRegion.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -26,6 +26,8 @@
#define SHARE_VM_GC_G1_G1ALLOCREGION_HPP
#include "gc/g1/heapRegion.hpp"
+#include "gc/g1/g1EvacStats.hpp"
+#include "gc/g1/g1InCSetState.hpp"
class G1CollectedHeap;
@@ -102,16 +104,22 @@
static inline HeapWord* par_allocate(HeapRegion* alloc_region,
size_t word_size,
bool bot_updates);
+ // Perform a MT-safe allocation out of the given region, with the given
+ // minimum and desired size. Returns the actual size allocated (between
+ // minimum and desired size) in actual_word_size if the allocation has been
+ // successful.
+ static inline HeapWord* par_allocate(HeapRegion* alloc_region,
+ size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size,
+ bool bot_updates);
// Ensure that the region passed as a parameter has been filled up
// so that noone else can allocate out of it any more.
- static void fill_up_remaining_space(HeapRegion* alloc_region,
- bool bot_updates);
-
- // Retire the active allocating region. If fill_up is true then make
- // sure that the region is full before we retire it so that noone
- // else can allocate out of it.
- void retire(bool fill_up);
+ // Returns the number of bytes that have been wasted by filled up
+ // the space.
+ static size_t fill_up_remaining_space(HeapRegion* alloc_region,
+ bool bot_updates);
// After a region is allocated by alloc_new_region, this
// method is used to set it as the active alloc_region
@@ -126,6 +134,12 @@
void fill_in_ext_msg(ar_ext_msg* msg, const char* message);
protected:
+ // Retire the active allocating region. If fill_up is true then make
+ // sure that the region is full before we retire it so that no one
+ // else can allocate out of it.
+ // Returns the number of bytes that have been filled up during retire.
+ virtual size_t retire(bool fill_up);
+
// For convenience as subclasses use it.
static G1CollectedHeap* _g1h;
@@ -154,7 +168,18 @@
// First-level allocation: Should be called without holding a
// lock. It will try to allocate lock-free out of the active region,
// or return NULL if it was unable to.
- inline HeapWord* attempt_allocation(size_t word_size, bool bot_updates);
+ inline HeapWord* attempt_allocation(size_t word_size,
+ bool bot_updates);
+ // Perform an allocation out of the current allocation region, with the given
+ // minimum and desired size. Returns the actual size allocated (between
+ // minimum and desired size) in actual_word_size if the allocation has been
+ // successful.
+ // Should be called without holding a lock. It will try to allocate lock-free
+ // out of the active region, or return NULL if it was unable to.
+ inline HeapWord* attempt_allocation(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size,
+ bool bot_updates);
// Second-level allocation: Should be called while holding a
// lock. It will try to first allocate lock-free out of the active
@@ -164,6 +189,14 @@
// it conform to its locking protocol.
inline HeapWord* attempt_allocation_locked(size_t word_size,
bool bot_updates);
+ // Same as attempt_allocation_locked(size_t, bool), but allowing specification
+ // of minimum word size of the block in min_word_size, and the maximum word
+ // size of the allocation in desired_word_size. The actual size of the block is
+ // returned in actual_word_size.
+ inline HeapWord* attempt_allocation_locked(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size,
+ bool bot_updates);
// Should be called to allocate a new region even if the max of this
// type of regions has been reached. Should only be called if other
@@ -186,9 +219,17 @@
virtual HeapRegion* release();
#if G1_ALLOC_REGION_TRACING
- void trace(const char* str, size_t word_size = 0, HeapWord* result = NULL);
+ void trace(const char* str,
+ size_t min_word_size = 0,
+ size_t desired_word_size = 0,
+ size_t actual_word_size = 0,
+ HeapWord* result = NULL);
#else // G1_ALLOC_REGION_TRACING
- void trace(const char* str, size_t word_size = 0, HeapWord* result = NULL) { }
+ void trace(const char* str,
+ size_t min_word_size = 0,
+ size_t desired_word_size = 0,
+ size_t actual_word_size = 0,
+ HeapWord* result = NULL) { }
#endif // G1_ALLOC_REGION_TRACING
};
@@ -201,22 +242,33 @@
: G1AllocRegion("Mutator Alloc Region", false /* bot_updates */) { }
};
-class SurvivorGCAllocRegion : public G1AllocRegion {
+// Common base class for allocation regions used during GC.
+class G1GCAllocRegion : public G1AllocRegion {
protected:
+ G1EvacStats* _stats;
+ InCSetState::in_cset_state_t _purpose;
+
virtual HeapRegion* allocate_new_region(size_t word_size, bool force);
virtual void retire_region(HeapRegion* alloc_region, size_t allocated_bytes);
+
+ virtual size_t retire(bool fill_up);
public:
- SurvivorGCAllocRegion()
- : G1AllocRegion("Survivor GC Alloc Region", false /* bot_updates */) { }
+ G1GCAllocRegion(const char* name, bool bot_updates, G1EvacStats* stats, InCSetState::in_cset_state_t purpose)
+ : G1AllocRegion(name, bot_updates), _stats(stats), _purpose(purpose) {
+ assert(stats != NULL, "Must pass non-NULL PLAB statistics");
+ }
};
-class OldGCAllocRegion : public G1AllocRegion {
-protected:
- virtual HeapRegion* allocate_new_region(size_t word_size, bool force);
- virtual void retire_region(HeapRegion* alloc_region, size_t allocated_bytes);
+class SurvivorGCAllocRegion : public G1GCAllocRegion {
public:
- OldGCAllocRegion()
- : G1AllocRegion("Old GC Alloc Region", true /* bot_updates */) { }
+ SurvivorGCAllocRegion(G1EvacStats* stats)
+ : G1GCAllocRegion("Survivor GC Alloc Region", false /* bot_updates */, stats, InCSetState::Young) { }
+};
+
+class OldGCAllocRegion : public G1GCAllocRegion {
+public:
+ OldGCAllocRegion(G1EvacStats* stats)
+ : G1GCAllocRegion("Old GC Alloc Region", true /* bot_updates */, stats, InCSetState::Old) { }
// This specialization of release() makes sure that the last card that has
// been allocated into has been completely filled by a dummy object. This
--- a/hotspot/src/share/vm/gc/g1/g1AllocRegion.inline.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1AllocRegion.inline.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -40,52 +40,74 @@
}
}
+inline HeapWord* G1AllocRegion::par_allocate(HeapRegion* alloc_region, size_t word_size, bool bot_updates) {
+ size_t temp;
+ return par_allocate(alloc_region, word_size, word_size, &temp, bot_updates);
+}
+
inline HeapWord* G1AllocRegion::par_allocate(HeapRegion* alloc_region,
- size_t word_size,
+ size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size,
bool bot_updates) {
assert(alloc_region != NULL, err_msg("pre-condition"));
assert(!alloc_region->is_empty(), err_msg("pre-condition"));
if (!bot_updates) {
- return alloc_region->par_allocate_no_bot_updates(word_size);
+ return alloc_region->par_allocate_no_bot_updates(min_word_size, desired_word_size, actual_word_size);
} else {
- return alloc_region->par_allocate(word_size);
+ return alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size);
}
}
-inline HeapWord* G1AllocRegion::attempt_allocation(size_t word_size,
+inline HeapWord* G1AllocRegion::attempt_allocation(size_t word_size, bool bot_updates) {
+ size_t temp;
+ return attempt_allocation(word_size, word_size, &temp, bot_updates);
+}
+
+inline HeapWord* G1AllocRegion::attempt_allocation(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size,
bool bot_updates) {
assert(bot_updates == _bot_updates, ar_ext_msg(this, "pre-condition"));
HeapRegion* alloc_region = _alloc_region;
assert(alloc_region != NULL, ar_ext_msg(this, "not initialized properly"));
- HeapWord* result = par_allocate(alloc_region, word_size, bot_updates);
+ HeapWord* result = par_allocate(alloc_region, min_word_size, desired_word_size, actual_word_size, bot_updates);
if (result != NULL) {
- trace("alloc", word_size, result);
+ trace("alloc", min_word_size, desired_word_size, *actual_word_size, result);
return result;
}
- trace("alloc failed", word_size);
+ trace("alloc failed", min_word_size, desired_word_size);
return NULL;
}
-inline HeapWord* G1AllocRegion::attempt_allocation_locked(size_t word_size,
+inline HeapWord* G1AllocRegion::attempt_allocation_locked(size_t word_size, bool bot_updates) {
+ size_t temp;
+ return attempt_allocation_locked(word_size, word_size, &temp, bot_updates);
+}
+
+inline HeapWord* G1AllocRegion::attempt_allocation_locked(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size,
bool bot_updates) {
// First we have to redo the allocation, assuming we're holding the
// appropriate lock, in case another thread changed the region while
// we were waiting to get the lock.
- HeapWord* result = attempt_allocation(word_size, bot_updates);
+ HeapWord* result = attempt_allocation(min_word_size, desired_word_size, actual_word_size, bot_updates);
if (result != NULL) {
return result;
}
retire(true /* fill_up */);
- result = new_alloc_region_and_allocate(word_size, false /* force */);
+ result = new_alloc_region_and_allocate(desired_word_size, false /* force */);
if (result != NULL) {
- trace("alloc locked (second attempt)", word_size, result);
+ *actual_word_size = desired_word_size;
+ trace("alloc locked (second attempt)", min_word_size, desired_word_size, *actual_word_size, result);
return result;
}
- trace("alloc locked failed", word_size);
+ trace("alloc locked failed", min_word_size, desired_word_size);
return NULL;
}
@@ -94,13 +116,13 @@
assert(bot_updates == _bot_updates, ar_ext_msg(this, "pre-condition"));
assert(_alloc_region != NULL, ar_ext_msg(this, "not initialized properly"));
- trace("forcing alloc");
+ trace("forcing alloc", word_size, word_size);
HeapWord* result = new_alloc_region_and_allocate(word_size, true /* force */);
if (result != NULL) {
- trace("alloc forced", word_size, result);
+ trace("alloc forced", word_size, word_size, word_size, result);
return result;
}
- trace("alloc forced failed", word_size);
+ trace("alloc forced failed", word_size, word_size);
return NULL;
}
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -24,12 +24,20 @@
#include "precompiled.hpp"
#include "gc/g1/g1Allocator.inline.hpp"
+#include "gc/g1/g1AllocRegion.inline.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CollectorPolicy.hpp"
#include "gc/g1/g1MarkSweep.hpp"
#include "gc/g1/heapRegion.inline.hpp"
#include "gc/g1/heapRegionSet.inline.hpp"
+G1DefaultAllocator::G1DefaultAllocator(G1CollectedHeap* heap) :
+ G1Allocator(heap),
+ _retained_old_gc_alloc_region(NULL),
+ _survivor_gc_alloc_region(heap->alloc_buffer_stats(InCSetState::Young)),
+ _old_gc_alloc_region(heap->alloc_buffer_stats(InCSetState::Old)) {
+}
+
void G1DefaultAllocator::init_mutator_alloc_region() {
assert(_mutator_alloc_region.get() == NULL, "pre-condition");
_mutator_alloc_region.init();
@@ -79,6 +87,8 @@
void G1DefaultAllocator::init_gc_alloc_regions(EvacuationInfo& evacuation_info) {
assert_at_safepoint(true /* should_be_vm_thread */);
+ G1Allocator::init_gc_alloc_regions(evacuation_info);
+
_survivor_gc_alloc_region.init();
_old_gc_alloc_region.init();
reuse_retained_old_region(evacuation_info,
@@ -101,10 +111,8 @@
_retained_old_gc_alloc_region->record_retained_region();
}
- if (ResizePLAB) {
- _g1h->alloc_buffer_stats(InCSetState::Young)->adjust_desired_plab_sz();
- _g1h->alloc_buffer_stats(InCSetState::Old)->adjust_desired_plab_sz();
- }
+ _g1h->alloc_buffer_stats(InCSetState::Young)->adjust_desired_plab_sz();
+ _g1h->alloc_buffer_stats(InCSetState::Old)->adjust_desired_plab_sz();
}
void G1DefaultAllocator::abandon_gc_alloc_regions() {
@@ -136,78 +144,159 @@
HeapWord* G1Allocator::par_allocate_during_gc(InCSetState dest,
size_t word_size,
AllocationContext_t context) {
+ size_t temp = 0;
+ HeapWord* result = par_allocate_during_gc(dest, word_size, word_size, &temp, context);
+ assert(result == NULL || temp == word_size,
+ err_msg("Requested " SIZE_FORMAT " words, but got " SIZE_FORMAT " at " PTR_FORMAT,
+ word_size, temp, p2i(result)));
+ return result;
+}
+
+HeapWord* G1Allocator::par_allocate_during_gc(InCSetState dest,
+ size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size,
+ AllocationContext_t context) {
switch (dest.value()) {
case InCSetState::Young:
- return survivor_attempt_allocation(word_size, context);
+ return survivor_attempt_allocation(min_word_size, desired_word_size, actual_word_size, context);
case InCSetState::Old:
- return old_attempt_allocation(word_size, context);
+ return old_attempt_allocation(min_word_size, desired_word_size, actual_word_size, context);
default:
ShouldNotReachHere();
return NULL; // Keep some compilers happy
}
}
-HeapWord* G1Allocator::survivor_attempt_allocation(size_t word_size,
+bool G1Allocator::survivor_is_full(AllocationContext_t context) const {
+ return _survivor_is_full;
+}
+
+bool G1Allocator::old_is_full(AllocationContext_t context) const {
+ return _old_is_full;
+}
+
+void G1Allocator::set_survivor_full(AllocationContext_t context) {
+ _survivor_is_full = true;
+}
+
+void G1Allocator::set_old_full(AllocationContext_t context) {
+ _old_is_full = true;
+}
+
+HeapWord* G1Allocator::survivor_attempt_allocation(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size,
AllocationContext_t context) {
- assert(!_g1h->is_humongous(word_size),
+ assert(!_g1h->is_humongous(desired_word_size),
"we should not be seeing humongous-size allocations in this path");
- HeapWord* result = survivor_gc_alloc_region(context)->attempt_allocation(word_size,
+ HeapWord* result = survivor_gc_alloc_region(context)->attempt_allocation(min_word_size,
+ desired_word_size,
+ actual_word_size,
false /* bot_updates */);
- if (result == NULL) {
+ if (result == NULL && !survivor_is_full(context)) {
MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag);
- result = survivor_gc_alloc_region(context)->attempt_allocation_locked(word_size,
+ result = survivor_gc_alloc_region(context)->attempt_allocation_locked(min_word_size,
+ desired_word_size,
+ actual_word_size,
false /* bot_updates */);
+ if (result == NULL) {
+ set_survivor_full(context);
+ }
}
if (result != NULL) {
- _g1h->dirty_young_block(result, word_size);
+ _g1h->dirty_young_block(result, *actual_word_size);
}
return result;
}
-HeapWord* G1Allocator::old_attempt_allocation(size_t word_size,
+HeapWord* G1Allocator::old_attempt_allocation(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size,
AllocationContext_t context) {
- assert(!_g1h->is_humongous(word_size),
+ assert(!_g1h->is_humongous(desired_word_size),
"we should not be seeing humongous-size allocations in this path");
- HeapWord* result = old_gc_alloc_region(context)->attempt_allocation(word_size,
+ HeapWord* result = old_gc_alloc_region(context)->attempt_allocation(min_word_size,
+ desired_word_size,
+ actual_word_size,
true /* bot_updates */);
- if (result == NULL) {
+ if (result == NULL && !old_is_full(context)) {
MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag);
- result = old_gc_alloc_region(context)->attempt_allocation_locked(word_size,
+ result = old_gc_alloc_region(context)->attempt_allocation_locked(min_word_size,
+ desired_word_size,
+ actual_word_size,
true /* bot_updates */);
+ if (result == NULL) {
+ set_old_full(context);
+ }
}
return result;
}
+void G1Allocator::init_gc_alloc_regions(EvacuationInfo& evacuation_info) {
+ _survivor_is_full = false;
+ _old_is_full = false;
+}
+
G1PLABAllocator::G1PLABAllocator(G1Allocator* allocator) :
_g1h(G1CollectedHeap::heap()),
_allocator(allocator),
_survivor_alignment_bytes(calc_survivor_alignment_bytes()) {
+ for (size_t i = 0; i < ARRAY_SIZE(_direct_allocated); i++) {
+ _direct_allocated[i] = 0;
+ }
+}
+
+bool G1PLABAllocator::may_throw_away_buffer(size_t const allocation_word_sz, size_t const buffer_size) const {
+ return (allocation_word_sz * 100 < buffer_size * ParallelGCBufferWastePct);
}
HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(InCSetState dest,
size_t word_sz,
- AllocationContext_t context) {
- size_t gclab_word_size = _g1h->desired_plab_sz(dest);
- if (word_sz * 100 < gclab_word_size * ParallelGCBufferWastePct) {
+ AllocationContext_t context,
+ bool* plab_refill_failed) {
+ size_t plab_word_size = G1CollectedHeap::heap()->desired_plab_sz(dest);
+ size_t required_in_plab = PLAB::size_required_for_allocation(word_sz);
+
+ // Only get a new PLAB if the allocation fits and it would not waste more than
+ // ParallelGCBufferWastePct in the existing buffer.
+ if ((required_in_plab <= plab_word_size) &&
+ may_throw_away_buffer(required_in_plab, plab_word_size)) {
+
G1PLAB* alloc_buf = alloc_buffer(dest, context);
alloc_buf->retire();
- HeapWord* buf = _allocator->par_allocate_during_gc(dest, gclab_word_size, context);
- if (buf == NULL) {
- return NULL; // Let caller handle allocation failure.
+ size_t actual_plab_size = 0;
+ HeapWord* buf = _allocator->par_allocate_during_gc(dest,
+ required_in_plab,
+ plab_word_size,
+ &actual_plab_size,
+ context);
+
+ assert(buf == NULL || ((actual_plab_size >= required_in_plab) && (actual_plab_size <= plab_word_size)),
+ err_msg("Requested at minimum " SIZE_FORMAT ", desired " SIZE_FORMAT " words, but got " SIZE_FORMAT " at " PTR_FORMAT,
+ required_in_plab, plab_word_size, actual_plab_size, p2i(buf)));
+
+ if (buf != NULL) {
+ alloc_buf->set_buf(buf, actual_plab_size);
+
+ HeapWord* const obj = alloc_buf->allocate(word_sz);
+ assert(obj != NULL, err_msg("PLAB should have been big enough, tried to allocate "
+ SIZE_FORMAT " requiring " SIZE_FORMAT " PLAB size " SIZE_FORMAT,
+ word_sz, required_in_plab, plab_word_size));
+ return obj;
}
// Otherwise.
- alloc_buf->set_word_size(gclab_word_size);
- alloc_buf->set_buf(buf);
-
- HeapWord* const obj = alloc_buf->allocate(word_sz);
- assert(obj != NULL, "buffer was definitely big enough...");
- return obj;
- } else {
- return _allocator->par_allocate_during_gc(dest, word_sz, context);
+ *plab_refill_failed = true;
}
+ // Try direct allocation.
+ HeapWord* result = _allocator->par_allocate_during_gc(dest, word_sz, context);
+ if (result != NULL) {
+ _direct_allocated[dest.value()] += word_sz;
+ }
+ return result;
}
void G1PLABAllocator::undo_allocation(InCSetState dest, HeapWord* obj, size_t word_sz, AllocationContext_t context) {
@@ -225,11 +314,14 @@
_alloc_buffers[InCSetState::Old] = &_tenured_alloc_buffer;
}
-void G1DefaultPLABAllocator::retire_alloc_buffers() {
+void G1DefaultPLABAllocator::flush_and_retire_stats() {
for (uint state = 0; state < InCSetState::Num; state++) {
G1PLAB* const buf = _alloc_buffers[state];
if (buf != NULL) {
- buf->flush_and_retire_stats(_g1h->alloc_buffer_stats(state));
+ G1EvacStats* stats = _g1h->alloc_buffer_stats(state);
+ buf->flush_and_retire_stats(stats);
+ stats->add_direct_allocated(_direct_allocated[state]);
+ _direct_allocated[state] = 0;
}
}
}
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -38,23 +38,36 @@
// Also keeps track of retained regions across GCs.
class G1Allocator : public CHeapObj<mtGC> {
friend class VMStructs;
+private:
+ bool _survivor_is_full;
+ bool _old_is_full;
protected:
G1CollectedHeap* _g1h;
virtual MutatorAllocRegion* mutator_alloc_region(AllocationContext_t context) = 0;
+ virtual bool survivor_is_full(AllocationContext_t context) const;
+ virtual bool old_is_full(AllocationContext_t context) const;
+
+ virtual void set_survivor_full(AllocationContext_t context);
+ virtual void set_old_full(AllocationContext_t context);
+
// Accessors to the allocation regions.
virtual SurvivorGCAllocRegion* survivor_gc_alloc_region(AllocationContext_t context) = 0;
virtual OldGCAllocRegion* old_gc_alloc_region(AllocationContext_t context) = 0;
// Allocation attempt during GC for a survivor object / PLAB.
- inline HeapWord* survivor_attempt_allocation(size_t word_size,
+ inline HeapWord* survivor_attempt_allocation(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size,
AllocationContext_t context);
// Allocation attempt during GC for an old object / PLAB.
- inline HeapWord* old_attempt_allocation(size_t word_size,
+ inline HeapWord* old_attempt_allocation(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size,
AllocationContext_t context);
public:
- G1Allocator(G1CollectedHeap* heap) : _g1h(heap) { }
+ G1Allocator(G1CollectedHeap* heap) : _g1h(heap), _survivor_is_full(false), _old_is_full(false) { }
virtual ~G1Allocator() { }
static G1Allocator* create_allocator(G1CollectedHeap* g1h);
@@ -66,7 +79,7 @@
virtual void init_mutator_alloc_region() = 0;
virtual void release_mutator_alloc_region() = 0;
- virtual void init_gc_alloc_regions(EvacuationInfo& evacuation_info) = 0;
+ virtual void init_gc_alloc_regions(EvacuationInfo& evacuation_info);
virtual void release_gc_alloc_regions(EvacuationInfo& evacuation_info) = 0;
virtual void abandon_gc_alloc_regions() = 0;
@@ -93,6 +106,12 @@
size_t word_size,
AllocationContext_t context);
+ HeapWord* par_allocate_during_gc(InCSetState dest,
+ size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size,
+ AllocationContext_t context);
+
virtual size_t used_in_alloc_regions() = 0;
};
@@ -114,7 +133,7 @@
HeapRegion* _retained_old_gc_alloc_region;
public:
- G1DefaultAllocator(G1CollectedHeap* heap) : G1Allocator(heap), _retained_old_gc_alloc_region(NULL) { }
+ G1DefaultAllocator(G1CollectedHeap* heap);
virtual void init_mutator_alloc_region();
virtual void release_mutator_alloc_region();
@@ -163,8 +182,12 @@
guarantee(_retired, "Allocation buffer has not been retired");
}
- virtual void set_buf(HeapWord* buf) {
- PLAB::set_buf(buf);
+ // The amount of space in words wasted within the PLAB including
+ // waste due to refills and alignment.
+ size_t wasted() const { return _wasted; }
+
+ virtual void set_buf(HeapWord* buf, size_t word_size) {
+ PLAB::set_buf(buf, word_size);
_retired = false;
}
@@ -198,7 +221,10 @@
// architectures have a special compare against zero instructions.
const uint _survivor_alignment_bytes;
- virtual void retire_alloc_buffers() = 0;
+ // Number of words allocated directly (not counting PLAB allocation).
+ size_t _direct_allocated[InCSetState::Num];
+
+ virtual void flush_and_retire_stats() = 0;
virtual G1PLAB* alloc_buffer(InCSetState dest, AllocationContext_t context) = 0;
// Calculate the survivor space object alignment in bytes. Returns that or 0 if
@@ -215,6 +241,11 @@
}
}
+ HeapWord* allocate_new_plab(InCSetState dest,
+ size_t word_sz,
+ AllocationContext_t context);
+
+ bool may_throw_away_buffer(size_t const allocation_word_sz, size_t const buffer_size) const;
public:
G1PLABAllocator(G1Allocator* allocator);
virtual ~G1PLABAllocator() { }
@@ -225,31 +256,28 @@
// Allocate word_sz words in dest, either directly into the regions or by
// allocating a new PLAB. Returns the address of the allocated memory, NULL if
- // not successful.
+ // not successful. Plab_refill_failed indicates whether an attempt to refill the
+ // PLAB failed or not.
HeapWord* allocate_direct_or_new_plab(InCSetState dest,
size_t word_sz,
- AllocationContext_t context);
+ AllocationContext_t context,
+ bool* plab_refill_failed);
// Allocate word_sz words in the PLAB of dest. Returns the address of the
// allocated memory, NULL if not successful.
- HeapWord* plab_allocate(InCSetState dest,
- size_t word_sz,
- AllocationContext_t context) {
- G1PLAB* buffer = alloc_buffer(dest, context);
- if (_survivor_alignment_bytes == 0 || !dest.is_young()) {
- return buffer->allocate(word_sz);
- } else {
- return buffer->allocate_aligned(word_sz, _survivor_alignment_bytes);
- }
- }
+ inline HeapWord* plab_allocate(InCSetState dest,
+ size_t word_sz,
+ AllocationContext_t context);
- HeapWord* allocate(InCSetState dest, size_t word_sz,
- AllocationContext_t context) {
+ HeapWord* allocate(InCSetState dest,
+ size_t word_sz,
+ AllocationContext_t context,
+ bool* refill_failed) {
HeapWord* const obj = plab_allocate(dest, word_sz, context);
if (obj != NULL) {
return obj;
}
- return allocate_direct_or_new_plab(dest, word_sz, context);
+ return allocate_direct_or_new_plab(dest, word_sz, context, refill_failed);
}
void undo_allocation(InCSetState dest, HeapWord* obj, size_t word_sz, AllocationContext_t context);
@@ -273,7 +301,7 @@
return _alloc_buffers[dest.value()];
}
- virtual void retire_alloc_buffers();
+ virtual void flush_and_retire_stats();
virtual void waste(size_t& wasted, size_t& undo_wasted);
};
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -27,6 +27,7 @@
#include "gc/g1/g1Allocator.hpp"
#include "gc/g1/g1AllocRegion.inline.hpp"
+#include "gc/shared/plab.inline.hpp"
HeapWord* G1Allocator::attempt_allocation(size_t word_size, AllocationContext_t context) {
return mutator_alloc_region(context)->attempt_allocation(word_size, false /* bot_updates */);
@@ -43,4 +44,15 @@
return mutator_alloc_region(context)->attempt_allocation_force(word_size, false /* bot_updates */);
}
+inline HeapWord* G1PLABAllocator::plab_allocate(InCSetState dest,
+ size_t word_sz,
+ AllocationContext_t context) {
+ G1PLAB* buffer = alloc_buffer(dest, context);
+ if (_survivor_alignment_bytes == 0 || !dest.is_young()) {
+ return buffer->allocate(word_sz);
+ } else {
+ return buffer->allocate_aligned(word_sz, _survivor_alignment_bytes);
+ }
+}
+
#endif // SHARE_VM_GC_G1_G1ALLOCATOR_HPP
--- a/hotspot/src/share/vm/gc/g1/g1Allocator_ext.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator_ext.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "gc/g1/g1Allocator.hpp"
+#include "gc/g1/g1Allocator.inline.hpp"
#include "gc/g1/g1CollectedHeap.hpp"
G1Allocator* G1Allocator::create_allocator(G1CollectedHeap* g1h) {
--- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.inline.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.inline.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -26,7 +26,7 @@
#define SHARE_VM_GC_G1_G1BLOCKOFFSETTABLE_INLINE_HPP
#include "gc/g1/g1BlockOffsetTable.hpp"
-#include "gc/g1/heapRegion.inline.hpp"
+#include "gc/g1/heapRegion.hpp"
#include "gc/shared/space.hpp"
inline HeapWord* G1BlockOffsetTable::block_start(const void* addr) {
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -1944,8 +1944,8 @@
_young_list(new YoungList(this)),
_gc_time_stamp(0),
_summary_bytes_used(0),
- _survivor_plab_stats(YoungPLABSize, PLABWeight),
- _old_plab_stats(OldPLABSize, PLABWeight),
+ _survivor_evac_stats(YoungPLABSize, PLABWeight),
+ _old_evac_stats(OldPLABSize, PLABWeight),
_expand_heap_after_alloc_failure(true),
_surviving_young_words(NULL),
_old_marking_cycles_started(0),
@@ -1960,7 +1960,7 @@
_gc_tracer_stw(new (ResourceObj::C_HEAP, mtGC) G1NewTracer()),
_gc_tracer_cm(new (ResourceObj::C_HEAP, mtGC) G1OldTracer()) {
- _workers = new FlexibleWorkGang("GC Thread", ParallelGCThreads,
+ _workers = new WorkGang("GC Thread", ParallelGCThreads,
/* are_GC_task_threads */true,
/* are_ConcurrentGC_threads */false);
_workers->initialize_workers();
@@ -3504,6 +3504,13 @@
return G1HeapSummary(heap_summary, used(), eden_used_bytes, eden_capacity_bytes, survivor_used_bytes);
}
+G1EvacSummary G1CollectedHeap::create_g1_evac_summary(G1EvacStats* stats) {
+ return G1EvacSummary(stats->allocated(), stats->wasted(), stats->undo_wasted(),
+ stats->unused(), stats->used(), stats->region_end_waste(),
+ stats->regions_filled(), stats->direct_allocated(),
+ stats->failure_used(), stats->failure_waste());
+}
+
void G1CollectedHeap::trace_heap(GCWhen::Type when, const GCTracer* gc_tracer) {
const G1HeapSummary& heap_summary = create_g1_heap_summary();
gc_tracer->report_gc_heap_summary(when, heap_summary);
@@ -3753,8 +3760,7 @@
cl.flush_rem_set_entries();
}
-void
-G1CollectedHeap::setup_surviving_young_words() {
+void G1CollectedHeap::setup_surviving_young_words() {
assert(_surviving_young_words == NULL, "pre-condition");
uint array_length = g1_policy()->young_cset_region_length();
_surviving_young_words = NEW_C_HEAP_ARRAY(size_t, (size_t) array_length, mtGC);
@@ -3770,17 +3776,15 @@
#endif // !ASSERT
}
-void
-G1CollectedHeap::update_surviving_young_words(size_t* surv_young_words) {
- MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
+void G1CollectedHeap::update_surviving_young_words(size_t* surv_young_words) {
+ assert_at_safepoint(true);
uint array_length = g1_policy()->young_cset_region_length();
for (uint i = 0; i < array_length; ++i) {
_surviving_young_words[i] += surv_young_words[i];
}
}
-void
-G1CollectedHeap::cleanup_surviving_young_words() {
+void G1CollectedHeap::cleanup_surviving_young_words() {
guarantee( _surviving_young_words != NULL, "pre-condition" );
FREE_C_HEAP_ARRAY(size_t, _surviving_young_words);
_surviving_young_words = NULL;
@@ -4375,6 +4379,13 @@
}
class G1ParEvacuateFollowersClosure : public VoidClosure {
+private:
+ double _start_term;
+ double _term_time;
+ size_t _term_attempts;
+
+ void start_term_time() { _term_attempts++; _start_term = os::elapsedTime(); }
+ void end_term_time() { _term_time += os::elapsedTime() - _start_term; }
protected:
G1CollectedHeap* _g1h;
G1ParScanThreadState* _par_scan_state;
@@ -4391,19 +4402,23 @@
RefToScanQueueSet* queues,
ParallelTaskTerminator* terminator)
: _g1h(g1h), _par_scan_state(par_scan_state),
- _queues(queues), _terminator(terminator) {}
+ _queues(queues), _terminator(terminator),
+ _start_term(0.0), _term_time(0.0), _term_attempts(0) {}
void do_void();
+ double term_time() const { return _term_time; }
+ size_t term_attempts() const { return _term_attempts; }
+
private:
inline bool offer_termination();
};
bool G1ParEvacuateFollowersClosure::offer_termination() {
G1ParScanThreadState* const pss = par_scan_state();
- pss->start_term_time();
+ start_term_time();
const bool res = terminator()->offer_termination();
- pss->end_term_time();
+ end_term_time();
return res;
}
@@ -4444,15 +4459,17 @@
class G1ParTask : public AbstractGangTask {
protected:
G1CollectedHeap* _g1h;
- RefToScanQueueSet *_queues;
+ G1ParScanThreadState** _pss;
+ RefToScanQueueSet* _queues;
G1RootProcessor* _root_processor;
ParallelTaskTerminator _terminator;
uint _n_workers;
public:
- G1ParTask(G1CollectedHeap* g1h, RefToScanQueueSet *task_queues, G1RootProcessor* root_processor, uint n_workers)
+ G1ParTask(G1CollectedHeap* g1h, G1ParScanThreadState** per_thread_states, RefToScanQueueSet *task_queues, G1RootProcessor* root_processor, uint n_workers)
: AbstractGangTask("G1 collection"),
_g1h(g1h),
+ _pss(per_thread_states),
_queues(task_queues),
_root_processor(root_processor),
_terminator(n_workers, _queues),
@@ -4499,7 +4516,8 @@
void work(uint worker_id) {
if (worker_id >= _n_workers) return; // no work needed this round
- _g1h->g1_policy()->phase_times()->record_time_secs(G1GCPhaseTimes::GCWorkerStart, worker_id, os::elapsedTime());
+ double start_sec = os::elapsedTime();
+ _g1h->g1_policy()->phase_times()->record_time_secs(G1GCPhaseTimes::GCWorkerStart, worker_id, start_sec);
{
ResourceMark rm;
@@ -4507,23 +4525,24 @@
ReferenceProcessor* rp = _g1h->ref_processor_stw();
- G1ParScanThreadState pss(_g1h, worker_id, rp);
+ G1ParScanThreadState* pss = _pss[worker_id];
+ pss->set_ref_processor(rp);
bool only_young = _g1h->collector_state()->gcs_are_young();
// Non-IM young GC.
- G1ParCopyClosure<G1BarrierNone, G1MarkNone> scan_only_root_cl(_g1h, &pss, rp);
+ G1ParCopyClosure<G1BarrierNone, G1MarkNone> scan_only_root_cl(_g1h, pss, rp);
G1CLDClosure<G1MarkNone> scan_only_cld_cl(&scan_only_root_cl,
only_young, // Only process dirty klasses.
false); // No need to claim CLDs.
// IM young GC.
// Strong roots closures.
- G1ParCopyClosure<G1BarrierNone, G1MarkFromRoot> scan_mark_root_cl(_g1h, &pss, rp);
+ G1ParCopyClosure<G1BarrierNone, G1MarkFromRoot> scan_mark_root_cl(_g1h, pss, rp);
G1CLDClosure<G1MarkFromRoot> scan_mark_cld_cl(&scan_mark_root_cl,
false, // Process all klasses.
true); // Need to claim CLDs.
// Weak roots closures.
- G1ParCopyClosure<G1BarrierNone, G1MarkPromotedFromRoot> scan_mark_weak_root_cl(_g1h, &pss, rp);
+ G1ParCopyClosure<G1BarrierNone, G1MarkPromotedFromRoot> scan_mark_weak_root_cl(_g1h, pss, rp);
G1CLDClosure<G1MarkPromotedFromRoot> scan_mark_weak_cld_cl(&scan_mark_weak_root_cl,
false, // Process all klasses.
true); // Need to claim CLDs.
@@ -4554,8 +4573,7 @@
weak_cld_cl = &scan_only_cld_cl;
}
- pss.start_strong_roots();
-
+ double start_strong_roots_sec = os::elapsedTime();
_root_processor->evacuate_roots(strong_root_cl,
weak_root_cl,
strong_cld_cl,
@@ -4563,32 +4581,45 @@
trace_metadata,
worker_id);
- G1ParPushHeapRSClosure push_heap_rs_cl(_g1h, &pss);
+ G1ParPushHeapRSClosure push_heap_rs_cl(_g1h, pss);
_root_processor->scan_remembered_sets(&push_heap_rs_cl,
weak_root_cl,
worker_id);
- pss.end_strong_roots();
-
+ double strong_roots_sec = os::elapsedTime() - start_strong_roots_sec;
+
+ double term_sec = 0.0;
+ size_t evac_term_attempts = 0;
{
double start = os::elapsedTime();
- G1ParEvacuateFollowersClosure evac(_g1h, &pss, _queues, &_terminator);
+ G1ParEvacuateFollowersClosure evac(_g1h, pss, _queues, &_terminator);
evac.do_void();
+
+ evac_term_attempts = evac.term_attempts();
+ term_sec = evac.term_time();
double elapsed_sec = os::elapsedTime() - start;
- double term_sec = pss.term_time();
_g1h->g1_policy()->phase_times()->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_id, elapsed_sec - term_sec);
_g1h->g1_policy()->phase_times()->record_time_secs(G1GCPhaseTimes::Termination, worker_id, term_sec);
- _g1h->g1_policy()->phase_times()->record_thread_work_item(G1GCPhaseTimes::Termination, worker_id, pss.term_attempts());
+ _g1h->g1_policy()->phase_times()->record_thread_work_item(G1GCPhaseTimes::Termination, worker_id, evac_term_attempts);
}
- _g1h->g1_policy()->record_thread_age_table(pss.age_table());
- _g1h->update_surviving_young_words(pss.surviving_young_words()+1);
+
+ assert(pss->queue_is_empty(), "should be empty");
if (PrintTerminationStats) {
MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
- pss.print_termination_stats();
+ size_t lab_waste;
+ size_t lab_undo_waste;
+ pss->waste(lab_waste, lab_undo_waste);
+ _g1h->print_termination_stats(gclog_or_tty,
+ worker_id,
+ (os::elapsedTime() - start_sec) * 1000.0, /* elapsed time */
+ strong_roots_sec * 1000.0, /* strong roots time */
+ term_sec * 1000.0, /* evac term time */
+ evac_term_attempts, /* evac term attempts */
+ lab_waste, /* alloc buffer waste */
+ lab_undo_waste /* undo waste */
+ );
}
- assert(pss.queue_is_empty(), "should be empty");
-
// Close the inner scope so that the ResourceMark and HandleMark
// destructors are executed here and are included as part of the
// "GC Worker Time".
@@ -4597,6 +4628,31 @@
}
};
+void G1CollectedHeap::print_termination_stats_hdr(outputStream* const st) {
+ st->print_raw_cr("GC Termination Stats");
+ st->print_raw_cr(" elapsed --strong roots-- -------termination------- ------waste (KiB)------");
+ st->print_raw_cr("thr ms ms % ms % attempts total alloc undo");
+ st->print_raw_cr("--- --------- --------- ------ --------- ------ -------- ------- ------- -------");
+}
+
+void G1CollectedHeap::print_termination_stats(outputStream* const st,
+ uint worker_id,
+ double elapsed_ms,
+ double strong_roots_ms,
+ double term_ms,
+ size_t term_attempts,
+ size_t alloc_buffer_waste,
+ size_t undo_waste) const {
+ st->print_cr("%3d %9.2f %9.2f %6.2f "
+ "%9.2f %6.2f " SIZE_FORMAT_W(8) " "
+ SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7),
+ worker_id, elapsed_ms, strong_roots_ms, strong_roots_ms * 100 / elapsed_ms,
+ term_ms, term_ms * 100 / elapsed_ms, term_attempts,
+ (alloc_buffer_waste + undo_waste) * HeapWordSize / K,
+ alloc_buffer_waste * HeapWordSize / K,
+ undo_waste * HeapWordSize / K);
+}
+
class G1StringSymbolTableUnlinkTask : public AbstractGangTask {
private:
BoolObjectClosure* _is_alive;
@@ -5125,17 +5181,20 @@
class G1STWRefProcTaskExecutor: public AbstractRefProcTaskExecutor {
private:
- G1CollectedHeap* _g1h;
- RefToScanQueueSet* _queues;
- FlexibleWorkGang* _workers;
- uint _active_workers;
+ G1CollectedHeap* _g1h;
+ G1ParScanThreadState** _pss;
+ RefToScanQueueSet* _queues;
+ WorkGang* _workers;
+ uint _active_workers;
public:
G1STWRefProcTaskExecutor(G1CollectedHeap* g1h,
- FlexibleWorkGang* workers,
+ G1ParScanThreadState** per_thread_states,
+ WorkGang* workers,
RefToScanQueueSet *task_queues,
uint n_workers) :
_g1h(g1h),
+ _pss(per_thread_states),
_queues(task_queues),
_workers(workers),
_active_workers(n_workers)
@@ -5154,17 +5213,20 @@
typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
ProcessTask& _proc_task;
G1CollectedHeap* _g1h;
- RefToScanQueueSet *_task_queues;
+ G1ParScanThreadState** _pss;
+ RefToScanQueueSet* _task_queues;
ParallelTaskTerminator* _terminator;
public:
G1STWRefProcTaskProxy(ProcessTask& proc_task,
- G1CollectedHeap* g1h,
- RefToScanQueueSet *task_queues,
- ParallelTaskTerminator* terminator) :
+ G1CollectedHeap* g1h,
+ G1ParScanThreadState** per_thread_states,
+ RefToScanQueueSet *task_queues,
+ ParallelTaskTerminator* terminator) :
AbstractGangTask("Process reference objects in parallel"),
_proc_task(proc_task),
_g1h(g1h),
+ _pss(per_thread_states),
_task_queues(task_queues),
_terminator(terminator)
{}
@@ -5176,11 +5238,12 @@
G1STWIsAliveClosure is_alive(_g1h);
- G1ParScanThreadState pss(_g1h, worker_id, NULL);
-
- G1ParScanExtRootClosure only_copy_non_heap_cl(_g1h, &pss, NULL);
-
- G1ParScanAndMarkExtRootClosure copy_mark_non_heap_cl(_g1h, &pss, NULL);
+ G1ParScanThreadState* pss = _pss[worker_id];
+ pss->set_ref_processor(NULL);
+
+ G1ParScanExtRootClosure only_copy_non_heap_cl(_g1h, pss, NULL);
+
+ G1ParScanAndMarkExtRootClosure copy_mark_non_heap_cl(_g1h, pss, NULL);
OopClosure* copy_non_heap_cl = &only_copy_non_heap_cl;
@@ -5190,10 +5253,10 @@
}
// Keep alive closure.
- G1CopyingKeepAliveClosure keep_alive(_g1h, copy_non_heap_cl, &pss);
+ G1CopyingKeepAliveClosure keep_alive(_g1h, copy_non_heap_cl, pss);
// Complete GC closure
- G1ParEvacuateFollowersClosure drain_queue(_g1h, &pss, _task_queues, _terminator);
+ G1ParEvacuateFollowersClosure drain_queue(_g1h, pss, _task_queues, _terminator);
// Call the reference processing task's work routine.
_proc_task.work(worker_id, is_alive, keep_alive, drain_queue);
@@ -5212,7 +5275,7 @@
assert(_workers != NULL, "Need parallel worker threads.");
ParallelTaskTerminator terminator(_active_workers, _queues);
- G1STWRefProcTaskProxy proc_task_proxy(proc_task, _g1h, _queues, &terminator);
+ G1STWRefProcTaskProxy proc_task_proxy(proc_task, _g1h, _pss, _queues, &terminator);
_workers->run_task(&proc_task_proxy);
}
@@ -5254,15 +5317,17 @@
class G1ParPreserveCMReferentsTask: public AbstractGangTask {
protected:
- G1CollectedHeap* _g1h;
- RefToScanQueueSet *_queues;
+ G1CollectedHeap* _g1h;
+ G1ParScanThreadState** _pss;
+ RefToScanQueueSet* _queues;
ParallelTaskTerminator _terminator;
uint _n_workers;
public:
- G1ParPreserveCMReferentsTask(G1CollectedHeap* g1h, uint workers, RefToScanQueueSet *task_queues) :
+ G1ParPreserveCMReferentsTask(G1CollectedHeap* g1h, G1ParScanThreadState** per_thread_states, int workers, RefToScanQueueSet *task_queues) :
AbstractGangTask("ParPreserveCMReferents"),
_g1h(g1h),
+ _pss(per_thread_states),
_queues(task_queues),
_terminator(workers, _queues),
_n_workers(workers)
@@ -5272,12 +5337,13 @@
ResourceMark rm;
HandleMark hm;
- G1ParScanThreadState pss(_g1h, worker_id, NULL);
- assert(pss.queue_is_empty(), "both queue and overflow should be empty");
-
- G1ParScanExtRootClosure only_copy_non_heap_cl(_g1h, &pss, NULL);
-
- G1ParScanAndMarkExtRootClosure copy_mark_non_heap_cl(_g1h, &pss, NULL);
+ G1ParScanThreadState* pss = _pss[worker_id];
+ pss->set_ref_processor(NULL);
+ assert(pss->queue_is_empty(), "both queue and overflow should be empty");
+
+ G1ParScanExtRootClosure only_copy_non_heap_cl(_g1h, pss, NULL);
+
+ G1ParScanAndMarkExtRootClosure copy_mark_non_heap_cl(_g1h, pss, NULL);
OopClosure* copy_non_heap_cl = &only_copy_non_heap_cl;
@@ -5291,7 +5357,7 @@
// Copying keep alive closure. Applied to referent objects that need
// to be copied.
- G1CopyingKeepAliveClosure keep_alive(_g1h, copy_non_heap_cl, &pss);
+ G1CopyingKeepAliveClosure keep_alive(_g1h, copy_non_heap_cl, pss);
ReferenceProcessor* rp = _g1h->ref_processor_cm();
@@ -5324,15 +5390,15 @@
}
// Drain the queue - which may cause stealing
- G1ParEvacuateFollowersClosure drain_queue(_g1h, &pss, _queues, &_terminator);
+ G1ParEvacuateFollowersClosure drain_queue(_g1h, pss, _queues, &_terminator);
drain_queue.do_void();
// Allocation buffers were retired at the end of G1ParEvacuateFollowersClosure
- assert(pss.queue_is_empty(), "should be");
+ assert(pss->queue_is_empty(), "should be");
}
};
// Weak Reference processing during an evacuation pause (part 1).
-void G1CollectedHeap::process_discovered_references() {
+void G1CollectedHeap::process_discovered_references(G1ParScanThreadState** per_thread_states) {
double ref_proc_start = os::elapsedTime();
ReferenceProcessor* rp = _ref_processor_stw;
@@ -5362,6 +5428,7 @@
uint no_of_gc_workers = workers()->active_workers();
G1ParPreserveCMReferentsTask keep_cm_referents(this,
+ per_thread_states,
no_of_gc_workers,
_task_queues);
@@ -5376,16 +5443,17 @@
// JNI refs.
// Use only a single queue for this PSS.
- G1ParScanThreadState pss(this, 0, NULL);
- assert(pss.queue_is_empty(), "pre-condition");
+ G1ParScanThreadState* pss = per_thread_states[0];
+ pss->set_ref_processor(NULL);
+ assert(pss->queue_is_empty(), "pre-condition");
// We do not embed a reference processor in the copying/scanning
// closures while we're actually processing the discovered
// reference objects.
- G1ParScanExtRootClosure only_copy_non_heap_cl(this, &pss, NULL);
-
- G1ParScanAndMarkExtRootClosure copy_mark_non_heap_cl(this, &pss, NULL);
+ G1ParScanExtRootClosure only_copy_non_heap_cl(this, pss, NULL);
+
+ G1ParScanAndMarkExtRootClosure copy_mark_non_heap_cl(this, pss, NULL);
OopClosure* copy_non_heap_cl = &only_copy_non_heap_cl;
@@ -5395,10 +5463,10 @@
}
// Keep alive closure.
- G1CopyingKeepAliveClosure keep_alive(this, copy_non_heap_cl, &pss);
+ G1CopyingKeepAliveClosure keep_alive(this, copy_non_heap_cl, pss);
// Serial Complete GC closure
- G1STWDrainQueueClosure drain_queue(this, &pss);
+ G1STWDrainQueueClosure drain_queue(this, pss);
// Setup the soft refs policy...
rp->setup_policy(false);
@@ -5417,7 +5485,7 @@
assert(rp->num_q() == no_of_gc_workers, "sanity");
assert(no_of_gc_workers <= rp->max_num_q(), "sanity");
- G1STWRefProcTaskExecutor par_task_executor(this, workers(), _task_queues, no_of_gc_workers);
+ G1STWRefProcTaskExecutor par_task_executor(this, per_thread_states, workers(), _task_queues, no_of_gc_workers);
stats = rp->process_discovered_references(&is_alive,
&keep_alive,
&drain_queue,
@@ -5429,14 +5497,14 @@
_gc_tracer_stw->report_gc_reference_stats(stats);
// We have completed copying any necessary live referent objects.
- assert(pss.queue_is_empty(), "both queue and overflow should be empty");
+ assert(pss->queue_is_empty(), "both queue and overflow should be empty");
double ref_proc_time = os::elapsedTime() - ref_proc_start;
g1_policy()->phase_times()->record_ref_proc_time(ref_proc_time * 1000.0);
}
// Weak Reference processing during an evacuation pause (part 2).
-void G1CollectedHeap::enqueue_discovered_references() {
+void G1CollectedHeap::enqueue_discovered_references(G1ParScanThreadState** per_thread_states) {
double ref_enq_start = os::elapsedTime();
ReferenceProcessor* rp = _ref_processor_stw;
@@ -5455,7 +5523,7 @@
assert(rp->num_q() == n_workers, "sanity");
assert(n_workers <= rp->max_num_q(), "sanity");
- G1STWRefProcTaskExecutor par_task_executor(this, workers(), _task_queues, n_workers);
+ G1STWRefProcTaskExecutor par_task_executor(this, per_thread_states, workers(), _task_queues, n_workers);
rp->enqueue_discovered_references(&par_task_executor);
}
@@ -5491,9 +5559,14 @@
double start_par_time_sec = os::elapsedTime();
double end_par_time_sec;
+ G1ParScanThreadState** per_thread_states = NEW_C_HEAP_ARRAY(G1ParScanThreadState*, n_workers, mtGC);
+ for (uint i = 0; i < n_workers; i++) {
+ per_thread_states[i] = new_par_scan_state(i);
+ }
+
{
G1RootProcessor root_processor(this, n_workers);
- G1ParTask g1_par_task(this, _task_queues, &root_processor, n_workers);
+ G1ParTask g1_par_task(this, per_thread_states, _task_queues, &root_processor, n_workers);
// InitialMark needs claim bits to keep track of the marked-through CLDs.
if (collector_state()->during_initial_mark_pause()) {
ClassLoaderDataGraph::clear_claimed_marks();
@@ -5501,7 +5574,7 @@
// The individual threads will set their evac-failure closures.
if (PrintTerminationStats) {
- G1ParScanThreadState::print_termination_stats_hdr();
+ print_termination_stats_hdr(gclog_or_tty);
}
workers()->run_task(&g1_par_task);
@@ -5528,7 +5601,7 @@
// as we may have to copy some 'reachable' referent
// objects (and their reachable sub-graphs) that were
// not copied during the pause.
- process_discovered_references();
+ process_discovered_references(per_thread_states);
if (G1StringDedup::is_enabled()) {
double fixup_start = os::elapsedTime();
@@ -5544,6 +5617,14 @@
_allocator->release_gc_alloc_regions(evacuation_info);
g1_rem_set()->cleanup_after_oops_into_collection_set_do();
+ for (uint i = 0; i < n_workers; i++) {
+ G1ParScanThreadState* pss = per_thread_states[i];
+ delete pss;
+ }
+ FREE_C_HEAP_ARRAY(G1ParScanThreadState*, per_thread_states);
+
+ record_obj_copy_mem_stats();
+
// Reset and re-enable the hot card cache.
// Note the counts for the cards in the regions in the
// collection set are reset when the collection set is freed.
@@ -5568,12 +5649,17 @@
// will log these updates (and dirty their associated
// cards). We need these updates logged to update any
// RSets.
- enqueue_discovered_references();
+ enqueue_discovered_references(per_thread_states);
redirty_logged_cards();
COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
}
+void G1CollectedHeap::record_obj_copy_mem_stats() {
+ _gc_tracer_stw->report_evacuation_statistics(create_g1_evac_summary(&_survivor_evac_stats),
+ create_g1_evac_summary(&_old_evac_stats));
+}
+
void G1CollectedHeap::free_region(HeapRegion* hr,
FreeRegionList* free_list,
bool par,
@@ -5972,6 +6058,11 @@
cur->set_evacuation_failed(false);
// The region is now considered to be old.
cur->set_old();
+ // Do some allocation statistics accounting. Regions that failed evacuation
+ // are always made old, so there is no need to update anything in the young
+ // gen statistics, but we need to update old gen statistics.
+ size_t used_words = cur->marked_bytes() / HeapWordSize;
+ _old_evac_stats.add_failure_used_and_waste(used_words, HeapRegion::GrainWords - used_words);
_old_set.add(cur);
evacuation_info.increment_collectionset_used_after(cur->used());
}
@@ -6217,6 +6308,10 @@
}
}
+bool G1CollectedHeap::is_old_gc_alloc_region(HeapRegion* hr) {
+ return _allocator->is_retained_old_region(hr);
+}
+
void G1CollectedHeap::set_region_short_lived_locked(HeapRegion* hr) {
_young_list->push_region(hr);
}
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -28,12 +28,12 @@
#include "gc/g1/concurrentMark.hpp"
#include "gc/g1/evacuationInfo.hpp"
#include "gc/g1/g1AllocationContext.hpp"
-#include "gc/g1/g1Allocator.hpp"
#include "gc/g1/g1BiasedArray.hpp"
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1HRPrinter.hpp"
#include "gc/g1/g1InCSetState.hpp"
#include "gc/g1/g1MonitoringSupport.hpp"
+#include "gc/g1/g1EvacStats.hpp"
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
#include "gc/g1/g1YCTypes.hpp"
#include "gc/g1/hSpaceCounters.hpp"
@@ -41,6 +41,7 @@
#include "gc/g1/heapRegionSet.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/plab.hpp"
#include "memory/memRegion.hpp"
#include "utilities/stack.hpp"
@@ -54,6 +55,7 @@
class HRRSCleanupTask;
class GenerationSpec;
class OopsInHeapRegionClosure;
+class G1ParScanThreadState;
class G1KlassScanClosure;
class G1ParScanThreadState;
class ObjectClosure;
@@ -75,7 +77,9 @@
class EvacuationFailedInfo;
class nmethod;
class Ticks;
-class FlexibleWorkGang;
+class WorkGang;
+class G1Allocator;
+class G1ArchiveAllocator;
typedef OverflowTaskQueue<StarTask, mtGC> RefToScanQueue;
typedef GenericTaskQueueSet<RefToScanQueue, mtGC> RefToScanQueueSet;
@@ -184,8 +188,7 @@
friend class VM_G1IncCollectionPause;
friend class VMStructs;
friend class MutatorAllocRegion;
- friend class SurvivorGCAllocRegion;
- friend class OldGCAllocRegion;
+ friend class G1GCAllocRegion;
// Closures used in implementation.
friend class G1ParScanThreadState;
@@ -200,7 +203,7 @@
friend class G1CheckCSetFastTableClosure;
private:
- FlexibleWorkGang* _workers;
+ WorkGang* _workers;
static size_t _humongous_object_threshold_in_words;
@@ -245,7 +248,7 @@
// The sequence of all heap regions in the heap.
HeapRegionManager _hrm;
- // Handles non-humongous allocations in the G1CollectedHeap.
+ // Manages all allocations with regions except humongous object allocations.
G1Allocator* _allocator;
// Outside of GC pauses, the number of bytes used in all regions other
@@ -263,11 +266,11 @@
// Statistics for each allocation context
AllocationContextStats _allocation_context_stats;
- // PLAB sizing policy for survivors.
- PLABStats _survivor_plab_stats;
+ // GC allocation statistics policy for survivors.
+ G1EvacStats _survivor_evac_stats;
- // PLAB sizing policy for tenured objects.
- PLABStats _old_plab_stats;
+ // GC allocation statistics policy for tenured objects.
+ G1EvacStats _old_evac_stats;
// It specifies whether we should attempt to expand the heap after a
// region allocation failure. If heap expansion fails we set this to
@@ -581,14 +584,14 @@
// Process any reference objects discovered during
// an incremental evacuation pause.
- void process_discovered_references();
+ void process_discovered_references(G1ParScanThreadState** per_thread_states);
// Enqueue any remaining discovered references
// after processing.
- void enqueue_discovered_references();
+ void enqueue_discovered_references(G1ParScanThreadState** per_thread_states);
public:
- FlexibleWorkGang* workers() const { return _workers; }
+ WorkGang* workers() const { return _workers; }
G1Allocator* allocator() {
return _allocator;
@@ -606,7 +609,7 @@
bool expand(size_t expand_bytes);
// Returns the PLAB statistics for a given destination.
- inline PLABStats* alloc_buffer_stats(InCSetState dest);
+ inline G1EvacStats* alloc_buffer_stats(InCSetState dest);
// Determines PLAB size for a given destination.
inline size_t desired_plab_sz(InCSetState dest);
@@ -680,6 +683,9 @@
// Allocates a new heap region instance.
HeapRegion* new_heap_region(uint hrs_index, MemRegion mr);
+ // Allocates a new per thread par scan state for the given thread id.
+ G1ParScanThreadState* new_par_scan_state(uint worker_id);
+
// Allocate the highest free region in the reserved heap. This will commit
// regions as necessary.
HeapRegion* alloc_highest_free_region();
@@ -789,6 +795,20 @@
// Actually do the work of evacuating the collection set.
void evacuate_collection_set(EvacuationInfo& evacuation_info);
+ // Print the header for the per-thread termination statistics.
+ static void print_termination_stats_hdr(outputStream* const st);
+ // Print actual per-thread termination statistics.
+ void print_termination_stats(outputStream* const st,
+ uint worker_id,
+ double elapsed_ms,
+ double strong_roots_ms,
+ double term_ms,
+ size_t term_attempts,
+ size_t alloc_buffer_waste,
+ size_t undo_waste) const;
+ // Update object copying statistics.
+ void record_obj_copy_mem_stats();
+
// The g1 remembered set of the heap.
G1RemSet* _g1_rem_set;
@@ -1195,9 +1215,7 @@
// Determine whether the given region is one that we are using as an
// old GC alloc region.
- bool is_old_gc_alloc_region(HeapRegion* hr) {
- return _allocator->is_retained_old_region(hr);
- }
+ bool is_old_gc_alloc_region(HeapRegion* hr);
// Perform a collection of the heap; intended for use in implementing
// "System.gc". This probably implies as full a collection as the
@@ -1566,6 +1584,7 @@
const VerifyOption vo) const;
G1HeapSummary create_g1_heap_summary();
+ G1EvacSummary create_g1_evac_summary(G1EvacStats* stats);
// Printing
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -35,12 +35,12 @@
#include "gc/shared/taskqueue.hpp"
#include "runtime/orderAccess.inline.hpp"
-PLABStats* G1CollectedHeap::alloc_buffer_stats(InCSetState dest) {
+G1EvacStats* G1CollectedHeap::alloc_buffer_stats(InCSetState dest) {
switch (dest.value()) {
case InCSetState::Young:
- return &_survivor_plab_stats;
+ return &_survivor_evac_stats;
case InCSetState::Old:
- return &_old_plab_stats;
+ return &_old_evac_stats;
default:
ShouldNotReachHere();
return NULL; // Keep some compilers happy
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap_ext.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap_ext.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "gc/g1/g1CollectedHeap.hpp"
+#include "gc/g1/g1ParScanThreadState.hpp"
#include "gc/g1/heapRegion.inline.hpp"
bool G1CollectedHeap::copy_allocation_context_stats(const jint* contexts,
@@ -37,3 +38,7 @@
MemRegion mr) {
return new HeapRegion(hrs_index, bot_shared(), mr);
}
+
+G1ParScanThreadState* G1CollectedHeap::new_par_scan_state(uint worker_id) {
+ return new G1ParScanThreadState(this, worker_id);
+}
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -1582,7 +1582,7 @@
G1CollectorPolicy::record_concurrent_mark_cleanup_end() {
_collectionSetChooser->clear();
- FlexibleWorkGang* workers = _g1->workers();
+ WorkGang* workers = _g1->workers();
uint n_workers = workers->active_workers();
uint n_regions = _g1->num_regions();
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -26,8 +26,8 @@
#define SHARE_VM_GC_G1_G1COLLECTORPOLICY_HPP
#include "gc/g1/collectionSetChooser.hpp"
-#include "gc/g1/g1Allocator.hpp"
#include "gc/g1/g1CollectorState.hpp"
+#include "gc/g1/g1InCSetState.hpp"
#include "gc/g1/g1MMUTracker.hpp"
#include "gc/shared/collectorPolicy.hpp"
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy_ext.hpp Tue Sep 08 16:01:29 2015 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * 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.
- *
- */
-
-#ifndef SHARE_VM_GC_G1_G1COLLECTORPOLICY_EXT_HPP
-#define SHARE_VM_GC_G1_G1COLLECTORPOLICY_EXT_HPP
-
-#include "gc/g1/g1CollectorPolicy.hpp"
-
-class G1CollectorPolicyExt : public G1CollectorPolicy { };
-
-#endif // SHARE_VM_GC_G1_G1COLLECTORPOLICY_EXT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/g1/g1EvacStats.hpp"
+#include "gc/shared/gcId.hpp"
+#include "trace/tracing.hpp"
+
+void G1EvacStats::adjust_desired_plab_sz() {
+ if (PrintPLAB) {
+ gclog_or_tty->print(" (allocated = " SIZE_FORMAT " wasted = " SIZE_FORMAT " "
+ "unused = " SIZE_FORMAT " used = " SIZE_FORMAT " "
+ "undo_waste = " SIZE_FORMAT " region_end_waste = " SIZE_FORMAT " "
+ "regions filled = %u direct_allocated = " SIZE_FORMAT " "
+ "failure_used = " SIZE_FORMAT " failure_waste = " SIZE_FORMAT ") ",
+ _allocated, _wasted, _unused, used(), _undo_wasted, _region_end_waste,
+ _regions_filled, _direct_allocated, _failure_used, _failure_waste);
+ }
+
+ if (ResizePLAB) {
+
+ assert(is_object_aligned(max_size()) && min_size() <= max_size(),
+ "PLAB clipping computation may be incorrect");
+
+ if (_allocated == 0) {
+ assert((_unused == 0),
+ err_msg("Inconsistency in PLAB stats: "
+ "_allocated: "SIZE_FORMAT", "
+ "_wasted: "SIZE_FORMAT", "
+ "_region_end_waste: "SIZE_FORMAT", "
+ "_unused: "SIZE_FORMAT", "
+ "_used : "SIZE_FORMAT,
+ _allocated, _wasted, _region_end_waste, _unused, used()));
+ _allocated = 1;
+ }
+ // We account region end waste fully to PLAB allocation. This is not completely fair,
+ // but is a conservative assumption because PLABs may be sized flexibly while we
+ // cannot adjust direct allocations.
+ // In some cases, wasted_frac may become > 1 but that just reflects the problem
+ // with region_end_waste.
+ double wasted_frac = (double)(_unused + _wasted + _region_end_waste) / (double)_allocated;
+ size_t target_refills = (size_t)((wasted_frac * TargetSurvivorRatio) / TargetPLABWastePct);
+ if (target_refills == 0) {
+ target_refills = 1;
+ }
+ size_t cur_plab_sz = used() / target_refills;
+ // Take historical weighted average
+ _filter.sample(cur_plab_sz);
+ // Clip from above and below, and align to object boundary
+ size_t plab_sz;
+ plab_sz = MAX2(min_size(), (size_t)_filter.average());
+ plab_sz = MIN2(max_size(), plab_sz);
+ plab_sz = align_object_size(plab_sz);
+ // Latch the result
+ _desired_net_plab_sz = plab_sz;
+ if (PrintPLAB) {
+ gclog_or_tty->print_cr(" (plab_sz = " SIZE_FORMAT " desired_plab_sz = " SIZE_FORMAT ") ", cur_plab_sz, plab_sz);
+ }
+ }
+ // Clear accumulators for next round.
+ reset();
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_gc_G1_G1EVACSTATS_HPP
+#define SHARE_VM_gc_G1_G1EVACSTATS_HPP
+
+#include "gc/shared/plab.hpp"
+#include "runtime/atomic.hpp"
+
+// Records various memory allocation statistics gathered during evacuation.
+class G1EvacStats : public PLABStats {
+ private:
+ size_t _region_end_waste; // Number of words wasted due to skipping to the next region.
+ uint _regions_filled; // Number of regions filled completely.
+ size_t _direct_allocated; // Number of words allocated directly into the regions.
+
+ // Number of words in live objects remaining in regions that ultimately suffered an
+ // evacuation failure. This is used in the regions when the regions are made old regions.
+ size_t _failure_used;
+ // Number of words wasted in regions which failed evacuation. This is the sum of space
+ // for objects successfully copied out of the regions (now dead space) plus waste at the
+ // end of regions.
+ size_t _failure_waste;
+
+ virtual void reset() {
+ PLABStats::reset();
+ _region_end_waste = 0;
+ _regions_filled = 0;
+ _direct_allocated = 0;
+ _failure_used = 0;
+ _failure_waste = 0;
+ }
+
+ public:
+ G1EvacStats(size_t desired_plab_sz_, unsigned wt) : PLABStats(desired_plab_sz_, wt),
+ _region_end_waste(0), _regions_filled(0), _direct_allocated(0),
+ _failure_used(0), _failure_waste(0) {
+ }
+
+ virtual void adjust_desired_plab_sz();
+
+ size_t allocated() const { return _allocated; }
+ size_t wasted() const { return _wasted; }
+ size_t unused() const { return _unused; }
+ size_t used() const { return allocated() - (wasted() + unused()); }
+ size_t undo_wasted() const { return _undo_wasted; }
+
+ uint regions_filled() const { return _regions_filled; }
+ size_t region_end_waste() const { return _region_end_waste; }
+ size_t direct_allocated() const { return _direct_allocated; }
+
+ // Amount of space in heapwords used in the failing regions when an evacuation failure happens.
+ size_t failure_used() const { return _failure_used; }
+ // Amount of space in heapwords wasted (unused) in the failing regions when an evacuation failure happens.
+ size_t failure_waste() const { return _failure_waste; }
+
+ void add_direct_allocated(size_t value) {
+ Atomic::add_ptr(value, &_direct_allocated);
+ }
+
+ void add_region_end_waste(size_t value) {
+ Atomic::add_ptr(value, &_region_end_waste);
+ Atomic::add_ptr(1, &_regions_filled);
+ }
+
+ void add_failure_used_and_waste(size_t used, size_t waste) {
+ Atomic::add_ptr(used, &_failure_used);
+ Atomic::add_ptr(waste, &_failure_waste);
+ }
+};
+
+#endif // SHARE_VM_gc_G1_G1EVACSTATS_HPP
--- a/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -32,7 +32,11 @@
G1ParCopyHelper::G1ParCopyHelper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) :
G1ParClosureSuper(g1, par_scan_state), _scanned_klass(NULL),
- _cm(_g1->concurrent_mark()) {}
+ _cm(_g1->concurrent_mark()) { }
+
+G1ParCopyHelper::G1ParCopyHelper(G1CollectedHeap* g1) :
+ G1ParClosureSuper(g1), _scanned_klass(NULL),
+ _cm(_g1->concurrent_mark()) { }
G1ParClosureSuper::G1ParClosureSuper(G1CollectedHeap* g1) :
_g1(g1), _par_scan_state(NULL), _worker_id(UINT_MAX) { }
--- a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -76,15 +76,13 @@
class G1ParScanClosure : public G1ParClosureSuper {
public:
- G1ParScanClosure(G1CollectedHeap* g1, ReferenceProcessor* rp) :
- G1ParClosureSuper(g1) {
- assert(_ref_processor == NULL, "sanity");
- _ref_processor = rp;
- }
+ G1ParScanClosure(G1CollectedHeap* g1) : G1ParClosureSuper(g1) { }
template <class T> void do_oop_nv(T* p);
virtual void do_oop(oop* p) { do_oop_nv(p); }
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
+
+ void set_ref_processor(ReferenceProcessor* ref_processor) { _ref_processor = ref_processor; }
};
// Add back base class for metadata
@@ -104,6 +102,7 @@
void mark_forwarded_object(oop from_obj, oop to_obj);
public:
G1ParCopyHelper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state);
+ G1ParCopyHelper(G1CollectedHeap* g1);
void set_scanned_klass(Klass* k) { _scanned_klass = k; }
template <class T> void do_klass_barrier(T* p, oop new_obj);
@@ -132,6 +131,10 @@
assert(_ref_processor == NULL, "sanity");
}
+ G1ParCopyClosure(G1CollectedHeap* g1) : G1ParCopyHelper(g1) {
+ assert(_ref_processor == NULL, "sanity");
+ }
+
template <class T> void do_oop_nv(T* p) { do_oop_work(p); }
virtual void do_oop(oop* p) { do_oop_nv(p); }
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
--- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "gc/g1/g1Allocator.inline.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1OopClosures.inline.hpp"
#include "gc/g1/g1ParScanThreadState.inline.hpp"
@@ -31,17 +32,19 @@
#include "oops/oop.inline.hpp"
#include "runtime/prefetch.inline.hpp"
-G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint worker_id, ReferenceProcessor* rp)
+G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint worker_id)
: _g1h(g1h),
_refs(g1h->task_queue(worker_id)),
_dcq(&g1h->dirty_card_queue_set()),
_ct_bs(g1h->g1_barrier_set()),
_g1_rem(g1h->g1_rem_set()),
- _hash_seed(17), _worker_id(worker_id),
- _term_attempts(0),
+ _hash_seed(17),
+ _worker_id(worker_id),
_tenuring_threshold(g1h->g1_policy()->tenuring_threshold()),
- _age_table(false), _scanner(g1h, rp),
- _strong_roots_time(0), _term_time(0) {
+ _age_table(false),
+ _scanner(g1h),
+ _old_gen_is_full(false)
+{
_scanner.set_par_scan_thread_state(this);
// we allocate G1YoungSurvRateNumRegions plus one entries, since
// we "sacrifice" entry 0 to keep track of surviving bytes for
@@ -66,38 +69,20 @@
// need to be moved to the next space.
_dest[InCSetState::Young] = InCSetState::Old;
_dest[InCSetState::Old] = InCSetState::Old;
-
- _start = os::elapsedTime();
}
G1ParScanThreadState::~G1ParScanThreadState() {
- _plab_allocator->retire_alloc_buffers();
+ // Update allocation statistics.
+ _plab_allocator->flush_and_retire_stats();
delete _plab_allocator;
+ _g1h->g1_policy()->record_thread_age_table(&_age_table);
+ // Update heap statistics.
+ _g1h->update_surviving_young_words(_surviving_young_words);
FREE_C_HEAP_ARRAY(size_t, _surviving_young_words_base);
}
-void G1ParScanThreadState::print_termination_stats_hdr(outputStream* const st) {
- st->print_raw_cr("GC Termination Stats");
- st->print_raw_cr(" elapsed --strong roots-- -------termination------- ------waste (KiB)------");
- st->print_raw_cr("thr ms ms % ms % attempts total alloc undo");
- st->print_raw_cr("--- --------- --------- ------ --------- ------ -------- ------- ------- -------");
-}
-
-void G1ParScanThreadState::print_termination_stats(outputStream* const st) const {
- const double elapsed_ms = elapsed_time() * 1000.0;
- const double s_roots_ms = strong_roots_time() * 1000.0;
- const double term_ms = term_time() * 1000.0;
- size_t alloc_buffer_waste = 0;
- size_t undo_waste = 0;
- _plab_allocator->waste(alloc_buffer_waste, undo_waste);
- st->print_cr("%3u %9.2f %9.2f %6.2f "
- "%9.2f %6.2f " SIZE_FORMAT_W(8) " "
- SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7) " " SIZE_FORMAT_W(7),
- _worker_id, elapsed_ms, s_roots_ms, s_roots_ms * 100 / elapsed_ms,
- term_ms, term_ms * 100 / elapsed_ms, term_attempts(),
- (alloc_buffer_waste + undo_waste) * HeapWordSize / K,
- alloc_buffer_waste * HeapWordSize / K,
- undo_waste * HeapWordSize / K);
+void G1ParScanThreadState::waste(size_t& wasted, size_t& undo_wasted) {
+ _plab_allocator->waste(wasted, undo_wasted);
}
#ifdef ASSERT
@@ -152,26 +137,38 @@
HeapWord* G1ParScanThreadState::allocate_in_next_plab(InCSetState const state,
InCSetState* dest,
size_t word_sz,
- AllocationContext_t const context) {
+ AllocationContext_t const context,
+ bool previous_plab_refill_failed) {
assert(state.is_in_cset_or_humongous(), err_msg("Unexpected state: " CSETSTATE_FORMAT, state.value()));
assert(dest->is_in_cset_or_humongous(), err_msg("Unexpected dest: " CSETSTATE_FORMAT, dest->value()));
// Right now we only have two types of regions (young / old) so
// let's keep the logic here simple. We can generalize it when necessary.
if (dest->is_young()) {
+ bool plab_refill_in_old_failed = false;
HeapWord* const obj_ptr = _plab_allocator->allocate(InCSetState::Old,
word_sz,
- context);
- if (obj_ptr == NULL) {
- return NULL;
- }
+ context,
+ &plab_refill_in_old_failed);
// Make sure that we won't attempt to copy any other objects out
// of a survivor region (given that apparently we cannot allocate
- // any new ones) to avoid coming into this slow path.
- _tenuring_threshold = 0;
- dest->set_old();
+ // any new ones) to avoid coming into this slow path again and again.
+ // Only consider failed PLAB refill here: failed inline allocations are
+ // typically large, so not indicative of remaining space.
+ if (previous_plab_refill_failed) {
+ _tenuring_threshold = 0;
+ }
+
+ if (obj_ptr != NULL) {
+ dest->set_old();
+ } else {
+ // We just failed to allocate in old gen. The same idea as explained above
+ // for making survivor gen unavailable for allocation applies for old gen.
+ _old_gen_is_full = plab_refill_in_old_failed;
+ }
return obj_ptr;
} else {
+ _old_gen_is_full = previous_plab_refill_failed;
assert(dest->is_old(), err_msg("Unexpected dest: " CSETSTATE_FORMAT, dest->value()));
// no other space to try.
return NULL;
@@ -202,14 +199,20 @@
uint age = 0;
InCSetState dest_state = next_state(state, old_mark, age);
+ // The second clause is to prevent premature evacuation failure in case there
+ // is still space in survivor, but old gen is full.
+ if (_old_gen_is_full && dest_state.is_old()) {
+ return handle_evacuation_failure_par(old, old_mark);
+ }
HeapWord* obj_ptr = _plab_allocator->plab_allocate(dest_state, word_sz, context);
// PLAB allocations should succeed most of the time, so we'll
// normally check against NULL once and that's it.
if (obj_ptr == NULL) {
- obj_ptr = _plab_allocator->allocate_direct_or_new_plab(dest_state, word_sz, context);
+ bool plab_refill_failed = false;
+ obj_ptr = _plab_allocator->allocate_direct_or_new_plab(dest_state, word_sz, context, &plab_refill_failed);
if (obj_ptr == NULL) {
- obj_ptr = allocate_in_next_plab(state, &dest_state, word_sz, context);
+ obj_ptr = allocate_in_next_plab(state, &dest_state, word_sz, context, plab_refill_failed);
if (obj_ptr == NULL) {
// This will either forward-to-self, or detect that someone else has
// installed a forwarding pointer.
@@ -253,7 +256,7 @@
} else {
obj->set_mark(old_mark->set_age(age));
}
- age_table()->add(age, word_sz);
+ _age_table.add(age, word_sz);
} else {
obj->set_mark(old_mark);
}
@@ -271,8 +274,7 @@
obj);
}
- size_t* const surv_young_words = surviving_young_words();
- surv_young_words[young_index] += word_sz;
+ _surviving_young_words[young_index] += word_sz;
if (obj->is_objArray() && arrayOop(obj)->length() >= ParGCArrayScanChunk) {
// We keep track of the next start index in the length field of
--- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -35,16 +35,17 @@
#include "memory/allocation.hpp"
#include "oops/oop.hpp"
+class G1PLABAllocator;
class HeapRegion;
class outputStream;
-class G1ParScanThreadState : public StackObj {
+class G1ParScanThreadState : public CHeapObj<mtGC> {
private:
G1CollectedHeap* _g1h;
RefToScanQueue* _refs;
DirtyCardQueue _dcq;
G1SATBCardTableModRefBS* _ct_bs;
- G1RemSet* _g1_rem;
+ G1RemSet* _g1_rem;
G1PLABAllocator* _plab_allocator;
@@ -57,20 +58,16 @@
int _hash_seed;
uint _worker_id;
- size_t _term_attempts;
-
- double _start;
- double _start_strong_roots;
- double _strong_roots_time;
- double _start_term;
- double _term_time;
-
// Map from young-age-index (0 == not young, 1 is youngest) to
// surviving words. base is what we get back from the malloc call
size_t* _surviving_young_words_base;
// this points into the array, as we use the first few entries for padding
size_t* _surviving_young_words;
+ // Indicates whether in the last generation (old) there is no more space
+ // available for allocation.
+ bool _old_gen_is_full;
+
#define PADDING_ELEM_NUM (DEFAULT_CACHE_LINE_SIZE / sizeof(size_t))
DirtyCardQueue& dirty_card_queue() { return _dcq; }
@@ -85,10 +82,10 @@
}
public:
- G1ParScanThreadState(G1CollectedHeap* g1h, uint worker_id, ReferenceProcessor* rp);
+ G1ParScanThreadState(G1CollectedHeap* g1h, uint worker_id);
~G1ParScanThreadState();
- ageTable* age_table() { return &_age_table; }
+ void set_ref_processor(ReferenceProcessor* rp) { _scanner.set_ref_processor(rp); }
#ifdef ASSERT
bool queue_is_empty() const { return _refs->is_empty(); }
@@ -114,40 +111,14 @@
uint worker_id() { return _worker_id; }
- size_t term_attempts() const { return _term_attempts; }
- void note_term_attempt() { _term_attempts++; }
-
- void start_strong_roots() {
- _start_strong_roots = os::elapsedTime();
- }
- void end_strong_roots() {
- _strong_roots_time += (os::elapsedTime() - _start_strong_roots);
- }
- double strong_roots_time() const { return _strong_roots_time; }
-
- void start_term_time() {
- note_term_attempt();
- _start_term = os::elapsedTime();
- }
- void end_term_time() {
- _term_time += (os::elapsedTime() - _start_term);
- }
- double term_time() const { return _term_time; }
-
- double elapsed_time() const {
- return os::elapsedTime() - _start;
- }
-
- // Print the header for the per-thread termination statistics.
- static void print_termination_stats_hdr(outputStream* const st = gclog_or_tty);
-
- // Print actual per-thread termination statistics.
- void print_termination_stats(outputStream* const st = gclog_or_tty) const;
+ // Returns the current amount of waste due to alignment or not being able to fit
+ // objects within LABs and the undo waste.
+ virtual void waste(size_t& wasted, size_t& undo_wasted);
size_t* surviving_young_words() {
- // We add on to hide entry 0 which accumulates surviving words for
+ // We add one to hide entry 0 which accumulates surviving words for
// age -1 regions (i.e. non-young ones)
- return _surviving_young_words;
+ return _surviving_young_words + 1;
}
private:
@@ -190,12 +161,16 @@
// Tries to allocate word_sz in the PLAB of the next "generation" after trying to
// allocate into dest. State is the original (source) cset state for the object
- // that is allocated for.
+ // that is allocated for. Previous_plab_refill_failed indicates whether previously
+ // a PLAB refill into "state" failed.
// Returns a non-NULL pointer if successful, and updates dest if required.
+ // Also determines whether we should continue to try to allocate into the various
+ // generations or just end trying to allocate.
HeapWord* allocate_in_next_plab(InCSetState const state,
InCSetState* dest,
size_t word_sz,
- AllocationContext_t const context);
+ AllocationContext_t const context,
+ bool previous_plab_refill_failed);
inline InCSetState next_state(InCSetState const state, markOop const m, uint& age);
public:
--- a/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -115,7 +115,7 @@
G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h, uint n_workers) :
_g1h(g1h),
- _process_strong_tasks(new SubTasksDone(G1RP_PS_NumElements)),
+ _process_strong_tasks(G1RP_PS_NumElements),
_srs(n_workers),
_lock(Mutex::leaf, "G1 Root Scanning barrier lock", false, Monitor::_safepoint_check_never),
_n_workers_discovered_strong_classes(0) {}
@@ -158,7 +158,7 @@
{
// Now the CM ref_processor roots.
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::CMRefRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_refProcessor_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_refProcessor_oops_do)) {
// We need to treat the discovered reference lists of the
// concurrent mark ref processor as roots and keep entries
// (which are added by the marking threads) on them live
@@ -201,12 +201,12 @@
// as implicitly live).
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::SATBFiltering, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_filter_satb_buffers) && _g1h->collector_state()->mark_in_progress()) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_filter_satb_buffers) && _g1h->collector_state()->mark_in_progress()) {
JavaThread::satb_mark_queue_set().filter_thread_buffers();
}
}
- _process_strong_tasks->all_tasks_completed(n_workers());
+ _process_strong_tasks.all_tasks_completed(n_workers());
}
void G1RootProcessor::process_strong_roots(OopClosure* oops,
@@ -216,7 +216,7 @@
process_java_roots(oops, clds, clds, NULL, blobs, NULL, 0);
process_vm_roots(oops, NULL, NULL, 0);
- _process_strong_tasks->all_tasks_completed(n_workers());
+ _process_strong_tasks.all_tasks_completed(n_workers());
}
void G1RootProcessor::process_all_roots(OopClosure* oops,
@@ -226,11 +226,11 @@
process_java_roots(oops, NULL, clds, clds, NULL, NULL, 0);
process_vm_roots(oops, oops, NULL, 0);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_CodeCache_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_CodeCache_oops_do)) {
CodeCache::blobs_do(blobs);
}
- _process_strong_tasks->all_tasks_completed(n_workers());
+ _process_strong_tasks.all_tasks_completed(n_workers());
}
void G1RootProcessor::process_java_roots(OopClosure* strong_roots,
@@ -246,7 +246,7 @@
// let the thread process the weak CLDs and nmethods.
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::CLDGRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_ClassLoaderDataGraph_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_ClassLoaderDataGraph_oops_do)) {
ClassLoaderDataGraph::roots_cld_do(strong_clds, weak_clds);
}
}
@@ -264,49 +264,49 @@
uint worker_i) {
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::UniverseRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_Universe_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_Universe_oops_do)) {
Universe::oops_do(strong_roots);
}
}
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::JNIRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_JNIHandles_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_JNIHandles_oops_do)) {
JNIHandles::oops_do(strong_roots);
}
}
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ObjectSynchronizerRoots, worker_i);
- if (!_process_strong_tasks-> is_task_claimed(G1RP_PS_ObjectSynchronizer_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_ObjectSynchronizer_oops_do)) {
ObjectSynchronizer::oops_do(strong_roots);
}
}
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::FlatProfilerRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_FlatProfiler_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_FlatProfiler_oops_do)) {
FlatProfiler::oops_do(strong_roots);
}
}
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ManagementRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_Management_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_Management_oops_do)) {
Management::oops_do(strong_roots);
}
}
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::JVMTIRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_jvmti_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_jvmti_oops_do)) {
JvmtiExport::oops_do(strong_roots);
}
}
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::SystemDictionaryRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_SystemDictionary_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_SystemDictionary_oops_do)) {
SystemDictionary::roots_oops_do(strong_roots, weak_roots);
}
}
--- a/hotspot/src/share/vm/gc/g1/g1RootProcessor.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/g1RootProcessor.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -45,7 +45,7 @@
// worker thread call the process_roots methods.
class G1RootProcessor : public StackObj {
G1CollectedHeap* _g1h;
- SubTasksDone* _process_strong_tasks;
+ SubTasksDone _process_strong_tasks;
StrongRootsScope _srs;
// Used to implement the Thread work barrier.
--- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -109,7 +109,7 @@
// evacuation pauses between two cleanups, which is _highly_ unlikely.
class G1OffsetTableContigSpace: public CompactibleSpace {
friend class VMStructs;
- HeapWord* _top;
+ HeapWord* volatile _top;
HeapWord* volatile _scan_top;
protected:
G1BlockOffsetArrayContigSpace _offsets;
@@ -134,10 +134,18 @@
// Reset the G1OffsetTableContigSpace.
virtual void initialize(MemRegion mr, bool clear_space, bool mangle_space);
- HeapWord** top_addr() { return &_top; }
- // Allocation helpers (return NULL if full).
- inline HeapWord* allocate_impl(size_t word_size, HeapWord* end_value);
- inline HeapWord* par_allocate_impl(size_t word_size, HeapWord* end_value);
+ HeapWord* volatile* top_addr() { return &_top; }
+ // Try to allocate at least min_word_size and up to desired_size from this Space.
+ // Returns NULL if not possible, otherwise sets actual_word_size to the amount of
+ // space allocated.
+ // This version assumes that all allocation requests to this Space are properly
+ // synchronized.
+ inline HeapWord* allocate_impl(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size);
+ // Try to allocate at least min_word_size and up to desired_size from this Space.
+ // Returns NULL if not possible, otherwise sets actual_word_size to the amount of
+ // space allocated.
+ // This version synchronizes with other calls to par_allocate_impl().
+ inline HeapWord* par_allocate_impl(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size);
public:
void reset_after_compaction() { set_top(compaction_top()); }
@@ -179,9 +187,14 @@
HeapWord* block_start(const void* p);
HeapWord* block_start_const(const void* p) const;
- // Add offset table update.
+ // Allocation (return NULL if full). Assumes the caller has established
+ // mutually exclusive access to the space.
+ HeapWord* allocate(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size);
+ // Allocation (return NULL if full). Enforces mutual exclusion internally.
+ HeapWord* par_allocate(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size);
+
virtual HeapWord* allocate(size_t word_size);
- HeapWord* par_allocate(size_t word_size);
+ virtual HeapWord* par_allocate(size_t word_size);
HeapWord* saved_mark_word() const { ShouldNotReachHere(); return NULL; }
@@ -351,8 +364,9 @@
// Override for scan_and_forward support.
void prepare_for_compaction(CompactPoint* cp);
- inline HeapWord* par_allocate_no_bot_updates(size_t word_size);
+ inline HeapWord* par_allocate_no_bot_updates(size_t min_word_size, size_t desired_word_size, size_t* word_size);
inline HeapWord* allocate_no_bot_updates(size_t word_size);
+ inline HeapWord* allocate_no_bot_updates(size_t min_word_size, size_t desired_word_size, size_t* actual_size);
// If this region is a member of a HeapRegionManager, the index in that
// sequence, otherwise -1.
--- a/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -32,33 +32,39 @@
#include "oops/oop.inline.hpp"
#include "runtime/atomic.inline.hpp"
-// This version requires locking.
-inline HeapWord* G1OffsetTableContigSpace::allocate_impl(size_t size,
- HeapWord* const end_value) {
+inline HeapWord* G1OffsetTableContigSpace::allocate_impl(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_size) {
HeapWord* obj = top();
- if (pointer_delta(end_value, obj) >= size) {
- HeapWord* new_top = obj + size;
+ size_t available = pointer_delta(end(), obj);
+ size_t want_to_allocate = MIN2(available, desired_word_size);
+ if (want_to_allocate >= min_word_size) {
+ HeapWord* new_top = obj + want_to_allocate;
set_top(new_top);
assert(is_aligned(obj) && is_aligned(new_top), "checking alignment");
+ *actual_size = want_to_allocate;
return obj;
} else {
return NULL;
}
}
-// This version is lock-free.
-inline HeapWord* G1OffsetTableContigSpace::par_allocate_impl(size_t size,
- HeapWord* const end_value) {
+inline HeapWord* G1OffsetTableContigSpace::par_allocate_impl(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_size) {
do {
HeapWord* obj = top();
- if (pointer_delta(end_value, obj) >= size) {
- HeapWord* new_top = obj + size;
+ size_t available = pointer_delta(end(), obj);
+ size_t want_to_allocate = MIN2(available, desired_word_size);
+ if (want_to_allocate >= min_word_size) {
+ HeapWord* new_top = obj + want_to_allocate;
HeapWord* result = (HeapWord*)Atomic::cmpxchg_ptr(new_top, top_addr(), obj);
// result can be one of two:
// the old top value: the exchange succeeded
// otherwise: the new value of the top is returned.
if (result == obj) {
assert(is_aligned(obj) && is_aligned(new_top), "checking alignment");
+ *actual_size = want_to_allocate;
return obj;
}
} else {
@@ -67,20 +73,34 @@
} while (true);
}
-inline HeapWord* G1OffsetTableContigSpace::allocate(size_t size) {
- HeapWord* res = allocate_impl(size, end());
+inline HeapWord* G1OffsetTableContigSpace::allocate(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_size) {
+ HeapWord* res = allocate_impl(min_word_size, desired_word_size, actual_size);
if (res != NULL) {
- _offsets.alloc_block(res, size);
+ _offsets.alloc_block(res, *actual_size);
}
return res;
}
+inline HeapWord* G1OffsetTableContigSpace::allocate(size_t word_size) {
+ size_t temp;
+ return allocate(word_size, word_size, &temp);
+}
+
+inline HeapWord* G1OffsetTableContigSpace::par_allocate(size_t word_size) {
+ size_t temp;
+ return par_allocate(word_size, word_size, &temp);
+}
+
// Because of the requirement of keeping "_offsets" up to date with the
// allocations, we sequentialize these with a lock. Therefore, best if
// this is used for larger LAB allocations only.
-inline HeapWord* G1OffsetTableContigSpace::par_allocate(size_t size) {
+inline HeapWord* G1OffsetTableContigSpace::par_allocate(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_size) {
MutexLocker x(&_par_alloc_lock);
- return allocate(size);
+ return allocate(min_word_size, desired_word_size, actual_size);
}
inline HeapWord* G1OffsetTableContigSpace::block_start(const void* p) {
@@ -128,14 +148,23 @@
return pointer_delta(next, addr);
}
-inline HeapWord* HeapRegion::par_allocate_no_bot_updates(size_t word_size) {
+inline HeapWord* HeapRegion::par_allocate_no_bot_updates(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size) {
assert(is_young(), "we can only skip BOT updates on young regions");
- return par_allocate_impl(word_size, end());
+ return par_allocate_impl(min_word_size, desired_word_size, actual_word_size);
}
inline HeapWord* HeapRegion::allocate_no_bot_updates(size_t word_size) {
+ size_t temp;
+ return allocate_no_bot_updates(word_size, word_size, &temp);
+}
+
+inline HeapWord* HeapRegion::allocate_no_bot_updates(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size) {
assert(is_young(), "we can only skip BOT updates on young regions");
- return allocate_impl(word_size, end());
+ return allocate_impl(min_word_size, desired_word_size, actual_word_size);
}
inline void HeapRegion::note_start_of_marking() {
--- a/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -428,7 +428,7 @@
uncommit_regions(idx_last_found + num_last_found - to_remove, to_remove);
- cur -= num_last_found;
+ cur = idx_last_found;
removed += to_remove;
}
--- a/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -34,7 +34,7 @@
static_field(HeapRegion, GrainBytes, size_t) \
static_field(HeapRegion, LogOfHRGrainBytes, int) \
\
- nonstatic_field(G1OffsetTableContigSpace, _top, HeapWord*) \
+ nonstatic_field(G1OffsetTableContigSpace, _top, HeapWord* volatile) \
\
nonstatic_field(G1HeapRegionTable, _base, address) \
nonstatic_field(G1HeapRegionTable, _length, size_t) \
--- a/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -225,6 +225,10 @@
return align_size_up(3 * _space_alignment, _gen_alignment);
}
+size_t GenCollectorPolicy::old_gen_size_lower_bound() {
+ return align_size_up(_space_alignment, _gen_alignment);
+}
+
#ifdef ASSERT
void GenCollectorPolicy::assert_flags() {
CollectorPolicy::assert_flags();
@@ -284,7 +288,7 @@
// Make sure the heap is large enough for two generations
size_t smallest_new_size = young_gen_size_lower_bound();
- size_t smallest_heap_size = align_size_up(smallest_new_size + align_size_up(_space_alignment, _gen_alignment),
+ size_t smallest_heap_size = align_size_up(smallest_new_size + old_gen_size_lower_bound(),
_heap_alignment);
if (MaxHeapSize < smallest_heap_size) {
FLAG_SET_ERGO(size_t, MaxHeapSize, smallest_heap_size);
@@ -356,6 +360,7 @@
vm_exit_during_initialization("Invalid young gen ratio specified");
}
+ OldSize = MAX2(OldSize, old_gen_size_lower_bound());
if (!is_size_aligned(OldSize, _gen_alignment)) {
// Setting OldSize directly to preserve information about the possible
// setting of OldSize on the command line.
--- a/hotspot/src/share/vm/gc/shared/collectorPolicy.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/shared/collectorPolicy.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -282,6 +282,8 @@
size_t young_gen_size_lower_bound();
+ size_t old_gen_size_lower_bound();
+
HeapWord* mem_allocate_work(size_t size,
bool is_tlab,
bool* gc_overhead_limit_was_exceeded);
--- a/hotspot/src/share/vm/gc/shared/gcHeapSummary.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/shared/gcHeapSummary.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -189,4 +189,44 @@
};
+class G1EvacSummary : public StackObj {
+private:
+ size_t _allocated; // Total allocated
+ size_t _wasted; // of which wasted (internal fragmentation)
+ size_t _undo_wasted; // of which wasted on undo (is not used for calculation of PLAB size)
+ size_t _unused; // Unused in last buffer
+ size_t _used;
+
+ size_t _region_end_waste; // Number of words wasted due to skipping to the next region.
+ uint _regions_filled; // Number of regions filled completely.
+ size_t _direct_allocated; // Number of words allocated directly into the regions.
+
+ // Number of words in live objects remaining in regions that ultimately suffered an
+ // evacuation failure. This is used in the regions when the regions are made old regions.
+ size_t _failure_used;
+ // Number of words wasted in regions which failed evacuation. This is the sum of space
+ // for objects successfully copied out of the regions (now dead space) plus waste at the
+ // end of regions.
+ size_t _failure_waste;
+public:
+ G1EvacSummary(size_t allocated, size_t wasted, size_t undo_wasted, size_t unused,
+ size_t used, size_t region_end_waste, uint regions_filled, size_t direct_allocated,
+ size_t failure_used, size_t failure_waste) :
+ _allocated(allocated), _wasted(wasted), _undo_wasted(undo_wasted), _unused(unused),
+ _used(used), _region_end_waste(region_end_waste), _regions_filled(regions_filled),
+ _direct_allocated(direct_allocated), _failure_used(failure_used), _failure_waste(failure_waste)
+ { }
+
+ size_t allocated() const { return _allocated; }
+ size_t wasted() const { return _wasted; }
+ size_t undo_wasted() const { return _undo_wasted; }
+ size_t unused() const { return _unused; }
+ size_t used() const { return _used; }
+ size_t region_end_waste() const { return _region_end_waste; }
+ uint regions_filled() const { return _regions_filled; }
+ size_t direct_allocated() const { return _direct_allocated; }
+ size_t failure_used() const { return _failure_used; }
+ size_t failure_waste() const { return _failure_waste; }
+};
+
#endif // SHARE_VM_GC_SHARED_GCHEAPSUMMARY_HPP
--- a/hotspot/src/share/vm/gc/shared/gcTrace.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/shared/gcTrace.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -252,4 +252,12 @@
send_evacuation_failed_event(ef_info);
ef_info.reset();
}
+
+void G1NewTracer::report_evacuation_statistics(const G1EvacSummary& young_summary, const G1EvacSummary& old_summary) const {
+ assert_set_gc_id();
+
+ send_young_evacuation_statistics(young_summary);
+ send_old_evacuation_statistics(old_summary);
+}
+
#endif
--- a/hotspot/src/share/vm/gc/shared/gcTrace.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/shared/gcTrace.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -45,6 +45,7 @@
class MetaspaceSummary;
class PSHeapSummary;
class G1HeapSummary;
+class G1EvacSummary;
class ReferenceProcessorStats;
class TimePartitions;
class BoolObjectClosure;
@@ -257,10 +258,14 @@
void report_evacuation_info(EvacuationInfo* info);
void report_evacuation_failed(EvacuationFailedInfo& ef_info);
+ void report_evacuation_statistics(const G1EvacSummary& young_summary, const G1EvacSummary& old_summary) const;
private:
void send_g1_young_gc_event();
void send_evacuation_info_event(EvacuationInfo* info);
void send_evacuation_failed_event(const EvacuationFailedInfo& ef_info) const;
+
+ void send_young_evacuation_statistics(const G1EvacSummary& summary) const;
+ void send_old_evacuation_statistics(const G1EvacSummary& summary) const;
};
#endif
--- a/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -234,6 +234,37 @@
e.commit();
}
}
+
+static TraceStructG1EvacStats create_g1_evacstats(unsigned gcid, const G1EvacSummary& summary) {
+ TraceStructG1EvacStats s;
+ s.set_gcId(gcid);
+ s.set_allocated(summary.allocated() * HeapWordSize);
+ s.set_wasted(summary.wasted() * HeapWordSize);
+ s.set_used(summary.used() * HeapWordSize);
+ s.set_undoWaste(summary.undo_wasted() * HeapWordSize);
+ s.set_regionEndWaste(summary.region_end_waste() * HeapWordSize);
+ s.set_regionsRefilled(summary.regions_filled());
+ s.set_directAllocated(summary.direct_allocated() * HeapWordSize);
+ s.set_failureUsed(summary.failure_used() * HeapWordSize);
+ s.set_failureWaste(summary.failure_waste() * HeapWordSize);
+ return s;
+}
+
+void G1NewTracer::send_young_evacuation_statistics(const G1EvacSummary& summary) const {
+ EventGCG1EvacuationYoungStatistics surv_evt;
+ if (surv_evt.should_commit()) {
+ surv_evt.set_stats(create_g1_evacstats(_shared_gc_info.gc_id().id(), summary));
+ surv_evt.commit();
+ }
+}
+
+void G1NewTracer::send_old_evacuation_statistics(const G1EvacSummary& summary) const {
+ EventGCG1EvacuationOldStatistics old_evt;
+ if (old_evt.should_commit()) {
+ old_evt.set_stats(create_g1_evacstats(_shared_gc_info.gc_id().id(), summary));
+ old_evt.commit();
+ }
+}
#endif
static TraceStructVirtualSpace to_trace_struct(const VirtualSpaceSummary& summary) {
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -86,7 +86,7 @@
{
assert(policy != NULL, "Sanity check");
if (UseConcMarkSweepGC) {
- _workers = new FlexibleWorkGang("GC Thread", ParallelGCThreads,
+ _workers = new WorkGang("GC Thread", ParallelGCThreads,
/* are_GC_task_threads */true,
/* are_ConcurrentGC_threads */false);
_workers->initialize_workers();
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -30,9 +30,9 @@
#include "gc/shared/collectorPolicy.hpp"
#include "gc/shared/generation.hpp"
-class FlexibleWorkGang;
class StrongRootsScope;
class SubTasksDone;
+class WorkGang;
// A "GenCollectedHeap" is a CollectedHeap that uses generational
// collection. It has two generations, young and old.
@@ -90,7 +90,7 @@
// In block contents verification, the number of header words to skip
NOT_PRODUCT(static size_t _skip_header_HeapWords;)
- FlexibleWorkGang* _workers;
+ WorkGang* _workers;
protected:
// Helper functions for allocation
@@ -124,7 +124,7 @@
public:
GenCollectedHeap(GenCollectorPolicy *policy);
- FlexibleWorkGang* workers() const { return _workers; }
+ WorkGang* workers() const { return _workers; }
GCStats* gc_stats(Generation* generation) const;
--- a/hotspot/src/share/vm/gc/shared/plab.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/shared/plab.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "gc/shared/collectedHeap.hpp"
-#include "gc/shared/plab.hpp"
+#include "gc/shared/plab.inline.hpp"
#include "gc/shared/threadLocalAllocBuffer.hpp"
#include "oops/arrayOop.hpp"
#include "oops/oop.inline.hpp"
--- a/hotspot/src/share/vm/gc/shared/plab.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/shared/plab.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -27,7 +27,6 @@
#include "gc/shared/gcUtil.hpp"
#include "memory/allocation.hpp"
-#include "runtime/atomic.hpp"
#include "utilities/globalDefinitions.hpp"
// Forward declarations.
@@ -75,6 +74,8 @@
PLAB(size_t word_sz);
virtual ~PLAB() {}
+ static size_t size_required_for_allocation(size_t word_size) { return word_size + AlignmentReserve; }
+
// Minimum PLAB size.
static size_t min_size();
// Maximum PLAB size.
@@ -95,7 +96,7 @@
}
// Allocate the object aligned to "alignment_in_bytes".
- HeapWord* allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes);
+ inline HeapWord* allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes);
// Undo any allocation in the buffer, which is required to be of the
// "obj" of the given "word_sz".
@@ -108,13 +109,6 @@
size_t waste() { return _wasted; }
size_t undo_waste() { return _undo_wasted; }
- // Should only be done if we are about to reset with a new buffer of the
- // given size.
- void set_word_size(size_t new_word_sz) {
- assert(new_word_sz > AlignmentReserve, "Too small");
- _word_sz = new_word_sz;
- }
-
// The number of words of unallocated space remaining in the buffer.
size_t words_remaining() {
assert(_end >= _top, "Negative buffer");
@@ -126,7 +120,10 @@
}
// Sets the space of the buffer to be [buf, space+word_sz()).
- virtual void set_buf(HeapWord* buf) {
+ virtual void set_buf(HeapWord* buf, size_t new_word_sz) {
+ assert(new_word_sz > AlignmentReserve, "Too small");
+ _word_sz = new_word_sz;
+
_bottom = buf;
_top = _bottom;
_hard_end = _bottom + word_sz();
@@ -149,7 +146,8 @@
};
// PLAB book-keeping.
-class PLABStats VALUE_OBJ_CLASS_SPEC {
+class PLABStats : public CHeapObj<mtGC> {
+ protected:
size_t _allocated; // Total allocated
size_t _wasted; // of which wasted (internal fragmentation)
size_t _undo_wasted; // of which wasted on undo (is not used for calculation of PLAB size)
@@ -158,7 +156,7 @@
AdaptiveWeightedAverage
_filter; // Integrator with decay
- void reset() {
+ virtual void reset() {
_allocated = 0;
_wasted = 0;
_undo_wasted = 0;
@@ -174,6 +172,8 @@
_filter(wt)
{ }
+ virtual ~PLABStats() { }
+
static const size_t min_size() {
return PLAB::min_size();
}
@@ -187,23 +187,15 @@
// Updates the current desired PLAB size. Computes the new desired PLAB size with one gc worker thread,
// updates _desired_plab_sz and clears sensor accumulators.
- void adjust_desired_plab_sz();
+ virtual void adjust_desired_plab_sz();
- void add_allocated(size_t v) {
- Atomic::add_ptr(v, &_allocated);
- }
+ inline void add_allocated(size_t v);
- void add_unused(size_t v) {
- Atomic::add_ptr(v, &_unused);
- }
+ inline void add_unused(size_t v);
- void add_wasted(size_t v) {
- Atomic::add_ptr(v, &_wasted);
- }
+ inline void add_wasted(size_t v);
- void add_undo_wasted(size_t v) {
- Atomic::add_ptr(v, &_undo_wasted);
- }
+ inline void add_undo_wasted(size_t v);
};
#endif // SHARE_VM_GC_SHARED_PLAB_HPP
--- a/hotspot/src/share/vm/gc/shared/plab.inline.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/shared/plab.inline.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -27,9 +27,10 @@
#include "gc/shared/collectedHeap.inline.hpp"
#include "gc/shared/plab.hpp"
+#include "memory/allocation.inline.hpp"
+#include "runtime/atomic.inline.hpp"
-HeapWord* PLAB::allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes) {
-
+inline HeapWord* PLAB::allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes) {
HeapWord* res = CollectedHeap::align_allocation_or_fail(_top, _end, alignment_in_bytes);
if (res == NULL) {
return NULL;
@@ -41,4 +42,20 @@
return allocate(word_sz);
}
+void PLABStats::add_allocated(size_t v) {
+ Atomic::add_ptr(v, &_allocated);
+}
+
+void PLABStats::add_unused(size_t v) {
+ Atomic::add_ptr(v, &_unused);
+}
+
+void PLABStats::add_wasted(size_t v) {
+ Atomic::add_ptr(v, &_wasted);
+}
+
+void PLABStats::add_undo_wasted(size_t v) {
+ Atomic::add_ptr(v, &_undo_wasted);
+}
+
#endif // SHARE_VM_GC_SHARED_PLAB_INLINE_HPP
--- a/hotspot/src/share/vm/gc/shared/workgroup.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/shared/workgroup.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -28,58 +28,25 @@
#include "memory/allocation.inline.hpp"
#include "runtime/atomic.inline.hpp"
#include "runtime/os.hpp"
+#include "runtime/semaphore.hpp"
+#include "runtime/thread.inline.hpp"
// Definitions of WorkGang methods.
-AbstractWorkGang::AbstractWorkGang(const char* name,
- bool are_GC_task_threads,
- bool are_ConcurrentGC_threads) :
- _name(name),
- _are_GC_task_threads(are_GC_task_threads),
- _are_ConcurrentGC_threads(are_ConcurrentGC_threads) {
-
- assert(!(are_GC_task_threads && are_ConcurrentGC_threads),
- "They cannot both be STW GC and Concurrent threads" );
-
- // Other initialization.
- _monitor = new Monitor(/* priority */ Mutex::leaf,
- /* name */ "WorkGroup monitor",
- /* allow_vm_block */ are_GC_task_threads,
- Monitor::_safepoint_check_sometimes);
- assert(monitor() != NULL, "Failed to allocate monitor");
- _task = NULL;
- _sequence_number = 0;
- _started_workers = 0;
- _finished_workers = 0;
-}
-
-WorkGang::WorkGang(const char* name,
- uint workers,
- bool are_GC_task_threads,
- bool are_ConcurrentGC_threads) :
- AbstractWorkGang(name, are_GC_task_threads, are_ConcurrentGC_threads) {
- _total_workers = workers;
-}
-
-GangWorker* WorkGang::allocate_worker(uint which) {
- GangWorker* new_worker = new GangWorker(this, which);
- return new_worker;
-}
-
// The current implementation will exit if the allocation
// of any worker fails. Still, return a boolean so that
// a future implementation can possibly do a partial
// initialization of the workers and report such to the
// caller.
-bool WorkGang::initialize_workers() {
+bool AbstractWorkGang::initialize_workers() {
if (TraceWorkGang) {
tty->print_cr("Constructing work gang %s with %d threads",
name(),
total_workers());
}
- _gang_workers = NEW_C_HEAP_ARRAY(GangWorker*, total_workers(), mtInternal);
- if (gang_workers() == NULL) {
+ _workers = NEW_C_HEAP_ARRAY(AbstractGangWorker*, total_workers(), mtInternal);
+ if (_workers == NULL) {
vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create GangWorker array.");
return false;
}
@@ -90,9 +57,9 @@
worker_type = os::pgc_thread;
}
for (uint worker = 0; worker < total_workers(); worker += 1) {
- GangWorker* new_worker = allocate_worker(worker);
+ AbstractGangWorker* new_worker = allocate_worker(worker);
assert(new_worker != NULL, "Failed to allocate GangWorker");
- _gang_workers[worker] = new_worker;
+ _workers[worker] = new_worker;
if (new_worker == NULL || !os::create_thread(new_worker, worker_type)) {
vm_exit_out_of_memory(0, OOM_MALLOC_ERROR,
"Cannot create worker GC thread. Out of system resources.");
@@ -105,110 +72,208 @@
return true;
}
-GangWorker* AbstractWorkGang::gang_worker(uint i) const {
+AbstractGangWorker* AbstractWorkGang::worker(uint i) const {
// Array index bounds checking.
- GangWorker* result = NULL;
- assert(gang_workers() != NULL, "No workers for indexing");
+ AbstractGangWorker* result = NULL;
+ assert(_workers != NULL, "No workers for indexing");
assert(i < total_workers(), "Worker index out of bounds");
- result = _gang_workers[i];
+ result = _workers[i];
assert(result != NULL, "Indexing to null worker");
return result;
}
-void WorkGang::run_task(AbstractGangTask* task) {
- run_task(task, total_workers());
-}
-
-void WorkGang::run_task(AbstractGangTask* task, uint no_of_parallel_workers) {
- // This thread is executed by the VM thread which does not block
- // on ordinary MutexLocker's.
- MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
- if (TraceWorkGang) {
- tty->print_cr("Running work gang %s task %s", name(), task->name());
- }
- // Tell all the workers to run a task.
- assert(task != NULL, "Running a null task");
- // Initialize.
- _task = task;
- _sequence_number += 1;
- _started_workers = 0;
- _finished_workers = 0;
- // Tell the workers to get to work.
- monitor()->notify_all();
- // Wait for them to be finished
- while (finished_workers() < no_of_parallel_workers) {
- if (TraceWorkGang) {
- tty->print_cr("Waiting in work gang %s: %u/%u finished sequence %d",
- name(), finished_workers(), no_of_parallel_workers,
- _sequence_number);
- }
- monitor()->wait(/* no_safepoint_check */ true);
- }
- _task = NULL;
- if (TraceWorkGang) {
- tty->print_cr("\nFinished work gang %s: %u/%u sequence %d",
- name(), finished_workers(), no_of_parallel_workers,
- _sequence_number);
- Thread* me = Thread::current();
- tty->print_cr(" T: " PTR_FORMAT " VM_thread: %d", p2i(me), me->is_VM_thread());
- }
-}
-
-void FlexibleWorkGang::run_task(AbstractGangTask* task) {
- // If active_workers() is passed, _finished_workers
- // must only be incremented for workers that find non_null
- // work (as opposed to all those that just check that the
- // task is not null).
- WorkGang::run_task(task, (uint) active_workers());
-}
-
-void AbstractWorkGang::internal_worker_poll(WorkData* data) const {
- assert(monitor()->owned_by_self(), "worker_poll is an internal method");
- assert(data != NULL, "worker data is null");
- data->set_task(task());
- data->set_sequence_number(sequence_number());
-}
-
-void AbstractWorkGang::internal_note_start() {
- assert(monitor()->owned_by_self(), "note_finish is an internal method");
- _started_workers += 1;
-}
-
-void AbstractWorkGang::internal_note_finish() {
- assert(monitor()->owned_by_self(), "note_finish is an internal method");
- _finished_workers += 1;
-}
-
void AbstractWorkGang::print_worker_threads_on(outputStream* st) const {
- uint num_thr = total_workers();
- for (uint i = 0; i < num_thr; i++) {
- gang_worker(i)->print_on(st);
+ uint workers = total_workers();
+ for (uint i = 0; i < workers; i++) {
+ worker(i)->print_on(st);
st->cr();
}
}
void AbstractWorkGang::threads_do(ThreadClosure* tc) const {
assert(tc != NULL, "Null ThreadClosure");
- uint num_thr = total_workers();
- for (uint i = 0; i < num_thr; i++) {
- tc->do_thread(gang_worker(i));
+ uint workers = total_workers();
+ for (uint i = 0; i < workers; i++) {
+ tc->do_thread(worker(i));
}
}
-// GangWorker methods.
+// WorkGang dispatcher implemented with semaphores.
+//
+// Semaphores don't require the worker threads to re-claim the lock when they wake up.
+// This helps lowering the latency when starting and stopping the worker threads.
+class SemaphoreGangTaskDispatcher : public GangTaskDispatcher {
+ // The task currently being dispatched to the GangWorkers.
+ AbstractGangTask* _task;
+
+ volatile uint _started;
+ volatile uint _not_finished;
+
+ // Semaphore used to start the GangWorkers.
+ Semaphore* _start_semaphore;
+ // Semaphore used to notify the coordinator that all workers are done.
+ Semaphore* _end_semaphore;
+
+public:
+ SemaphoreGangTaskDispatcher() :
+ _task(NULL),
+ _started(0),
+ _not_finished(0),
+ _start_semaphore(new Semaphore()),
+ _end_semaphore(new Semaphore())
+{ }
+
+ ~SemaphoreGangTaskDispatcher() {
+ delete _start_semaphore;
+ delete _end_semaphore;
+ }
+
+ void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers) {
+ // No workers are allowed to read the state variables until they have been signaled.
+ _task = task;
+ _not_finished = num_workers;
+
+ // Dispatch 'num_workers' number of tasks.
+ _start_semaphore->signal(num_workers);
+
+ // Wait for the last worker to signal the coordinator.
+ _end_semaphore->wait();
+
+ // No workers are allowed to read the state variables after the coordinator has been signaled.
+ assert(_not_finished == 0, err_msg("%d not finished workers?", _not_finished));
+ _task = NULL;
+ _started = 0;
+
+ }
+
+ WorkData worker_wait_for_task() {
+ // Wait for the coordinator to dispatch a task.
+ _start_semaphore->wait();
+
+ uint num_started = (uint) Atomic::add(1, (volatile jint*)&_started);
+
+ // Subtract one to get a zero-indexed worker id.
+ uint worker_id = num_started - 1;
+
+ return WorkData(_task, worker_id);
+ }
+
+ void worker_done_with_task() {
+ // Mark that the worker is done with the task.
+ // The worker is not allowed to read the state variables after this line.
+ uint not_finished = (uint) Atomic::add(-1, (volatile jint*)&_not_finished);
+
+ // The last worker signals to the coordinator that all work is completed.
+ if (not_finished == 0) {
+ _end_semaphore->signal();
+ }
+ }
+};
+
+class MutexGangTaskDispatcher : public GangTaskDispatcher {
+ AbstractGangTask* _task;
+
+ volatile uint _started;
+ volatile uint _finished;
+ volatile uint _num_workers;
+
+ Monitor* _monitor;
-GangWorker::GangWorker(AbstractWorkGang* gang, uint id) {
+ public:
+ MutexGangTaskDispatcher()
+ : _task(NULL),
+ _monitor(new Monitor(Monitor::leaf, "WorkGang dispatcher lock", false, Monitor::_safepoint_check_never)),
+ _started(0),
+ _finished(0),
+ _num_workers(0) {}
+
+ ~MutexGangTaskDispatcher() {
+ delete _monitor;
+ }
+
+ void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers) {
+ MutexLockerEx ml(_monitor, Mutex::_no_safepoint_check_flag);
+
+ _task = task;
+ _num_workers = num_workers;
+
+ // Tell the workers to get to work.
+ _monitor->notify_all();
+
+ // Wait for them to finish.
+ while (_finished < _num_workers) {
+ _monitor->wait(/* no_safepoint_check */ true);
+ }
+
+ _task = NULL;
+ _num_workers = 0;
+ _started = 0;
+ _finished = 0;
+ }
+
+ WorkData worker_wait_for_task() {
+ MonitorLockerEx ml(_monitor, Mutex::_no_safepoint_check_flag);
+
+ while (_num_workers == 0 || _started == _num_workers) {
+ _monitor->wait(/* no_safepoint_check */ true);
+ }
+
+ _started++;
+
+ // Subtract one to get a zero-indexed worker id.
+ uint worker_id = _started - 1;
+
+ return WorkData(_task, worker_id);
+ }
+
+ void worker_done_with_task() {
+ MonitorLockerEx ml(_monitor, Mutex::_no_safepoint_check_flag);
+
+ _finished++;
+
+ if (_finished == _num_workers) {
+ // This will wake up all workers and not only the coordinator.
+ _monitor->notify_all();
+ }
+ }
+};
+
+static GangTaskDispatcher* create_dispatcher() {
+ if (UseSemaphoreGCThreadsSynchronization) {
+ return new SemaphoreGangTaskDispatcher();
+ }
+
+ return new MutexGangTaskDispatcher();
+}
+
+WorkGang::WorkGang(const char* name,
+ uint workers,
+ bool are_GC_task_threads,
+ bool are_ConcurrentGC_threads) :
+ AbstractWorkGang(name, workers, are_GC_task_threads, are_ConcurrentGC_threads),
+ _dispatcher(create_dispatcher())
+{ }
+
+AbstractGangWorker* WorkGang::allocate_worker(uint worker_id) {
+ return new GangWorker(this, worker_id);
+}
+
+void WorkGang::run_task(AbstractGangTask* task) {
+ _dispatcher->coordinator_execute_on_workers(task, active_workers());
+}
+
+AbstractGangWorker::AbstractGangWorker(AbstractWorkGang* gang, uint id) {
_gang = gang;
set_id(id);
set_name("%s#%d", gang->name(), id);
}
-void GangWorker::run() {
+void AbstractGangWorker::run() {
initialize();
loop();
}
-void GangWorker::initialize() {
+void AbstractGangWorker::initialize() {
this->initialize_thread_local_storage();
this->record_stack_base_and_size();
this->initialize_named_thread();
@@ -224,112 +289,59 @@
" of a work gang");
}
-void GangWorker::loop() {
- int previous_sequence_number = 0;
- Monitor* gang_monitor = gang()->monitor();
- for ( ; ; ) {
- WorkData data;
- int part; // Initialized below.
- {
- // Grab the gang mutex.
- MutexLocker ml(gang_monitor);
- // Wait for something to do.
- // Polling outside the while { wait } avoids missed notifies
- // in the outer loop.
- gang()->internal_worker_poll(&data);
- if (TraceWorkGang) {
- tty->print("Polled outside for work in gang %s worker %u",
- gang()->name(), id());
- tty->print(" sequence: %d (prev: %d)",
- data.sequence_number(), previous_sequence_number);
- if (data.task() != NULL) {
- tty->print(" task: %s", data.task()->name());
- } else {
- tty->print(" task: NULL");
- }
- tty->cr();
- }
- for ( ; /* break */; ) {
- // Check for new work.
- if ((data.task() != NULL) &&
- (data.sequence_number() != previous_sequence_number)) {
- if (gang()->needs_more_workers()) {
- gang()->internal_note_start();
- gang_monitor->notify_all();
- part = gang()->started_workers() - 1;
- break;
- }
- }
- // Nothing to do.
- gang_monitor->wait(/* no_safepoint_check */ true);
- gang()->internal_worker_poll(&data);
- if (TraceWorkGang) {
- tty->print("Polled inside for work in gang %s worker %u",
- gang()->name(), id());
- tty->print(" sequence: %d (prev: %d)",
- data.sequence_number(), previous_sequence_number);
- if (data.task() != NULL) {
- tty->print(" task: %s", data.task()->name());
- } else {
- tty->print(" task: NULL");
- }
- tty->cr();
- }
- }
- // Drop gang mutex.
- }
- if (TraceWorkGang) {
- tty->print("Work for work gang %s id %u task %s part %d",
- gang()->name(), id(), data.task()->name(), part);
- }
- assert(data.task() != NULL, "Got null task");
- data.task()->work(part);
- {
- if (TraceWorkGang) {
- tty->print("Finish for work gang %s id %u task %s part %d",
- gang()->name(), id(), data.task()->name(), part);
- }
- // Grab the gang mutex.
- MutexLocker ml(gang_monitor);
- gang()->internal_note_finish();
- // Tell the gang you are done.
- gang_monitor->notify_all();
- // Drop the gang mutex.
- }
- previous_sequence_number = data.sequence_number();
- }
-}
-
-bool GangWorker::is_GC_task_thread() const {
+bool AbstractGangWorker::is_GC_task_thread() const {
return gang()->are_GC_task_threads();
}
-bool GangWorker::is_ConcurrentGC_thread() const {
+bool AbstractGangWorker::is_ConcurrentGC_thread() const {
return gang()->are_ConcurrentGC_threads();
}
-void GangWorker::print_on(outputStream* st) const {
+void AbstractGangWorker::print_on(outputStream* st) const {
st->print("\"%s\" ", name());
Thread::print_on(st);
st->cr();
}
-// Printing methods
+WorkData GangWorker::wait_for_task() {
+ return gang()->dispatcher()->worker_wait_for_task();
+}
-const char* AbstractWorkGang::name() const {
- return _name;
+void GangWorker::signal_task_done() {
+ gang()->dispatcher()->worker_done_with_task();
+}
+
+void GangWorker::print_task_started(WorkData data) {
+ if (TraceWorkGang) {
+ tty->print_cr("Running work gang %s task %s worker %u", name(), data._task->name(), data._worker_id);
+ }
}
-#ifndef PRODUCT
-
-const char* AbstractGangTask::name() const {
- return _name;
+void GangWorker::print_task_done(WorkData data) {
+ if (TraceWorkGang) {
+ tty->print_cr("\nFinished work gang %s task %s worker %u", name(), data._task->name(), data._worker_id);
+ Thread* me = Thread::current();
+ tty->print_cr(" T: " PTR_FORMAT " VM_thread: %d", p2i(me), me->is_VM_thread());
+ }
}
-#endif /* PRODUCT */
+void GangWorker::run_task(WorkData data) {
+ print_task_started(data);
+
+ data._task->work(data._worker_id);
+
+ print_task_done(data);
+}
-// FlexibleWorkGang
+void GangWorker::loop() {
+ while (true) {
+ WorkData data = wait_for_task();
+ run_task(data);
+
+ signal_task_done();
+ }
+}
// *** WorkGangBarrierSync
--- a/hotspot/src/share/vm/gc/shared/workgroup.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -25,282 +25,111 @@
#ifndef SHARE_VM_GC_SHARED_WORKGROUP_HPP
#define SHARE_VM_GC_SHARED_WORKGROUP_HPP
-#include "gc/shared/taskqueue.hpp"
-#include "runtime/thread.inline.hpp"
+#include "memory/allocation.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/thread.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/globalDefinitions.hpp"
// Task class hierarchy:
// AbstractGangTask
-// AbstractGangTaskWOopQueues
//
// Gang/Group class hierarchy:
// AbstractWorkGang
// WorkGang
-// FlexibleWorkGang
-// YieldingFlexibleWorkGang (defined in another file)
+// YieldingFlexibleWorkGang (defined in another file)
//
// Worker class hierarchy:
-// GangWorker (subclass of WorkerThread)
+// AbstractGangWorker (subclass of WorkerThread)
+// GangWorker
// YieldingFlexibleGangWorker (defined in another file)
// Forward declarations of classes defined here
+class AbstractGangWorker;
+class Semaphore;
class WorkGang;
-class GangWorker;
-class YieldingFlexibleGangWorker;
-class YieldingFlexibleGangTask;
-class WorkData;
-class AbstractWorkGang;
// An abstract task to be worked on by a gang.
// You subclass this to supply your own work() method
class AbstractGangTask VALUE_OBJ_CLASS_SPEC {
-public:
+ const char* _name;
+
+ public:
+ AbstractGangTask(const char* name) : _name(name) {}
+
// The abstract work method.
// The argument tells you which member of the gang you are.
virtual void work(uint worker_id) = 0;
// Debugging accessor for the name.
- const char* name() const PRODUCT_RETURN_(return NULL;);
- int counter() { return _counter; }
- void set_counter(int value) { _counter = value; }
- int *address_of_counter() { return &_counter; }
-
- // RTTI
- NOT_PRODUCT(virtual bool is_YieldingFlexibleGang_task() const {
- return false;
- })
+ const char* name() const { return _name; }
+};
-private:
- NOT_PRODUCT(const char* _name;)
- // ??? Should a task have a priority associated with it?
- // ??? Or can the run method adjust priority as needed?
- int _counter;
-
-protected:
- // Constructor and desctructor: only construct subclasses.
- AbstractGangTask(const char* name)
- {
- NOT_PRODUCT(_name = name);
- _counter = 0;
- }
- ~AbstractGangTask() { }
-
-public:
+struct WorkData {
+ AbstractGangTask* _task;
+ uint _worker_id;
+ WorkData(AbstractGangTask* task, uint worker_id) : _task(task), _worker_id(worker_id) {}
};
-class AbstractGangTaskWOopQueues : public AbstractGangTask {
- OopTaskQueueSet* _queues;
- ParallelTaskTerminator _terminator;
+// Interface to handle the synchronization between the coordinator thread and the worker threads,
+// when a task is dispatched out to the worker threads.
+class GangTaskDispatcher : public CHeapObj<mtGC> {
public:
- AbstractGangTaskWOopQueues(const char* name, OopTaskQueueSet* queues, uint n_threads) :
- AbstractGangTask(name), _queues(queues), _terminator(n_threads, _queues) {}
- ParallelTaskTerminator* terminator() { return &_terminator; }
- OopTaskQueueSet* queues() { return _queues; }
+ virtual ~GangTaskDispatcher() {}
+
+ // Coordinator API.
+
+ // Distributes the task out to num_workers workers.
+ // Returns when the task has been completed by all workers.
+ virtual void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers) = 0;
+
+ // Worker API.
+
+ // Waits for a task to become available to the worker.
+ // Returns when the worker has been assigned a task.
+ virtual WorkData worker_wait_for_task() = 0;
+
+ // Signal to the coordinator that the worker is done with the assigned task.
+ virtual void worker_done_with_task() = 0;
};
+// The work gang is the collection of workers to execute tasks.
+// The number of workers run for a task is "_active_workers"
+// while "_total_workers" is the number of available of workers.
+class AbstractWorkGang : public CHeapObj<mtInternal> {
+ protected:
+ // The array of worker threads for this gang.
+ AbstractGangWorker** _workers;
+ // The count of the number of workers in the gang.
+ uint _total_workers;
+ // The currently active workers in this gang.
+ uint _active_workers;
+ // Printing support.
+ const char* _name;
-// Class AbstractWorkGang:
-// An abstract class representing a gang of workers.
-// You subclass this to supply an implementation of run_task().
-class AbstractWorkGang: public CHeapObj<mtInternal> {
-protected:
- // Work gangs are never deleted, so no need to cleanup.
- ~AbstractWorkGang() { ShouldNotReachHere(); }
-public:
- // Constructor.
- AbstractWorkGang(const char* name, bool are_GC_task_threads,
- bool are_ConcurrentGC_threads);
- // Run a task, returns when the task is done (or terminated).
- virtual void run_task(AbstractGangTask* task) = 0;
- // Return true if more workers should be applied to the task.
- virtual bool needs_more_workers() const { return true; }
-public:
- // Debugging.
- const char* name() const;
-protected:
+ private:
// Initialize only instance data.
const bool _are_GC_task_threads;
const bool _are_ConcurrentGC_threads;
- // Printing support.
- const char* _name;
- // The monitor which protects these data,
- // and notifies of changes in it.
- Monitor* _monitor;
- // The count of the number of workers in the gang.
- uint _total_workers;
- // The array of worker threads for this gang.
- // This is only needed for cleaning up.
- GangWorker** _gang_workers;
- // The task for this gang.
- AbstractGangTask* _task;
- // A sequence number for the current task.
- int _sequence_number;
- // The number of started workers.
- uint _started_workers;
- // The number of finished workers.
- uint _finished_workers;
-public:
- // Accessors for fields
- Monitor* monitor() const {
- return _monitor;
- }
- uint total_workers() const {
- return _total_workers;
- }
- virtual uint active_workers() const {
- return _total_workers;
- }
- GangWorker** gang_workers() const {
- return _gang_workers;
- }
- AbstractGangTask* task() const {
- return _task;
- }
- int sequence_number() const {
- return _sequence_number;
- }
- uint started_workers() const {
- return _started_workers;
- }
- uint finished_workers() const {
- return _finished_workers;
- }
- bool are_GC_task_threads() const {
- return _are_GC_task_threads;
- }
- bool are_ConcurrentGC_threads() const {
- return _are_ConcurrentGC_threads;
- }
- // Predicates.
- bool is_idle() const {
- return (task() == NULL);
- }
- // Return the Ith gang worker.
- GangWorker* gang_worker(uint i) const;
-
- void threads_do(ThreadClosure* tc) const;
-
- // Printing
- void print_worker_threads_on(outputStream *st) const;
- void print_worker_threads() const {
- print_worker_threads_on(tty);
- }
-
-protected:
- friend class GangWorker;
- friend class YieldingFlexibleGangWorker;
- // Note activation and deactivation of workers.
- // These methods should only be called with the mutex held.
- void internal_worker_poll(WorkData* data) const;
- void internal_note_start();
- void internal_note_finish();
-};
-class WorkData: public StackObj {
- // This would be a struct, but I want accessor methods.
-private:
- AbstractGangTask* _task;
- int _sequence_number;
-public:
- // Constructor and destructor
- WorkData() {
- _task = NULL;
- _sequence_number = 0;
- }
- ~WorkData() {
- }
- AbstractGangTask* task() const { return _task; }
- void set_task(AbstractGangTask* value) { _task = value; }
- int sequence_number() const { return _sequence_number; }
- void set_sequence_number(int value) { _sequence_number = value; }
-
- YieldingFlexibleGangTask* yf_task() const {
- return (YieldingFlexibleGangTask*)_task;
- }
-};
-
-// Class WorkGang:
-class WorkGang: public AbstractWorkGang {
-public:
- // Constructor
- WorkGang(const char* name, uint workers,
- bool are_GC_task_threads, bool are_ConcurrentGC_threads);
- // Run a task, returns when the task is done (or terminated).
- virtual void run_task(AbstractGangTask* task);
- void run_task(AbstractGangTask* task, uint no_of_parallel_workers);
- // Allocate a worker and return a pointer to it.
- virtual GangWorker* allocate_worker(uint which);
- // Initialize workers in the gang. Return true if initialization
- // succeeded. The type of the worker can be overridden in a derived
- // class with the appropriate implementation of allocate_worker().
- bool initialize_workers();
-};
-
-// Class GangWorker:
-// Several instances of this class run in parallel as workers for a gang.
-class GangWorker: public WorkerThread {
-public:
- // Constructors and destructor.
- GangWorker(AbstractWorkGang* gang, uint id);
+ public:
+ AbstractWorkGang(const char* name, uint workers, bool are_GC_task_threads, bool are_ConcurrentGC_threads) :
+ _name(name),
+ _total_workers(workers),
+ _active_workers(UseDynamicNumberOfGCThreads ? 1U : workers),
+ _are_GC_task_threads(are_GC_task_threads),
+ _are_ConcurrentGC_threads(are_ConcurrentGC_threads)
+ { }
- // The only real method: run a task for the gang.
- virtual void run();
- // Predicate for Thread
- virtual bool is_GC_task_thread() const;
- virtual bool is_ConcurrentGC_thread() const;
- // Printing
- void print_on(outputStream* st) const;
- virtual void print() const { print_on(tty); }
-protected:
- AbstractWorkGang* _gang;
-
- virtual void initialize();
- virtual void loop();
-
-public:
- AbstractWorkGang* gang() const { return _gang; }
-};
+ // Initialize workers in the gang. Return true if initialization succeeded.
+ bool initialize_workers();
-// Dynamic number of worker threads
-//
-// This type of work gang is used to run different numbers of
-// worker threads at different times. The
-// number of workers run for a task is "_active_workers"
-// instead of "_total_workers" in a WorkGang. The method
-// "needs_more_workers()" returns true until "_active_workers"
-// have been started and returns false afterwards. The
-// implementation of "needs_more_workers()" in WorkGang always
-// returns true so that all workers are started. The method
-// "loop()" in GangWorker was modified to ask "needs_more_workers()"
-// in its loop to decide if it should start working on a task.
-// A worker in "loop()" waits for notification on the WorkGang
-// monitor and execution of each worker as it checks for work
-// is serialized via the same monitor. The "needs_more_workers()"
-// call is serialized and additionally the calculation for the
-// "part" (effectively the worker id for executing the task) is
-// serialized to give each worker a unique "part". Workers that
-// are not needed for this tasks (i.e., "_active_workers" have
-// been started before it, continue to wait for work.
+ bool are_GC_task_threads() const { return _are_GC_task_threads; }
+ bool are_ConcurrentGC_threads() const { return _are_ConcurrentGC_threads; }
-class FlexibleWorkGang: public WorkGang {
- // The currently active workers in this gang.
- // This is a number that is dynamically adjusted
- // and checked in the run_task() method at each invocation.
- // As described above _active_workers determines the number
- // of threads started on a task. It must also be used to
- // determine completion.
+ uint total_workers() const { return _total_workers; }
- protected:
- uint _active_workers;
- public:
- // Constructor and destructor.
- FlexibleWorkGang(const char* name, uint workers,
- bool are_GC_task_threads,
- bool are_ConcurrentGC_threads) :
- WorkGang(name, workers, are_GC_task_threads, are_ConcurrentGC_threads),
- _active_workers(UseDynamicNumberOfGCThreads ? 1U : workers) {}
-
- // Accessors for fields.
virtual uint active_workers() const {
assert(_active_workers <= _total_workers,
err_msg("_active_workers: %u > _total_workers: %u", _active_workers, _total_workers));
@@ -317,10 +146,90 @@
assert(UseDynamicNumberOfGCThreads || _active_workers == _total_workers,
"Unless dynamic should use total workers");
}
+
+ // Return the Ith worker.
+ AbstractGangWorker* worker(uint i) const;
+
+ void threads_do(ThreadClosure* tc) const;
+
+ // Debugging.
+ const char* name() const { return _name; }
+
+ // Printing
+ void print_worker_threads_on(outputStream *st) const;
+ void print_worker_threads() const {
+ print_worker_threads_on(tty);
+ }
+
+ protected:
+ virtual AbstractGangWorker* allocate_worker(uint which) = 0;
+};
+
+// An class representing a gang of workers.
+class WorkGang: public AbstractWorkGang {
+ // To get access to the GangTaskDispatcher instance.
+ friend class GangWorker;
+
+ // Never deleted.
+ ~WorkGang();
+
+ GangTaskDispatcher* const _dispatcher;
+ GangTaskDispatcher* dispatcher() const {
+ return _dispatcher;
+ }
+
+public:
+ WorkGang(const char* name,
+ uint workers,
+ bool are_GC_task_threads,
+ bool are_ConcurrentGC_threads);
+
+ // Run a task, returns when the task is done.
virtual void run_task(AbstractGangTask* task);
- virtual bool needs_more_workers() const {
- return _started_workers < _active_workers;
- }
+
+protected:
+ virtual AbstractGangWorker* allocate_worker(uint which);
+};
+
+// Several instances of this class run in parallel as workers for a gang.
+class AbstractGangWorker: public WorkerThread {
+public:
+ AbstractGangWorker(AbstractWorkGang* gang, uint id);
+
+ // The only real method: run a task for the gang.
+ virtual void run();
+ // Predicate for Thread
+ virtual bool is_GC_task_thread() const;
+ virtual bool is_ConcurrentGC_thread() const;
+ // Printing
+ void print_on(outputStream* st) const;
+ virtual void print() const { print_on(tty); }
+
+protected:
+ AbstractWorkGang* _gang;
+
+ virtual void initialize();
+ virtual void loop() = 0;
+
+ AbstractWorkGang* gang() const { return _gang; }
+};
+
+class GangWorker: public AbstractGangWorker {
+public:
+ GangWorker(WorkGang* gang, uint id) : AbstractGangWorker(gang, id) {}
+
+protected:
+ virtual void loop();
+
+private:
+ WorkData wait_for_task();
+ void run_task(WorkData work);
+ void signal_task_done();
+
+ void print_task_started(WorkData data);
+ void print_task_done(WorkData data);
+
+ WorkGang* gang() const { return (WorkGang*)_gang; }
};
// A class that acts as a synchronisation barrier. Workers enter
--- a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -90,6 +90,10 @@
java_util_zip_CRC32_update, // implementation of java.util.zip.CRC32.update()
java_util_zip_CRC32_updateBytes, // implementation of java.util.zip.CRC32.updateBytes()
java_util_zip_CRC32_updateByteBuffer, // implementation of java.util.zip.CRC32.updateByteBuffer()
+ java_lang_Float_intBitsToFloat, // implementation of java.lang.Float.intBitsToFloat()
+ java_lang_Float_floatToRawIntBits, // implementation of java.lang.Float.floatToRawIntBits()
+ java_lang_Double_longBitsToDouble, // implementation of java.lang.Double.longBitsToDouble()
+ java_lang_Double_doubleToRawLongBits, // implementation of java.lang.Double.doubleToRawLongBits()
number_of_method_entries,
invalid = -1
};
--- a/hotspot/src/share/vm/interpreter/interpreter.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/interpreter/interpreter.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -234,7 +234,15 @@
case vmIntrinsics::_updateByteBufferCRC32 : return java_util_zip_CRC32_updateByteBuffer;
}
}
-#endif
+
+ switch(m->intrinsic_id()) {
+ case vmIntrinsics::_intBitsToFloat: return java_lang_Float_intBitsToFloat;
+ case vmIntrinsics::_floatToRawIntBits: return java_lang_Float_floatToRawIntBits;
+ case vmIntrinsics::_longBitsToDouble: return java_lang_Double_longBitsToDouble;
+ case vmIntrinsics::_doubleToRawLongBits: return java_lang_Double_doubleToRawLongBits;
+ }
+
+#endif // CC_INTERP
// Native method?
// Note: This test must come _before_ the test for intrinsic
@@ -559,6 +567,25 @@
: // fall thru
case Interpreter::java_util_zip_CRC32_updateByteBuffer
: entry_point = generate_CRC32_updateBytes_entry(kind); break;
+#if defined(TARGET_ARCH_x86) && !defined(_LP64)
+ // On x86_32 platforms, a special entry is generated for the following four methods.
+ // On other platforms the normal entry is used to enter these methods.
+ case Interpreter::java_lang_Float_intBitsToFloat
+ : entry_point = generate_Float_intBitsToFloat_entry(); break;
+ case Interpreter::java_lang_Float_floatToRawIntBits
+ : entry_point = generate_Float_floatToRawIntBits_entry(); break;
+ case Interpreter::java_lang_Double_longBitsToDouble
+ : entry_point = generate_Double_longBitsToDouble_entry(); break;
+ case Interpreter::java_lang_Double_doubleToRawLongBits
+ : entry_point = generate_Double_doubleToRawLongBits_entry(); break;
+#else
+ case Interpreter::java_lang_Float_intBitsToFloat:
+ case Interpreter::java_lang_Float_floatToRawIntBits:
+ case Interpreter::java_lang_Double_longBitsToDouble:
+ case Interpreter::java_lang_Double_doubleToRawLongBits:
+ entry_point = generate_native_entry(false);
+ break;
+#endif // defined(TARGET_ARCH_x86) && !defined(_LP64)
#endif // CC_INTERP
default:
fatal(err_msg("unexpected method kind: %d", kind));
--- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -397,34 +397,39 @@
// all non-native method kinds
method_entry(zerolocals)
- method_entry(zerolocals_synchronized)
- method_entry(empty)
- method_entry(accessor)
- method_entry(abstract)
- method_entry(java_lang_math_sin )
- method_entry(java_lang_math_cos )
- method_entry(java_lang_math_tan )
- method_entry(java_lang_math_abs )
- method_entry(java_lang_math_sqrt )
- method_entry(java_lang_math_log )
- method_entry(java_lang_math_log10)
- method_entry(java_lang_math_exp )
- method_entry(java_lang_math_pow )
- method_entry(java_lang_ref_reference_get)
+ method_entry(zerolocals_synchronized)
+ method_entry(empty)
+ method_entry(accessor)
+ method_entry(abstract)
+ method_entry(java_lang_math_sin )
+ method_entry(java_lang_math_cos )
+ method_entry(java_lang_math_tan )
+ method_entry(java_lang_math_abs )
+ method_entry(java_lang_math_sqrt )
+ method_entry(java_lang_math_log )
+ method_entry(java_lang_math_log10)
+ method_entry(java_lang_math_exp )
+ method_entry(java_lang_math_pow )
+ method_entry(java_lang_ref_reference_get)
- if (UseCRC32Intrinsics) {
- method_entry(java_util_zip_CRC32_update)
- method_entry(java_util_zip_CRC32_updateBytes)
- method_entry(java_util_zip_CRC32_updateByteBuffer)
- }
+ if (UseCRC32Intrinsics) {
+ method_entry(java_util_zip_CRC32_update)
+ method_entry(java_util_zip_CRC32_updateBytes)
+ method_entry(java_util_zip_CRC32_updateByteBuffer)
+ }
+
+ method_entry(java_lang_Float_intBitsToFloat);
+ method_entry(java_lang_Float_floatToRawIntBits);
+ method_entry(java_lang_Double_longBitsToDouble);
+ method_entry(java_lang_Double_doubleToRawLongBits);
initialize_method_handle_entries();
// all native method kinds (must be one contiguous block)
Interpreter::_native_entry_begin = Interpreter::code()->code_end();
method_entry(native)
- method_entry(native_synchronized)
- Interpreter::_native_entry_end = Interpreter::code()->code_end();
+ method_entry(native_synchronized)
+ Interpreter::_native_entry_end = Interpreter::code()->code_end();
#undef method_entry
--- a/hotspot/src/share/vm/memory/metaspace.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/memory/metaspace.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -254,7 +254,7 @@
// Debugging support
void verify();
- static void print_compressed_class_space(outputStream* st, const char* requested_addr = 0);
+ static void print_compressed_class_space(outputStream* st, const char* requested_addr = 0) NOT_LP64({});
class AllocRecordClosure : public StackObj {
public:
--- a/hotspot/src/share/vm/memory/universe.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/memory/universe.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -77,7 +77,7 @@
#if INCLUDE_ALL_GCS
#include "gc/cms/cmsCollectorPolicy.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
-#include "gc/g1/g1CollectorPolicy_ext.hpp"
+#include "gc/g1/g1CollectorPolicy.hpp"
#include "gc/parallel/parallelScavengeHeap.hpp"
#include "gc/shared/adaptiveSizePolicy.hpp"
#endif // INCLUDE_ALL_GCS
@@ -694,13 +694,29 @@
return JNI_OK;
}
-template <class Heap, class Policy>
-jint Universe::create_heap() {
+CollectedHeap* Universe::create_heap() {
assert(_collectedHeap == NULL, "Heap already created");
- Policy* policy = new Policy();
- policy->initialize_all();
- _collectedHeap = new Heap(policy);
- return _collectedHeap->initialize();
+#if !INCLUDE_ALL_GCS
+ if (UseParallelGC) {
+ fatal("UseParallelGC not supported in this VM.");
+ } else if (UseG1GC) {
+ fatal("UseG1GC not supported in this VM.");
+ } else if (UseConcMarkSweepGC) {
+ fatal("UseConcMarkSweepGC not supported in this VM.");
+#else
+ if (UseParallelGC) {
+ return Universe::create_heap_with_policy<ParallelScavengeHeap, GenerationSizer>();
+ } else if (UseG1GC) {
+ return Universe::create_heap_with_policy<G1CollectedHeap, G1CollectorPolicy>();
+ } else if (UseConcMarkSweepGC) {
+ return Universe::create_heap_with_policy<GenCollectedHeap, ConcurrentMarkSweepPolicy>();
+#endif
+ } else if (UseSerialGC) {
+ return Universe::create_heap_with_policy<GenCollectedHeap, MarkSweepPolicy>();
+ }
+
+ ShouldNotReachHere();
+ return NULL;
}
// Choose the heap base address and oop encoding mode
@@ -714,27 +730,12 @@
jint Universe::initialize_heap() {
jint status = JNI_ERR;
-#if !INCLUDE_ALL_GCS
- if (UseParallelGC) {
- fatal("UseParallelGC not supported in this VM.");
- } else if (UseG1GC) {
- fatal("UseG1GC not supported in this VM.");
- } else if (UseConcMarkSweepGC) {
- fatal("UseConcMarkSweepGC not supported in this VM.");
-#else
- if (UseParallelGC) {
- status = Universe::create_heap<ParallelScavengeHeap, GenerationSizer>();
- } else if (UseG1GC) {
- status = Universe::create_heap<G1CollectedHeap, G1CollectorPolicyExt>();
- } else if (UseConcMarkSweepGC) {
- status = Universe::create_heap<GenCollectedHeap, ConcurrentMarkSweepPolicy>();
-#endif
- } else if (UseSerialGC) {
- status = Universe::create_heap<GenCollectedHeap, MarkSweepPolicy>();
- } else {
- ShouldNotReachHere();
+ _collectedHeap = create_heap_ext();
+ if (_collectedHeap == NULL) {
+ _collectedHeap = create_heap();
}
+ status = _collectedHeap->initialize();
if (status != JNI_OK) {
return status;
}
--- a/hotspot/src/share/vm/memory/universe.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/memory/universe.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -214,7 +214,9 @@
static size_t _heap_capacity_at_last_gc;
static size_t _heap_used_at_last_gc;
- template <class Heap, class Policy> static jint create_heap();
+ template <class Heap, class Policy> static CollectedHeap* create_heap_with_policy();
+ static CollectedHeap* create_heap();
+ static CollectedHeap* create_heap_ext();
static jint initialize_heap();
static void initialize_basic_type_mirrors(TRAPS);
static void fixup_mirrors(TRAPS);
--- a/hotspot/src/share/vm/memory/universe.inline.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/memory/universe.inline.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -49,4 +49,11 @@
_allocation_context_notification_obj = obj;
}
+template <class Heap, class Policy>
+CollectedHeap* Universe::create_heap_with_policy() {
+ Policy* policy = new Policy();
+ policy->initialize_all();
+ return new Heap(policy);
+}
+
#endif // SHARE_VM_MEMORY_UNIVERSE_INLINE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/memory/universe_ext.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "memory/universe.hpp"
+
+CollectedHeap* Universe::create_heap_ext() {
+ return NULL;
+}
--- a/hotspot/src/share/vm/oops/symbol.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/oops/symbol.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -35,7 +35,7 @@
Symbol::Symbol(const u1* name, int length, int refcount) {
_refcount = refcount;
_length = length;
- _identity_hash = os::random();
+ _identity_hash = (short)os::random();
for (int i = 0; i < _length; i++) {
byte_at_put(i, name[i]);
}
--- a/hotspot/src/share/vm/oops/symbol.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/oops/symbol.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -106,23 +106,18 @@
#define PERM_REFCOUNT -1
#endif
-// We separate the fields in SymbolBase from Symbol::_body so that
-// Symbol::size(int) can correctly calculate the space needed.
-class SymbolBase : public MetaspaceObj {
- public:
+class Symbol : public MetaspaceObj {
+ friend class VMStructs;
+ friend class SymbolTable;
+ friend class MoveSymbols;
+
+ private:
ATOMIC_SHORT_PAIR(
volatile short _refcount, // needs atomic operation
unsigned short _length // number of UTF8 characters in the symbol (does not need atomic op)
);
- int _identity_hash;
-};
-
-class Symbol : private SymbolBase {
- friend class VMStructs;
- friend class SymbolTable;
- friend class MoveSymbols;
- private:
- jbyte _body[1];
+ short _identity_hash;
+ jbyte _body[2];
enum {
// max_symbol_length is constrained by type of _length
@@ -130,7 +125,7 @@
};
static int size(int length) {
- size_t sz = heap_word_size(sizeof(SymbolBase) + (length > 0 ? length : 0));
+ size_t sz = heap_word_size(sizeof(Symbol) + (length > 2 ? length - 2 : 0));
return align_object_size(sz);
}
@@ -154,8 +149,11 @@
// Returns the largest size symbol we can safely hold.
static int max_length() { return max_symbol_length; }
-
- int identity_hash() { return _identity_hash; }
+ unsigned identity_hash() {
+ unsigned addr_bits = (unsigned)((uintptr_t)this >> (LogMinObjAlignmentInBytes + 3));
+ return ((unsigned)_identity_hash & 0xffff) |
+ ((addr_bits ^ (_length << 8) ^ (( _body[0] << 8) | _body[1])) << 16);
+ }
// For symbol table alternate hashing
unsigned int new_hash(juint seed);
--- a/hotspot/src/share/vm/opto/arraycopynode.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/opto/arraycopynode.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -626,3 +626,75 @@
return CallNode::may_modify_arraycopy_helper(dest_t, t_oop, phase);
}
+
+bool ArrayCopyNode::may_modify_helper(const TypeOopPtr *t_oop, Node* n, PhaseTransform *phase) {
+ if (n->is_Proj()) {
+ n = n->in(0);
+ if (n->is_Call() && n->as_Call()->may_modify(t_oop, phase)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ArrayCopyNode::may_modify(const TypeOopPtr *t_oop, MemBarNode* mb, PhaseTransform *phase) {
+ Node* mem = mb->in(TypeFunc::Memory);
+
+ if (mem->is_MergeMem()) {
+ Node* n = mem->as_MergeMem()->memory_at(Compile::AliasIdxRaw);
+ if (may_modify_helper(t_oop, n, phase)) {
+ return true;
+ } else if (n->is_Phi()) {
+ for (uint i = 1; i < n->req(); i++) {
+ if (n->in(i) != NULL) {
+ if (may_modify_helper(t_oop, n->in(i), phase)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+// Does this array copy modify offsets between offset_lo and offset_hi
+// in the destination array
+// if must_modify is false, return true if the copy could write
+// between offset_lo and offset_hi
+// if must_modify is true, return true if the copy is guaranteed to
+// write between offset_lo and offset_hi
+bool ArrayCopyNode::modifies(intptr_t offset_lo, intptr_t offset_hi, PhaseTransform* phase, bool must_modify) {
+ assert(_kind == ArrayCopy || _kind == CopyOf || _kind == CopyOfRange, "only for real array copies");
+
+ Node* dest = in(ArrayCopyNode::Dest);
+ Node* src_pos = in(ArrayCopyNode::SrcPos);
+ Node* dest_pos = in(ArrayCopyNode::DestPos);
+ Node* len = in(ArrayCopyNode::Length);
+
+ const TypeInt *dest_pos_t = phase->type(dest_pos)->isa_int();
+ const TypeInt *len_t = phase->type(len)->isa_int();
+ const TypeAryPtr* ary_t = phase->type(dest)->isa_aryptr();
+
+ if (dest_pos_t != NULL && len_t != NULL && ary_t != NULL) {
+ BasicType ary_elem = ary_t->klass()->as_array_klass()->element_type()->basic_type();
+ uint header = arrayOopDesc::base_offset_in_bytes(ary_elem);
+ uint elemsize = type2aelembytes(ary_elem);
+
+ intptr_t dest_pos_plus_len_lo = (((intptr_t)dest_pos_t->_lo) + len_t->_lo) * elemsize + header;
+ intptr_t dest_pos_plus_len_hi = (((intptr_t)dest_pos_t->_hi) + len_t->_hi) * elemsize + header;
+ intptr_t dest_pos_lo = ((intptr_t)dest_pos_t->_lo) * elemsize + header;
+ intptr_t dest_pos_hi = ((intptr_t)dest_pos_t->_hi) * elemsize + header;
+
+ if (must_modify) {
+ if (offset_lo >= dest_pos_hi && offset_hi < dest_pos_plus_len_lo) {
+ return true;
+ }
+ } else {
+ if (offset_hi >= dest_pos_lo && offset_lo < dest_pos_plus_len_hi) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
--- a/hotspot/src/share/vm/opto/arraycopynode.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/opto/arraycopynode.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -108,6 +108,7 @@
BasicType copy_type, const Type* value_type, int count);
bool finish_transform(PhaseGVN *phase, bool can_reshape,
Node* ctl, Node *mem);
+ static bool may_modify_helper(const TypeOopPtr *t_oop, Node* n, PhaseTransform *phase);
public:
@@ -162,6 +163,9 @@
bool is_alloc_tightly_coupled() const { return _alloc_tightly_coupled; }
+ static bool may_modify(const TypeOopPtr *t_oop, MemBarNode* mb, PhaseTransform *phase);
+ bool modifies(intptr_t offset_lo, intptr_t offset_hi, PhaseTransform* phase, bool must_modify);
+
#ifndef PRODUCT
virtual void dump_spec(outputStream *st) const;
virtual void dump_compact_spec(outputStream* st) const;
--- a/hotspot/src/share/vm/opto/c2compiler.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/opto/c2compiler.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -161,7 +161,7 @@
vmIntrinsics::ID id = method->intrinsic_id();
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
- if (id < vmIntrinsics::FIRST_ID || id >= vmIntrinsics::LAST_COMPILER_INLINE) {
+ if (id < vmIntrinsics::FIRST_ID || id > vmIntrinsics::LAST_COMPILER_INLINE) {
return false;
}
--- a/hotspot/src/share/vm/opto/callnode.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/opto/callnode.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -742,7 +742,7 @@
//
bool CallNode::may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase) {
assert((t_oop != NULL), "sanity");
- if (is_call_to_arraycopystub()) {
+ if (is_call_to_arraycopystub() && strcmp(_name, "unsafe_arraycopy") != 0) {
const TypeTuple* args = _tf->domain();
Node* dest = NULL;
// Stubs that can be called once an ArrayCopyNode is expanded have
--- a/hotspot/src/share/vm/opto/chaitin.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/opto/chaitin.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -990,9 +990,13 @@
// FOUR registers!
#ifdef ASSERT
if (is_vect) {
- assert(lrgmask.is_aligned_sets(lrg.num_regs()), "vector should be aligned");
- assert(!lrg._fat_proj, "sanity");
- assert(RegMask::num_registers(kreg) == lrg.num_regs(), "sanity");
+ if (lrg.num_regs() != 0) {
+ assert(lrgmask.is_aligned_sets(lrg.num_regs()), "vector should be aligned");
+ assert(!lrg._fat_proj, "sanity");
+ assert(RegMask::num_registers(kreg) == lrg.num_regs(), "sanity");
+ } else {
+ assert(n->is_Phi(), "not all inputs processed only if Phi");
+ }
}
#endif
if (!is_vect && lrg.num_regs() == 2 && !lrg._fat_proj && rm.is_misaligned_pair()) {
--- a/hotspot/src/share/vm/opto/compile.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/opto/compile.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -93,7 +93,7 @@
public:
void set_idx(node_idx_t idx) {
- _idx_clone_orig = _idx_clone_orig & 0xFFFFFFFF00000000 | idx;
+ _idx_clone_orig = _idx_clone_orig & CONST64(0xFFFFFFFF00000000) | idx;
}
node_idx_t idx() const { return (node_idx_t)(_idx_clone_orig & 0xFFFFFFFF); }
--- a/hotspot/src/share/vm/opto/library_call.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/opto/library_call.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -2730,7 +2730,22 @@
load_store = _gvn.transform(new CompareAndSwapPNode(control(), mem, adr, newval, oldval));
}
}
- post_barrier(control(), load_store, base, adr, alias_idx, newval, T_OBJECT, true);
+ if (kind == LS_cmpxchg) {
+ // Emit the post barrier only when the actual store happened.
+ // This makes sense to check only for compareAndSet that can fail to set the value.
+ // CAS success path is marked more likely since we anticipate this is a performance
+ // critical path, while CAS failure path can use the penalty for going through unlikely
+ // path as backoff. Which is still better than doing a store barrier there.
+ IdealKit ideal(this);
+ ideal.if_then(load_store, BoolTest::ne, ideal.ConI(0), PROB_STATIC_FREQUENT); {
+ sync_kit(ideal);
+ post_barrier(ideal.ctrl(), load_store, base, adr, alias_idx, newval, T_OBJECT, true);
+ ideal.sync_kit(this);
+ } ideal.end_if();
+ final_sync(ideal);
+ } else {
+ post_barrier(control(), load_store, base, adr, alias_idx, newval, T_OBJECT, true);
+ }
break;
default:
fatal(err_msg_res("unexpected type %d: %s", type, type2name(type)));
--- a/hotspot/src/share/vm/opto/loopnode.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/opto/loopnode.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -1175,7 +1175,7 @@
//=============================================================================
//------------------------------is_member--------------------------------------
// Is 'l' a member of 'this'?
-int IdealLoopTree::is_member( const IdealLoopTree *l ) const {
+bool IdealLoopTree::is_member(const IdealLoopTree *l) const {
while( l->_nest > _nest ) l = l->_parent;
return l == this;
}
--- a/hotspot/src/share/vm/opto/loopnode.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/opto/loopnode.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -384,7 +384,7 @@
{ }
// Is 'l' a member of 'this'?
- int is_member( const IdealLoopTree *l ) const; // Test for nested membership
+ bool is_member(const IdealLoopTree *l) const; // Test for nested membership
// Set loop nesting depth. Accumulate has_call bits.
int set_nest( uint depth );
@@ -1086,6 +1086,8 @@
bool split_up( Node *n, Node *blk1, Node *blk2 );
void sink_use( Node *use, Node *post_loop );
Node *place_near_use( Node *useblock ) const;
+ Node* try_move_store_before_loop(Node* n, Node *n_ctrl);
+ void try_move_store_after_loop(Node* n);
bool _created_loop_node;
public:
--- a/hotspot/src/share/vm/opto/loopopts.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/opto/loopopts.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -653,6 +653,209 @@
return iff->in(1);
}
+#ifdef ASSERT
+static void enqueue_cfg_uses(Node* m, Unique_Node_List& wq) {
+ for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax; i++) {
+ Node* u = m->fast_out(i);
+ if (u->is_CFG()) {
+ if (u->Opcode() == Op_NeverBranch) {
+ u = ((NeverBranchNode*)u)->proj_out(0);
+ enqueue_cfg_uses(u, wq);
+ } else {
+ wq.push(u);
+ }
+ }
+ }
+}
+#endif
+
+// Try moving a store out of a loop, right before the loop
+Node* PhaseIdealLoop::try_move_store_before_loop(Node* n, Node *n_ctrl) {
+ // Store has to be first in the loop body
+ IdealLoopTree *n_loop = get_loop(n_ctrl);
+ if (n->is_Store() && n_loop != _ltree_root && n_loop->is_loop()) {
+ assert(n->in(0), "store should have control set");
+ Node* address = n->in(MemNode::Address);
+ Node* value = n->in(MemNode::ValueIn);
+ Node* mem = n->in(MemNode::Memory);
+ IdealLoopTree* address_loop = get_loop(get_ctrl(address));
+ IdealLoopTree* value_loop = get_loop(get_ctrl(value));
+
+ // - address and value must be loop invariant
+ // - memory must be a memory Phi for the loop
+ // - Store must be the only store on this memory slice in the
+ // loop: if there's another store following this one then value
+ // written at iteration i by the second store could be overwritten
+ // at iteration i+n by the first store: it's not safe to move the
+ // first store out of the loop
+ // - nothing must observe the Phi memory: it guarantees no read
+ // before the store and no early exit out of the loop
+ // With those conditions, we are also guaranteed the store post
+ // dominates the loop head. Otherwise there would be extra Phi
+ // involved between the loop's Phi and the store.
+
+ if (!n_loop->is_member(address_loop) &&
+ !n_loop->is_member(value_loop) &&
+ mem->is_Phi() && mem->in(0) == n_loop->_head &&
+ mem->outcnt() == 1 &&
+ mem->in(LoopNode::LoopBackControl) == n) {
+
+#ifdef ASSERT
+ // Verify that store's control does post dominate loop entry and
+ // that there's no early exit of the loop before the store.
+ bool ctrl_ok = false;
+ {
+ // Follow control from loop head until n, we exit the loop or
+ // we reach the tail
+ ResourceMark rm;
+ Unique_Node_List wq;
+ wq.push(n_loop->_head);
+ assert(n_loop->_tail != NULL, "need a tail");
+ for (uint next = 0; next < wq.size(); ++next) {
+ Node *m = wq.at(next);
+ if (m == n->in(0)) {
+ ctrl_ok = true;
+ continue;
+ }
+ assert(!has_ctrl(m), "should be CFG");
+ if (!n_loop->is_member(get_loop(m)) || m == n_loop->_tail) {
+ ctrl_ok = false;
+ break;
+ }
+ enqueue_cfg_uses(m, wq);
+ }
+ }
+ assert(ctrl_ok, "bad control");
+#endif
+
+ // move the Store
+ _igvn.replace_input_of(mem, LoopNode::LoopBackControl, mem);
+ _igvn.replace_input_of(n, 0, n_loop->_head->in(LoopNode::EntryControl));
+ _igvn.replace_input_of(n, MemNode::Memory, mem->in(LoopNode::EntryControl));
+ // Disconnect the phi now. An empty phi can confuse other
+ // optimizations in this pass of loop opts.
+ _igvn.replace_node(mem, mem->in(LoopNode::EntryControl));
+ n_loop->_body.yank(mem);
+
+ IdealLoopTree* new_loop = get_loop(n->in(0));
+ set_ctrl_and_loop(n, n->in(0));
+
+ return n;
+ }
+ }
+ return NULL;
+}
+
+// Try moving a store out of a loop, right after the loop
+void PhaseIdealLoop::try_move_store_after_loop(Node* n) {
+ if (n->is_Store()) {
+ assert(n->in(0), "store should have control set");
+ Node *n_ctrl = get_ctrl(n);
+ IdealLoopTree *n_loop = get_loop(n_ctrl);
+ // Store must be in a loop
+ if (n_loop != _ltree_root && !n_loop->_irreducible) {
+ Node* address = n->in(MemNode::Address);
+ Node* value = n->in(MemNode::ValueIn);
+ IdealLoopTree* address_loop = get_loop(get_ctrl(address));
+ // address must be loop invariant
+ if (!n_loop->is_member(address_loop)) {
+ // Store must be last on this memory slice in the loop and
+ // nothing in the loop must observe it
+ Node* phi = NULL;
+ for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
+ Node* u = n->fast_out(i);
+ if (has_ctrl(u)) { // control use?
+ IdealLoopTree *u_loop = get_loop(get_ctrl(u));
+ if (!n_loop->is_member(u_loop)) {
+ continue;
+ }
+ if (u->is_Phi() && u->in(0) == n_loop->_head) {
+ assert(_igvn.type(u) == Type::MEMORY, "bad phi");
+ assert(phi == NULL, "already found");
+ phi = u;
+ continue;
+ }
+ }
+ phi = NULL;
+ break;
+ }
+ if (phi != NULL) {
+ // Nothing in the loop before the store (next iteration)
+ // must observe the stored value
+ bool mem_ok = true;
+ {
+ ResourceMark rm;
+ Unique_Node_List wq;
+ wq.push(phi);
+ for (uint next = 0; next < wq.size() && mem_ok; ++next) {
+ Node *m = wq.at(next);
+ for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax && mem_ok; i++) {
+ Node* u = m->fast_out(i);
+ if (u->is_Store() || u->is_Phi()) {
+ if (u != n) {
+ wq.push(u);
+ mem_ok = (wq.size() <= 10);
+ }
+ } else {
+ mem_ok = false;
+ break;
+ }
+ }
+ }
+ }
+ if (mem_ok) {
+ // Move the Store out of the loop creating clones along
+ // all paths out of the loop that observe the stored value
+ _igvn.rehash_node_delayed(phi);
+ int count = phi->replace_edge(n, n->in(MemNode::Memory));
+ assert(count > 0, "inconsistent phi");
+ for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
+ Node* u = n->fast_out(i);
+ Node* c = get_ctrl(u);
+
+ if (u->is_Phi()) {
+ c = u->in(0)->in(u->find_edge(n));
+ }
+ IdealLoopTree *u_loop = get_loop(c);
+ assert (!n_loop->is_member(u_loop), "only the phi should have been a use in the loop");
+ while(true) {
+ Node* next_c = find_non_split_ctrl(idom(c));
+ if (n_loop->is_member(get_loop(next_c))) {
+ break;
+ }
+ c = next_c;
+ }
+
+ Node* st = n->clone();
+ st->set_req(0, c);
+ _igvn.register_new_node_with_optimizer(st);
+
+ set_ctrl(st, c);
+ IdealLoopTree* new_loop = get_loop(c);
+ assert(new_loop != n_loop, "should be moved out of loop");
+ if (new_loop->_child == NULL) new_loop->_body.push(st);
+
+ _igvn.replace_input_of(u, u->find_edge(n), st);
+ --imax;
+ --i;
+ }
+
+
+ assert(n->outcnt() == 0, "all uses should be gone");
+ _igvn.replace_input_of(n, MemNode::Memory, C->top());
+ // Disconnect the phi now. An empty phi can confuse other
+ // optimizations in this pass of loop opts..
+ if (phi->in(LoopNode::LoopBackControl) == phi) {
+ _igvn.replace_node(phi, phi->in(LoopNode::EntryControl));
+ n_loop->_body.yank(phi);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
//------------------------------split_if_with_blocks_pre-----------------------
// Do the real work in a non-recursive function. Data nodes want to be
// cloned in the pre-order so they can feed each other nicely.
@@ -683,6 +886,11 @@
Node *n_ctrl = get_ctrl(n);
if( !n_ctrl ) return n; // Dead node
+ Node* res = try_move_store_before_loop(n, n_ctrl);
+ if (res != NULL) {
+ return n;
+ }
+
// Attempt to remix address expressions for loop invariants
Node *m = remix_address_expressions( n );
if( m ) return m;
@@ -691,16 +899,18 @@
// Returns the block to clone thru.
Node *n_blk = has_local_phi_input( n );
if( !n_blk ) return n;
+
// Do not clone the trip counter through on a CountedLoop
// (messes up the canonical shape).
if( n_blk->is_CountedLoop() && n->Opcode() == Op_AddI ) return n;
// Check for having no control input; not pinned. Allow
// dominating control.
- if( n->in(0) ) {
+ if (n->in(0)) {
Node *dom = idom(n_blk);
- if( dom_lca( n->in(0), dom ) != n->in(0) )
+ if (dom_lca(n->in(0), dom) != n->in(0)) {
return n;
+ }
}
// Policy: when is it profitable. You must get more wins than
// policy before it is considered profitable. Policy is usually 0,
@@ -1029,6 +1239,8 @@
}
}
+ try_move_store_after_loop(n);
+
// Check for Opaque2's who's loop has disappeared - who's input is in the
// same loop nest as their output. Remove 'em, they are no longer useful.
if( n_op == Op_Opaque2 &&
--- a/hotspot/src/share/vm/opto/macro.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/opto/macro.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -324,18 +324,28 @@
return in;
} else if (in->is_Call()) {
CallNode *call = in->as_Call();
- if (!call->may_modify(tinst, phase)) {
- mem = call->in(TypeFunc::Memory);
+ if (call->may_modify(tinst, phase)) {
+ assert(call->is_ArrayCopy(), "ArrayCopy is the only call node that doesn't make allocation escape");
+
+ if (call->as_ArrayCopy()->modifies(offset, offset, phase, false)) {
+ return in;
+ }
}
mem = in->in(TypeFunc::Memory);
} else if (in->is_MemBar()) {
+ if (ArrayCopyNode::may_modify(tinst, in->as_MemBar(), phase)) {
+ assert(in->in(0)->is_Proj() && in->in(0)->in(0)->is_ArrayCopy(), "should be arraycopy");
+ ArrayCopyNode* ac = in->in(0)->in(0)->as_ArrayCopy();
+ assert(ac->is_clonebasic(), "Only basic clone is a non escaping clone");
+ return ac;
+ }
mem = in->in(TypeFunc::Memory);
} else {
assert(false, "unexpected projection");
}
} else if (mem->is_Store()) {
const TypePtr* atype = mem->as_Store()->adr_type();
- int adr_idx = Compile::current()->get_alias_index(atype);
+ int adr_idx = phase->C->get_alias_index(atype);
if (adr_idx == alias_idx) {
assert(atype->isa_oopptr(), "address type must be oopptr");
int adr_offset = atype->offset();
@@ -373,7 +383,7 @@
adr = mem->in(3); // Destination array
}
const TypePtr* atype = adr->bottom_type()->is_ptr();
- int adr_idx = Compile::current()->get_alias_index(atype);
+ int adr_idx = phase->C->get_alias_index(atype);
if (adr_idx == alias_idx) {
assert(false, "Object is not scalar replaceable if a LoadStore node access its field");
return NULL;
@@ -386,12 +396,63 @@
}
}
+// Generate loads from source of the arraycopy for fields of
+// destination needed at a deoptimization point
+Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, BasicType ft, const Type *ftype, AllocateNode *alloc) {
+ BasicType bt = ft;
+ const Type *type = ftype;
+ if (ft == T_NARROWOOP) {
+ bt = T_OBJECT;
+ type = ftype->make_oopptr();
+ }
+ Node* res = NULL;
+ if (ac->is_clonebasic()) {
+ Node* base = ac->in(ArrayCopyNode::Src)->in(AddPNode::Base);
+ Node* adr = _igvn.transform(new AddPNode(base, base, MakeConX(offset)));
+ const TypePtr* adr_type = _igvn.type(base)->is_ptr()->add_offset(offset);
+ Node* m = ac->in(TypeFunc::Memory);
+ while (m->is_MergeMem()) {
+ m = m->as_MergeMem()->memory_at(C->get_alias_index(adr_type));
+ if (m->is_Proj() && m->in(0)->is_MemBar()) {
+ m = m->in(0)->in(TypeFunc::Memory);
+ }
+ }
+ res = LoadNode::make(_igvn, ctl, m, adr, adr_type, type, bt, MemNode::unordered, LoadNode::Pinned);
+ } else {
+ if (ac->modifies(offset, offset, &_igvn, true)) {
+ assert(ac->in(ArrayCopyNode::Dest) == alloc->result_cast(), "arraycopy destination should be allocation's result");
+ uint shift = exact_log2(type2aelembytes(bt));
+ Node* diff = _igvn.transform(new SubINode(ac->in(ArrayCopyNode::SrcPos), ac->in(ArrayCopyNode::DestPos)));
+#ifdef _LP64
+ diff = _igvn.transform(new ConvI2LNode(diff));
+#endif
+ diff = _igvn.transform(new LShiftXNode(diff, intcon(shift)));
+
+ Node* off = _igvn.transform(new AddXNode(MakeConX(offset), diff));
+ Node* base = ac->in(ArrayCopyNode::Src);
+ Node* adr = _igvn.transform(new AddPNode(base, base, off));
+ const TypePtr* adr_type = _igvn.type(base)->is_ptr()->add_offset(offset);
+ Node* m = ac->in(TypeFunc::Memory);
+ res = LoadNode::make(_igvn, ctl, m, adr, adr_type, type, bt, MemNode::unordered, LoadNode::Pinned);
+ }
+ }
+ if (res != NULL) {
+ res = _igvn.transform(res);
+ if (ftype->isa_narrowoop()) {
+ // PhaseMacroExpand::scalar_replacement adds DecodeN nodes
+ res = _igvn.transform(new EncodePNode(res, ftype));
+ }
+ return res;
+ }
+ return NULL;
+}
+
//
// Given a Memory Phi, compute a value Phi containing the values from stores
// on the input paths.
-// Note: this function is recursive, its depth is limied by the "level" argument
+// Note: this function is recursive, its depth is limited by the "level" argument
// Returns the computed Phi, or NULL if it cannot compute it.
-Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *phi_type, const TypeOopPtr *adr_t, Node *alloc, Node_Stack *value_phis, int level) {
+Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *phi_type, const TypeOopPtr *adr_t, AllocateNode *alloc, Node_Stack *value_phis, int level) {
assert(mem->is_Phi(), "sanity");
int alias_idx = C->get_alias_index(adr_t);
int offset = adr_t->offset();
@@ -458,6 +519,12 @@
assert(val->in(0)->is_LoadStore() || val->in(0)->Opcode() == Op_EncodeISOArray, "sanity");
assert(false, "Object is not scalar replaceable if a LoadStore node access its field");
return NULL;
+ } else if (val->is_ArrayCopy()) {
+ Node* res = make_arraycopy_load(val->as_ArrayCopy(), offset, val->in(0), ft, phi_type, alloc);
+ if (res == NULL) {
+ return NULL;
+ }
+ values.at_put(j, res);
} else {
#ifdef ASSERT
val->dump();
@@ -479,7 +546,7 @@
}
// Search the last value stored into the object's field.
-Node *PhaseMacroExpand::value_from_mem(Node *sfpt_mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, Node *alloc) {
+Node *PhaseMacroExpand::value_from_mem(Node *sfpt_mem, Node *sfpt_ctl, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, AllocateNode *alloc) {
assert(adr_t->is_known_instance_field(), "instance required");
int instance_id = adr_t->instance_id();
assert((uint)instance_id == alloc->_idx, "wrong allocation");
@@ -538,6 +605,8 @@
} else {
done = true;
}
+ } else if (mem->is_ArrayCopy()) {
+ done = true;
} else {
assert(false, "unexpected node");
}
@@ -562,6 +631,13 @@
value_phis.pop();
}
}
+ } else if (mem->is_ArrayCopy()) {
+ Node* ctl = mem->in(0);
+ if (sfpt_ctl->is_Proj() && sfpt_ctl->as_Proj()->is_uncommon_trap_proj(Deoptimization::Reason_none)) {
+ // pin the loads in the uncommon trap path
+ ctl = sfpt_ctl;
+ }
+ return make_arraycopy_load(mem->as_ArrayCopy(), offset, ctl, ft, ftype, alloc);
}
}
// Something go wrong.
@@ -738,6 +814,7 @@
while (safepoints.length() > 0) {
SafePointNode* sfpt = safepoints.pop();
Node* mem = sfpt->memory();
+ Node* ctl = sfpt->control();
assert(sfpt->jvms() != NULL, "missed JVMS");
// Fields of scalar objs are referenced only at the end
// of regular debuginfo at the last (youngest) JVMS.
@@ -789,7 +866,7 @@
const TypeOopPtr *field_addr_type = res_type->add_offset(offset)->isa_oopptr();
- Node *field_val = value_from_mem(mem, basic_elem_type, field_type, field_addr_type, alloc);
+ Node *field_val = value_from_mem(mem, ctl, basic_elem_type, field_type, field_addr_type, alloc);
if (field_val == NULL) {
// We weren't able to find a value for this field,
// give up on eliminating this allocation.
--- a/hotspot/src/share/vm/opto/macro.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/opto/macro.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -85,8 +85,8 @@
Node* length,
const TypeFunc* slow_call_type,
address slow_call_address);
- Node *value_from_mem(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, Node *alloc);
- Node *value_from_mem_phi(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, Node *alloc, Node_Stack *value_phis, int level);
+ Node *value_from_mem(Node *mem, Node *ctl, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, AllocateNode *alloc);
+ Node *value_from_mem_phi(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, AllocateNode *alloc, Node_Stack *value_phis, int level);
bool eliminate_boxing_node(CallStaticJavaNode *boxing);
bool eliminate_allocate_node(AllocateNode *alloc);
@@ -200,6 +200,8 @@
Node* old_eden_top, Node* new_eden_top,
Node* length);
+ Node* make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, BasicType ft, const Type *ftype, AllocateNode *alloc);
+
public:
PhaseMacroExpand(PhaseIterGVN &igvn) : Phase(Macro_Expand), _igvn(igvn), _has_locks(false) {
_igvn.set_delay_transform(true);
--- a/hotspot/src/share/vm/opto/memnode.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/opto/memnode.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -108,37 +108,6 @@
#endif
-static bool membar_for_arraycopy_helper(const TypeOopPtr *t_oop, Node* n, PhaseTransform *phase) {
- if (n->is_Proj()) {
- n = n->in(0);
- if (n->is_Call() && n->as_Call()->may_modify(t_oop, phase)) {
- return true;
- }
- }
- return false;
-}
-
-static bool membar_for_arraycopy(const TypeOopPtr *t_oop, MemBarNode* mb, PhaseTransform *phase) {
- Node* mem = mb->in(TypeFunc::Memory);
-
- if (mem->is_MergeMem()) {
- Node* n = mem->as_MergeMem()->memory_at(Compile::AliasIdxRaw);
- if (membar_for_arraycopy_helper(t_oop, n, phase)) {
- return true;
- } else if (n->is_Phi()) {
- for (uint i = 1; i < n->req(); i++) {
- if (n->in(i) != NULL) {
- if (membar_for_arraycopy_helper(t_oop, n->in(i), phase)) {
- return true;
- }
- }
- }
- }
- }
-
- return false;
-}
-
Node *MemNode::optimize_simple_memory_chain(Node *mchain, const TypeOopPtr *t_oop, Node *load, PhaseGVN *phase) {
assert((t_oop != NULL), "sanity");
bool is_instance = t_oop->is_known_instance_field();
@@ -183,7 +152,7 @@
}
}
} else if (proj_in->is_MemBar()) {
- if (membar_for_arraycopy(t_oop, proj_in->as_MemBar(), phase)) {
+ if (ArrayCopyNode::may_modify(t_oop, proj_in->as_MemBar(), phase)) {
break;
}
result = proj_in->in(TypeFunc::Memory);
@@ -545,35 +514,12 @@
Node* dest = ac->in(ArrayCopyNode::Dest);
if (dest == ld_base) {
- Node* src_pos = ac->in(ArrayCopyNode::SrcPos);
- Node* dest_pos = ac->in(ArrayCopyNode::DestPos);
- Node* len = ac->in(ArrayCopyNode::Length);
-
- const TypeInt *dest_pos_t = phase->type(dest_pos)->isa_int();
const TypeX *ld_offs_t = phase->type(ld_offs)->isa_intptr_t();
- const TypeInt *len_t = phase->type(len)->isa_int();
- const TypeAryPtr* ary_t = phase->type(dest)->isa_aryptr();
-
- if (dest_pos_t != NULL && ld_offs_t != NULL && len_t != NULL && ary_t != NULL) {
- BasicType ary_elem = ary_t->klass()->as_array_klass()->element_type()->basic_type();
- uint header = arrayOopDesc::base_offset_in_bytes(ary_elem);
- uint elemsize = type2aelembytes(ary_elem);
-
- intptr_t dest_pos_plus_len_lo = (((intptr_t)dest_pos_t->_lo) + len_t->_lo) * elemsize + header;
- intptr_t dest_pos_plus_len_hi = (((intptr_t)dest_pos_t->_hi) + len_t->_hi) * elemsize + header;
- intptr_t dest_pos_lo = ((intptr_t)dest_pos_t->_lo) * elemsize + header;
- intptr_t dest_pos_hi = ((intptr_t)dest_pos_t->_hi) * elemsize + header;
-
- if (can_see_stored_value) {
- if (ld_offs_t->_lo >= dest_pos_hi && ld_offs_t->_hi < dest_pos_plus_len_lo) {
- return ac;
- }
- } else {
- if (ld_offs_t->_hi < dest_pos_lo || ld_offs_t->_lo >= dest_pos_plus_len_hi) {
- mem = ac->in(TypeFunc::Memory);
- }
- return ac;
- }
+ if (ac->modifies(ld_offs_t->_lo, ld_offs_t->_hi, phase, can_see_stored_value)) {
+ return ac;
+ }
+ if (!can_see_stored_value) {
+ mem = ac->in(TypeFunc::Memory);
}
}
}
@@ -703,7 +649,7 @@
continue; // (a) advance through independent call memory
}
} else if (mem->is_Proj() && mem->in(0)->is_MemBar()) {
- if (membar_for_arraycopy(addr_t, mem->in(0)->as_MemBar(), phase)) {
+ if (ArrayCopyNode::may_modify(addr_t, mem->in(0)->as_MemBar(), phase)) {
break;
}
mem = mem->in(0)->in(TypeFunc::Memory);
@@ -883,18 +829,17 @@
// Is the value loaded previously stored by an arraycopy? If so return
// a load node that reads from the source array so we may be able to
// optimize out the ArrayCopy node later.
-Node* MemNode::can_see_arraycopy_value(Node* st, PhaseTransform* phase) const {
+Node* LoadNode::can_see_arraycopy_value(Node* st, PhaseTransform* phase) const {
Node* ld_adr = in(MemNode::Address);
intptr_t ld_off = 0;
AllocateNode* ld_alloc = AllocateNode::Ideal_allocation(ld_adr, phase, ld_off);
Node* ac = find_previous_arraycopy(phase, ld_alloc, st, true);
if (ac != NULL) {
assert(ac->is_ArrayCopy(), "what kind of node can this be?");
- assert(is_Load(), "only for loads");
-
+
+ Node* ld = clone();
if (ac->as_ArrayCopy()->is_clonebasic()) {
assert(ld_alloc != NULL, "need an alloc");
- Node* ld = clone();
Node* addp = in(MemNode::Address)->clone();
assert(addp->is_AddP(), "address must be addp");
assert(addp->in(AddPNode::Base) == ac->in(ArrayCopyNode::Dest)->in(AddPNode::Base), "strange pattern");
@@ -906,9 +851,7 @@
assert(ld_alloc->in(0) != NULL, "alloc must have control");
ld->set_req(0, ld_alloc->in(0));
}
- return ld;
} else {
- Node* ld = clone();
Node* addp = in(MemNode::Address)->clone();
assert(addp->in(AddPNode::Base) == addp->in(AddPNode::Address), "should be");
addp->set_req(AddPNode::Base, ac->in(ArrayCopyNode::Src));
@@ -933,8 +876,10 @@
assert(ac->in(0) != NULL, "alloc must have control");
ld->set_req(0, ac->in(0));
}
- return ld;
}
+ // load depends on the tests that validate the arraycopy
+ ld->as_Load()->_depends_only_on_test = Pinned;
+ return ld;
}
return NULL;
}
@@ -2426,40 +2371,47 @@
Node* mem = in(MemNode::Memory);
Node* address = in(MemNode::Address);
-
// Back-to-back stores to same address? Fold em up. Generally
// unsafe if I have intervening uses... Also disallowed for StoreCM
// since they must follow each StoreP operation. Redundant StoreCMs
// are eliminated just before matching in final_graph_reshape.
- if (mem->is_Store() && mem->in(MemNode::Address)->eqv_uncast(address) &&
- mem->Opcode() != Op_StoreCM) {
- // Looking at a dead closed cycle of memory?
- assert(mem != mem->in(MemNode::Memory), "dead loop in StoreNode::Ideal");
-
- assert(Opcode() == mem->Opcode() ||
- phase->C->get_alias_index(adr_type()) == Compile::AliasIdxRaw,
- "no mismatched stores, except on raw memory");
-
- if (mem->outcnt() == 1 && // check for intervening uses
- mem->as_Store()->memory_size() <= this->memory_size()) {
- // If anybody other than 'this' uses 'mem', we cannot fold 'mem' away.
- // For example, 'mem' might be the final state at a conditional return.
- // Or, 'mem' might be used by some node which is live at the same time
- // 'this' is live, which might be unschedulable. So, require exactly
- // ONE user, the 'this' store, until such time as we clone 'mem' for
- // each of 'mem's uses (thus making the exactly-1-user-rule hold true).
- if (can_reshape) { // (%%% is this an anachronism?)
- set_req_X(MemNode::Memory, mem->in(MemNode::Memory),
- phase->is_IterGVN());
- } else {
- // It's OK to do this in the parser, since DU info is always accurate,
- // and the parser always refers to nodes via SafePointNode maps.
- set_req(MemNode::Memory, mem->in(MemNode::Memory));
+ {
+ Node* st = mem;
+ // If Store 'st' has more than one use, we cannot fold 'st' away.
+ // For example, 'st' might be the final state at a conditional
+ // return. Or, 'st' might be used by some node which is live at
+ // the same time 'st' is live, which might be unschedulable. So,
+ // require exactly ONE user until such time as we clone 'mem' for
+ // each of 'mem's uses (thus making the exactly-1-user-rule hold
+ // true).
+ while (st->is_Store() && st->outcnt() == 1 && st->Opcode() != Op_StoreCM) {
+ // Looking at a dead closed cycle of memory?
+ assert(st != st->in(MemNode::Memory), "dead loop in StoreNode::Ideal");
+ assert(Opcode() == st->Opcode() ||
+ st->Opcode() == Op_StoreVector ||
+ Opcode() == Op_StoreVector ||
+ phase->C->get_alias_index(adr_type()) == Compile::AliasIdxRaw ||
+ (Opcode() == Op_StoreL && st->Opcode() == Op_StoreI), // expanded ClearArrayNode
+ err_msg_res("no mismatched stores, except on raw memory: %s %s", NodeClassNames[Opcode()], NodeClassNames[st->Opcode()]));
+
+ if (st->in(MemNode::Address)->eqv_uncast(address) &&
+ st->as_Store()->memory_size() <= this->memory_size()) {
+ Node* use = st->raw_out(0);
+ phase->igvn_rehash_node_delayed(use);
+ if (can_reshape) {
+ use->set_req_X(MemNode::Memory, st->in(MemNode::Memory), phase->is_IterGVN());
+ } else {
+ // It's OK to do this in the parser, since DU info is always accurate,
+ // and the parser always refers to nodes via SafePointNode maps.
+ use->set_req(MemNode::Memory, st->in(MemNode::Memory));
+ }
+ return this;
}
- return this;
+ st = st->in(MemNode::Memory);
}
}
+
// Capture an unaliased, unconditional, simple store into an initializer.
// Or, if it is independent of the allocation, hoist it above the allocation.
if (ReduceFieldZeroing && /*can_reshape &&*/
--- a/hotspot/src/share/vm/opto/memnode.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/opto/memnode.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -126,7 +126,6 @@
// Can this node (load or store) accurately see a stored value in
// the given memory state? (The state may or may not be in(Memory).)
Node* can_see_stored_value(Node* st, PhaseTransform* phase) const;
- Node* can_see_arraycopy_value(Node* st, PhaseTransform* phase) const;
#ifndef PRODUCT
static void dump_adr_type(const Node* mem, const TypePtr* adr_type, outputStream *st);
@@ -252,6 +251,9 @@
protected:
const Type* load_array_final_field(const TypeKlassPtr *tkls,
ciKlass* klass) const;
+
+ Node* can_see_arraycopy_value(Node* st, PhaseTransform* phase) const;
+
// depends_only_on_test is almost always true, and needs to be almost always
// true to enable key hoisting & commoning optimizations. However, for the
// special case of RawPtr loads from TLS top & end, and other loads performed by
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -3771,7 +3771,7 @@
// Deoptimize all activations depending on marked nmethods
Deoptimization::deoptimize_dependents();
- // Make the dependent methods not entrant (in VM_Deoptimize they are made zombies)
+ // Make the dependent methods not entrant
CodeCache::make_marked_nmethods_not_entrant();
// From now on we know that the dependency information is complete
--- a/hotspot/src/share/vm/runtime/arguments.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -81,8 +81,6 @@
bool Arguments::_has_profile = false;
size_t Arguments::_conservative_max_heap_alignment = 0;
size_t Arguments::_min_heap_size = 0;
-uintx Arguments::_min_heap_free_ratio = 0;
-uintx Arguments::_max_heap_free_ratio = 0;
Arguments::Mode Arguments::_mode = _mixed;
bool Arguments::_java_compiler = false;
bool Arguments::_xdebug_mode = false;
@@ -1614,11 +1612,9 @@
// unless the user actually sets these flags.
if (FLAG_IS_DEFAULT(MinHeapFreeRatio)) {
FLAG_SET_DEFAULT(MinHeapFreeRatio, 0);
- _min_heap_free_ratio = MinHeapFreeRatio;
}
if (FLAG_IS_DEFAULT(MaxHeapFreeRatio)) {
FLAG_SET_DEFAULT(MaxHeapFreeRatio, 100);
- _max_heap_free_ratio = MaxHeapFreeRatio;
}
}
@@ -3978,15 +3974,6 @@
return JNI_OK;
}
-// Any custom code post the 'CommandLineFlagConstraint::AfterErgo' constraint check
-// can be done here. We pass a flag that specifies whether
-// the check passed successfully
-void Arguments::post_after_ergo_constraint_check(bool check_passed) {
- // This does not set the flag itself, but stores the value in a safe place for later usage.
- _min_heap_free_ratio = MinHeapFreeRatio;
- _max_heap_free_ratio = MaxHeapFreeRatio;
-}
-
int Arguments::PropertyList_count(SystemProperty* pl) {
int count = 0;
while(pl != NULL) {
--- a/hotspot/src/share/vm/runtime/arguments.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/arguments.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -288,10 +288,6 @@
static uintx _min_heap_size;
- // Used to store original flag values
- static uintx _min_heap_free_ratio;
- static uintx _max_heap_free_ratio;
-
// -Xrun arguments
static AgentLibraryList _libraryList;
static void add_init_library(const char* name, char* options)
@@ -463,8 +459,6 @@
static jint apply_ergo();
// Adjusts the arguments after the OS have adjusted the arguments
static jint adjust_after_os();
- // Set any arguments that need to be set after the 'CommandLineFlagConstraint::AfterErgo' constraint check
- static void post_after_ergo_constraint_check(bool check_passed);
static void set_gc_specific_flags();
static inline bool gc_selected(); // whether a gc has been selected
@@ -526,10 +520,6 @@
static size_t min_heap_size() { return _min_heap_size; }
static void set_min_heap_size(size_t v) { _min_heap_size = v; }
- // Returns the original values of -XX:MinHeapFreeRatio and -XX:MaxHeapFreeRatio
- static uintx min_heap_free_ratio() { return _min_heap_free_ratio; }
- static uintx max_heap_free_ratio() { return _max_heap_free_ratio; }
-
// -Xrun
static AgentLibrary* libraries() { return _libraryList.first(); }
static bool init_libraries_at_startup() { return !_libraryList.is_empty(); }
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -45,8 +45,8 @@
_constraint=func;
}
- Flag::Error apply_bool(bool* value, bool verbose) {
- return _constraint(verbose, value);
+ Flag::Error apply_bool(bool value, bool verbose) {
+ return _constraint(value, verbose);
}
};
@@ -61,8 +61,8 @@
_constraint=func;
}
- Flag::Error apply_int(int* value, bool verbose) {
- return _constraint(verbose, value);
+ Flag::Error apply_int(int value, bool verbose) {
+ return _constraint(value, verbose);
}
};
@@ -77,8 +77,8 @@
_constraint=func;
}
- Flag::Error apply_intx(intx* value, bool verbose) {
- return _constraint(verbose, value);
+ Flag::Error apply_intx(intx value, bool verbose) {
+ return _constraint(value, verbose);
}
};
@@ -93,8 +93,8 @@
_constraint=func;
}
- Flag::Error apply_uint(uint* value, bool verbose) {
- return _constraint(verbose, value);
+ Flag::Error apply_uint(uint value, bool verbose) {
+ return _constraint(value, verbose);
}
};
@@ -109,8 +109,8 @@
_constraint=func;
}
- Flag::Error apply_uintx(uintx* value, bool verbose) {
- return _constraint(verbose, value);
+ Flag::Error apply_uintx(uintx value, bool verbose) {
+ return _constraint(value, verbose);
}
};
@@ -125,8 +125,8 @@
_constraint=func;
}
- Flag::Error apply_uint64_t(uint64_t* value, bool verbose) {
- return _constraint(verbose, value);
+ Flag::Error apply_uint64_t(uint64_t value, bool verbose) {
+ return _constraint(value, verbose);
}
};
@@ -141,8 +141,8 @@
_constraint=func;
}
- Flag::Error apply_size_t(size_t* value, bool verbose) {
- return _constraint(verbose, value);
+ Flag::Error apply_size_t(size_t value, bool verbose) {
+ return _constraint(value, verbose);
}
};
@@ -157,8 +157,8 @@
_constraint=func;
}
- Flag::Error apply_double(double* value, bool verbose) {
- return _constraint(verbose, value);
+ Flag::Error apply_double(double value, bool verbose) {
+ return _constraint(value, verbose);
}
};
@@ -226,7 +226,6 @@
// Check the ranges of all flags that have them or print them out and exit if requested
void CommandLineFlagConstraintList::init(void) {
-
_constraints = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<CommandLineFlagConstraint*>(INITIAL_CONSTRAINTS_SIZE, true);
emit_constraint_no(NULL RUNTIME_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG,
@@ -306,40 +305,6 @@
// Check constraints for specific constraint type.
bool CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::ConstraintType type) {
-//#define PRINT_CONSTRAINTS_SIZES
-#ifdef PRINT_CONSTRAINTS_SIZES
- {
- size_t size_constraints = sizeof(CommandLineFlagConstraintList);
- for (int i=0; i<length(); i++) {
- size_constraints += sizeof(CommandLineFlagConstraint);
- CommandLineFlagConstraint* constraint = at(i);
- const char* name = constraint->name();
- Flag* flag = Flag::find_flag(name, strlen(name), true, true);
- if (flag->is_bool()) {
- size_constraints += sizeof(CommandLineFlagConstraintFunc_bool);
- size_constraints += sizeof(CommandLineFlagConstraint*);
- } else if (flag->is_intx()) {
- size_constraints += sizeof(CommandLineFlagConstraintFunc_intx);
- size_constraints += sizeof(CommandLineFlagConstraint*);
- } else if (flag->is_uintx()) {
- size_constraints += sizeof(CommandLineFlagConstraintFunc_uintx);
- size_constraints += sizeof(CommandLineFlagConstraint*);
- } else if (flag->is_uint64_t()) {
- size_constraints += sizeof(CommandLineFlagConstraintFunc_uint64_t);
- size_constraints += sizeof(CommandLineFlagConstraint*);
- } else if (flag->is_size_t()) {
- size_constraints += sizeof(CommandLineFlagConstraintFunc_size_t);
- size_constraints += sizeof(CommandLineFlagConstraint*);
- } else if (flag->is_double()) {
- size_constraints += sizeof(CommandLineFlagConstraintFunc_double);
- size_constraints += sizeof(CommandLineFlagConstraint*);
- }
- }
- fprintf(stderr, "Size of %d constraints: " SIZE_FORMAT " bytes\n",
- length(), size_constraints);
- }
-#endif // PRINT_CONSTRAINTS_SIZES
-
// Skip if we already checked.
if (type < _validating_type) {
return true;
@@ -350,27 +315,36 @@
for (int i=0; i<length(); i++) {
CommandLineFlagConstraint* constraint = at(i);
if (type != constraint->type()) continue;
- const char*name = constraint->name();
+ const char* name = constraint->name();
Flag* flag = Flag::find_flag(name, strlen(name), true, true);
+ // We must check for NULL here as lp64_product flags on 32 bit architecture
+ // can generate constraint check (despite that they are declared as constants),
+ // but they will not be returned by Flag::find_flag()
if (flag != NULL) {
if (flag->is_bool()) {
bool value = flag->get_bool();
- if (constraint->apply_bool(&value, true) != Flag::SUCCESS) status = false;
+ if (constraint->apply_bool(value, true) != Flag::SUCCESS) status = false;
+ } else if (flag->is_int()) {
+ int value = flag->get_int();
+ if (constraint->apply_int(value, true) != Flag::SUCCESS) status = false;
+ } else if (flag->is_uint()) {
+ uint value = flag->get_uint();
+ if (constraint->apply_uint(value, true) != Flag::SUCCESS) status = false;
} else if (flag->is_intx()) {
intx value = flag->get_intx();
- if (constraint->apply_intx(&value, true) != Flag::SUCCESS) status = false;
+ if (constraint->apply_intx(value, true) != Flag::SUCCESS) status = false;
} else if (flag->is_uintx()) {
uintx value = flag->get_uintx();
- if (constraint->apply_uintx(&value, true) != Flag::SUCCESS) status = false;
+ if (constraint->apply_uintx(value, true) != Flag::SUCCESS) status = false;
} else if (flag->is_uint64_t()) {
uint64_t value = flag->get_uint64_t();
- if (constraint->apply_uint64_t(&value, true) != Flag::SUCCESS) status = false;
+ if (constraint->apply_uint64_t(value, true) != Flag::SUCCESS) status = false;
} else if (flag->is_size_t()) {
size_t value = flag->get_size_t();
- if (constraint->apply_size_t(&value, true) != Flag::SUCCESS) status = false;
+ if (constraint->apply_size_t(value, true) != Flag::SUCCESS) status = false;
} else if (flag->is_double()) {
double value = flag->get_double();
- if (constraint->apply_double(&value, true) != Flag::SUCCESS) status = false;
+ if (constraint->apply_double(value, true) != Flag::SUCCESS) status = false;
}
}
}
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -39,14 +39,14 @@
* "runtime/commandLineFlagConstraintsRuntime.hpp" for the functions themselves.
*/
-typedef Flag::Error (*CommandLineFlagConstraintFunc_bool)(bool verbose, bool* value);
-typedef Flag::Error (*CommandLineFlagConstraintFunc_int)(bool verbose, int* value);
-typedef Flag::Error (*CommandLineFlagConstraintFunc_intx)(bool verbose, intx* value);
-typedef Flag::Error (*CommandLineFlagConstraintFunc_uint)(bool verbose, uint* value);
-typedef Flag::Error (*CommandLineFlagConstraintFunc_uintx)(bool verbose, uintx* value);
-typedef Flag::Error (*CommandLineFlagConstraintFunc_uint64_t)(bool verbose, uint64_t* value);
-typedef Flag::Error (*CommandLineFlagConstraintFunc_size_t)(bool verbose, size_t* value);
-typedef Flag::Error (*CommandLineFlagConstraintFunc_double)(bool verbose, double* value);
+typedef Flag::Error (*CommandLineFlagConstraintFunc_bool)(bool value, bool verbose);
+typedef Flag::Error (*CommandLineFlagConstraintFunc_int)(int value, bool verbose);
+typedef Flag::Error (*CommandLineFlagConstraintFunc_intx)(intx value, bool verbose);
+typedef Flag::Error (*CommandLineFlagConstraintFunc_uint)(uint value, bool verbose);
+typedef Flag::Error (*CommandLineFlagConstraintFunc_uintx)(uintx value, bool verbose);
+typedef Flag::Error (*CommandLineFlagConstraintFunc_uint64_t)(uint64_t value, bool verbose);
+typedef Flag::Error (*CommandLineFlagConstraintFunc_size_t)(size_t value, bool verbose);
+typedef Flag::Error (*CommandLineFlagConstraintFunc_double)(double value, bool verbose);
class CommandLineFlagConstraint : public CHeapObj<mtInternal> {
public:
@@ -70,14 +70,14 @@
~CommandLineFlagConstraint() {};
const char* name() const { return _name; }
ConstraintType type() const { return _validate_type; }
- virtual Flag::Error apply_bool(bool* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
- virtual Flag::Error apply_int(int* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
- virtual Flag::Error apply_intx(intx* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
- virtual Flag::Error apply_uint(uint* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
- virtual Flag::Error apply_uintx(uintx* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
- virtual Flag::Error apply_uint64_t(uint64_t* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
- virtual Flag::Error apply_size_t(size_t* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
- virtual Flag::Error apply_double(double* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+ virtual Flag::Error apply_bool(bool value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+ virtual Flag::Error apply_int(int value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+ virtual Flag::Error apply_intx(intx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+ virtual Flag::Error apply_uint(uint value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+ virtual Flag::Error apply_uintx(uintx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+ virtual Flag::Error apply_uint64_t(uint64_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+ virtual Flag::Error apply_size_t(size_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+ virtual Flag::Error apply_double(double value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
};
class CommandLineFlagConstraintList : public AllStatic {
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -25,17 +25,16 @@
#include "precompiled.hpp"
#include "runtime/arguments.hpp"
#include "runtime/commandLineFlagConstraintsCompiler.hpp"
+#include "runtime/commandLineFlagRangeList.hpp"
#include "runtime/globals.hpp"
#include "utilities/defaultStream.hpp"
-Flag::Error AliasLevelConstraintFunc(bool verbose, intx* value) {
- if ((*value <= 1) && (Arguments::mode() == Arguments::_comp)) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "AliasLevel (" INTX_FORMAT ") is not compatible "
- "with -Xcomp \n",
- *value);
- }
+Flag::Error AliasLevelConstraintFunc(intx value, bool verbose) {
+ if ((value <= 1) && (Arguments::mode() == Arguments::_comp)) {
+ CommandLineError::print(verbose,
+ "AliasLevel (" INTX_FORMAT ") is not "
+ "compatible with -Xcomp \n",
+ value);
return Flag::VIOLATES_CONSTRAINT;
} else {
return Flag::SUCCESS;
@@ -57,7 +56,7 @@
* 'TieredStopAtLevel = CompLevel_full_optimization' (the default value). As a result,
* the minimum number of compiler threads is 2.
*/
-Flag::Error CICompilerCountConstraintFunc(bool verbose, intx* value) {
+Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose) {
int min_number_of_compiler_threads = 0;
#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK)
// case 1
@@ -75,12 +74,11 @@
// min_number_of_compiler_threads to exceed CI_COMPILER_COUNT.
min_number_of_compiler_threads = MIN2(min_number_of_compiler_threads, CI_COMPILER_COUNT);
- if (*value < (intx)min_number_of_compiler_threads) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "CICompilerCount=" INTX_FORMAT " must be at least %d \n",
- *value, min_number_of_compiler_threads);
- }
+ if (value < (intx)min_number_of_compiler_threads) {
+ CommandLineError::print(verbose,
+ "CICompilerCount (" INTX_FORMAT ") must be "
+ "at least %d \n",
+ value, min_number_of_compiler_threads);
return Flag::VIOLATES_CONSTRAINT;
} else {
return Flag::SUCCESS;
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -34,8 +34,8 @@
* an appropriate error value.
*/
-Flag::Error AliasLevelConstraintFunc(bool verbose, intx* value);
+Flag::Error AliasLevelConstraintFunc(intx value, bool verbose);
-Flag::Error CICompilerCountConstraintFunc(bool verbose, intx* value);
+Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose);
#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP */
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "runtime/arguments.hpp"
#include "runtime/commandLineFlagConstraintsGC.hpp"
+#include "runtime/commandLineFlagRangeList.hpp"
#include "runtime/globals.hpp"
#include "utilities/defaultStream.hpp"
@@ -41,97 +42,85 @@
#include "opto/c2_globals.hpp"
#endif // COMPILER2
-static Flag::Error MinPLABSizeBounds(const char* name, bool verbose, size_t* value) {
+static Flag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbose) {
#if INCLUDE_ALL_GCS
- if ((UseConcMarkSweepGC || UseG1GC) && (*value < PLAB::min_size())) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "%s (" SIZE_FORMAT ") must be greater than "
- "ergonomic PLAB minimum size (" SIZE_FORMAT ")\n",
- name, *value, PLAB::min_size());
- }
+ if ((UseConcMarkSweepGC || UseG1GC) && (value < PLAB::min_size())) {
+ CommandLineError::print(verbose,
+ "%s (" SIZE_FORMAT ") must be "
+ "greater than or equal to ergonomic PLAB minimum size (" SIZE_FORMAT ")\n",
+ name, value, PLAB::min_size());
return Flag::VIOLATES_CONSTRAINT;
}
#endif // INCLUDE_ALL_GCS
return Flag::SUCCESS;
}
-static Flag::Error MaxPLABSizeBounds(const char* name, bool verbose, size_t* value) {
+static Flag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose) {
#if INCLUDE_ALL_GCS
- if ((UseConcMarkSweepGC || UseG1GC) && (*value > PLAB::max_size())) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "%s (" SIZE_FORMAT ") must be less than "
- "ergonomic PLAB maximum size (" SIZE_FORMAT ")\n",
- name, *value, PLAB::max_size());
- }
+ if ((UseConcMarkSweepGC || UseG1GC) && (value > PLAB::max_size())) {
+ CommandLineError::print(verbose,
+ "%s (" SIZE_FORMAT ") must be "
+ "less than ergonomic PLAB maximum size (" SIZE_FORMAT ")\n",
+ name, value, PLAB::min_size());
return Flag::VIOLATES_CONSTRAINT;
}
#endif // INCLUDE_ALL_GCS
return Flag::SUCCESS;
}
-static Flag::Error MinMaxPLABSizeBounds(const char* name, bool verbose, size_t* value) {
- if (MinPLABSizeBounds(name, verbose, value) == Flag::SUCCESS) {
- return MaxPLABSizeBounds(name, verbose, value);
+static Flag::Error MinMaxPLABSizeBounds(const char* name, size_t value, bool verbose) {
+ if (MinPLABSizeBounds(name, value, verbose) == Flag::SUCCESS) {
+ return MaxPLABSizeBounds(name, value, verbose);
}
return Flag::VIOLATES_CONSTRAINT;
}
-Flag::Error YoungPLABSizeConstraintFunc(bool verbose, size_t* value) {
- return MinMaxPLABSizeBounds("YoungPLABSize", verbose, value);
+Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose) {
+ return MinMaxPLABSizeBounds("YoungPLABSize", value, verbose);
}
-Flag::Error MinHeapFreeRatioConstraintFunc(bool verbose, uintx* value) {
- if (*value > MaxHeapFreeRatio) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "MinHeapFreeRatio (" UINTX_FORMAT ") must be less than or "
- "equal to MaxHeapFreeRatio (" UINTX_FORMAT ")\n",
- *value, MaxHeapFreeRatio);
- }
+Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose) {
+ if (value > MaxHeapFreeRatio) {
+ CommandLineError::print(verbose,
+ "MinHeapFreeRatio (" UINTX_FORMAT ") must be "
+ "less than or equal to MaxHeapFreeRatio (" UINTX_FORMAT ")\n",
+ value, MaxHeapFreeRatio);
return Flag::VIOLATES_CONSTRAINT;
} else {
return Flag::SUCCESS;
}
}
-Flag::Error MaxHeapFreeRatioConstraintFunc(bool verbose, uintx* value) {
- if (*value < MinHeapFreeRatio) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "MaxHeapFreeRatio (" UINTX_FORMAT ") must be greater than or "
- "equal to MinHeapFreeRatio (" UINTX_FORMAT ")\n",
- *value, MinHeapFreeRatio);
- }
+Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose) {
+ if (value < MinHeapFreeRatio) {
+ CommandLineError::print(verbose,
+ "MaxHeapFreeRatio (" UINTX_FORMAT ") must be "
+ "greater than or equal to MinHeapFreeRatio (" UINTX_FORMAT ")\n",
+ value, MinHeapFreeRatio);
return Flag::VIOLATES_CONSTRAINT;
} else {
return Flag::SUCCESS;
}
}
-Flag::Error MinMetaspaceFreeRatioConstraintFunc(bool verbose, uintx* value) {
- if (*value > MaxMetaspaceFreeRatio) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "MinMetaspaceFreeRatio (" UINTX_FORMAT ") must be less than or "
- "equal to MaxMetaspaceFreeRatio (" UINTX_FORMAT ")\n",
- *value, MaxMetaspaceFreeRatio);
- }
+Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) {
+ if (value > MaxMetaspaceFreeRatio) {
+ CommandLineError::print(verbose,
+ "MinMetaspaceFreeRatio (" UINTX_FORMAT ") must be "
+ "less than or equal to MaxMetaspaceFreeRatio (" UINTX_FORMAT ")\n",
+ value, MaxMetaspaceFreeRatio);
return Flag::VIOLATES_CONSTRAINT;
} else {
return Flag::SUCCESS;
}
}
-Flag::Error MaxMetaspaceFreeRatioConstraintFunc(bool verbose, uintx* value) {
- if (*value < MinMetaspaceFreeRatio) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "MaxMetaspaceFreeRatio (" UINTX_FORMAT ") must be greater than or "
- "equal to MinMetaspaceFreeRatio (" UINTX_FORMAT ")\n",
- *value, MinMetaspaceFreeRatio);
- }
+Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) {
+ if (value < MinMetaspaceFreeRatio) {
+ CommandLineError::print(verbose,
+ "MaxMetaspaceFreeRatio (" UINTX_FORMAT ") must be "
+ "greater than or equal to MinMetaspaceFreeRatio (" UINTX_FORMAT ")\n",
+ value, MinMetaspaceFreeRatio);
return Flag::VIOLATES_CONSTRAINT;
} else {
return Flag::SUCCESS;
@@ -147,32 +136,28 @@
} \
}
-Flag::Error InitialTenuringThresholdConstraintFunc(bool verbose, uintx* value) {
- UseConcMarkSweepGCWorkaroundIfNeeded(*value, MaxTenuringThreshold);
+Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose) {
+ UseConcMarkSweepGCWorkaroundIfNeeded(value, MaxTenuringThreshold);
- if (*value > MaxTenuringThreshold) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "InitialTenuringThreshold (" UINTX_FORMAT ") must be less than or "
- "equal to MaxTenuringThreshold (" UINTX_FORMAT ")\n",
- *value, MaxTenuringThreshold);
- }
+ if (value > MaxTenuringThreshold) {
+ CommandLineError::print(verbose,
+ "InitialTenuringThreshold (" UINTX_FORMAT ") must be "
+ "less than or equal to MaxTenuringThreshold (" UINTX_FORMAT ")\n",
+ value, MaxTenuringThreshold);
return Flag::VIOLATES_CONSTRAINT;
} else {
return Flag::SUCCESS;
}
}
-Flag::Error MaxTenuringThresholdConstraintFunc(bool verbose, uintx* value) {
- UseConcMarkSweepGCWorkaroundIfNeeded(InitialTenuringThreshold, *value);
+Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) {
+ UseConcMarkSweepGCWorkaroundIfNeeded(InitialTenuringThreshold, value);
- if (*value < InitialTenuringThreshold) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "MaxTenuringThreshold (" UINTX_FORMAT ") must be greater than or "
- "equal to InitialTenuringThreshold (" UINTX_FORMAT ")\n",
- *value, InitialTenuringThreshold);
- }
+ if (value < InitialTenuringThreshold) {
+ CommandLineError::print(verbose,
+ "MaxTenuringThreshold (" UINTX_FORMAT ") must be "
+ "greater than or equal to InitialTenuringThreshold (" UINTX_FORMAT ")\n",
+ value, InitialTenuringThreshold);
return Flag::VIOLATES_CONSTRAINT;
} else {
return Flag::SUCCESS;
@@ -180,28 +165,24 @@
}
#if INCLUDE_ALL_GCS
-Flag::Error G1NewSizePercentConstraintFunc(bool verbose, uintx* value) {
- if (*value > G1MaxNewSizePercent) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "G1NewSizePercent (" UINTX_FORMAT ") must be less than or "
- "equal to G1MaxNewSizePercent (" UINTX_FORMAT ")\n",
- *value, G1MaxNewSizePercent);
- }
+Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose) {
+ if (value > G1MaxNewSizePercent) {
+ CommandLineError::print(verbose,
+ "G1NewSizePercent (" UINTX_FORMAT ") must be "
+ "less than or equal to G1MaxNewSizePercent (" UINTX_FORMAT ")\n",
+ value, G1MaxNewSizePercent);
return Flag::VIOLATES_CONSTRAINT;
} else {
return Flag::SUCCESS;
}
}
-Flag::Error G1MaxNewSizePercentConstraintFunc(bool verbose, uintx* value) {
- if (*value < G1NewSizePercent) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "G1MaxNewSizePercent (" UINTX_FORMAT ") must be greater than or "
- "equal to G1NewSizePercent (" UINTX_FORMAT ")\n",
- *value, G1NewSizePercent);
- }
+Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose) {
+ if (value < G1NewSizePercent) {
+ CommandLineError::print(verbose,
+ "G1MaxNewSizePercent (" UINTX_FORMAT ") must be "
+ "greater than or equal to G1NewSizePercent (" UINTX_FORMAT ")\n",
+ value, G1NewSizePercent);
return Flag::VIOLATES_CONSTRAINT;
} else {
return Flag::SUCCESS;
@@ -210,65 +191,56 @@
#endif // INCLUDE_ALL_GCS
-Flag::Error CMSOldPLABMinConstraintFunc(bool verbose, size_t* value) {
- if (*value > CMSOldPLABMax) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "CMSOldPLABMin (" SIZE_FORMAT ") must be less than or "
- "equal to CMSOldPLABMax (" SIZE_FORMAT ")\n",
- *value, CMSOldPLABMax);
- }
+Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) {
+ if (value > CMSOldPLABMax) {
+ CommandLineError::print(verbose,
+ "CMSOldPLABMin (" SIZE_FORMAT ") must be "
+ "less than or equal to CMSOldPLABMax (" SIZE_FORMAT ")\n",
+ value, CMSOldPLABMax);
return Flag::VIOLATES_CONSTRAINT;
} else {
return Flag::SUCCESS;
}
}
-Flag::Error CMSPrecleanDenominatorConstraintFunc(bool verbose, uintx* value) {
- if (*value <= CMSPrecleanNumerator) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "CMSPrecleanDenominator (" UINTX_FORMAT ") must be strickly greater than "
- "CMSPrecleanNumerator (" UINTX_FORMAT ")\n",
- *value, CMSPrecleanNumerator);
- }
+Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose) {
+ if (value <= CMSPrecleanNumerator) {
+ CommandLineError::print(verbose,
+ "CMSPrecleanDenominator (" UINTX_FORMAT ") must be "
+ "strickly greater than CMSPrecleanNumerator (" UINTX_FORMAT ")\n",
+ value, CMSPrecleanNumerator);
return Flag::VIOLATES_CONSTRAINT;
} else {
return Flag::SUCCESS;
}
}
-Flag::Error CMSPrecleanNumeratorConstraintFunc(bool verbose, uintx* value) {
- if (*value > (CMSPrecleanDenominator - 1)) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "CMSPrecleanNumerator (" UINTX_FORMAT ") must be less than or "
- "equal to CMSPrecleanDenominator - 1 (" UINTX_FORMAT ")\n", *value,
- CMSPrecleanDenominator - 1);
- }
+Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) {
+ if (value > (CMSPrecleanDenominator - 1)) {
+ CommandLineError::print(verbose,
+ "CMSPrecleanNumerator (" UINTX_FORMAT ") must be "
+ "less than or equal to CMSPrecleanDenominator - 1 (" UINTX_FORMAT ")\n",
+ value, CMSPrecleanDenominator - 1);
return Flag::VIOLATES_CONSTRAINT;
} else {
return Flag::SUCCESS;
}
}
-Flag::Error SurvivorAlignmentInBytesConstraintFunc(bool verbose, intx* value) {
- if (*value != 0) {
- if (!is_power_of_2(*value)) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be power of 2\n",
- *value);
- }
+Flag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose) {
+ if (value != 0) {
+ if (!is_power_of_2(value)) {
+ CommandLineError::print(verbose,
+ "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be "
+ "power of 2\n",
+ value);
return Flag::VIOLATES_CONSTRAINT;
}
- if (*value < ObjectAlignmentInBytes) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be greater than or "
- "equal to ObjectAlignmentInBytes (" INTX_FORMAT ")\n",
- *value, ObjectAlignmentInBytes);
- }
+ if (value < ObjectAlignmentInBytes) {
+ CommandLineError::print(verbose,
+ "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be "
+ "greater than or equal to ObjectAlignmentInBytes (" INTX_FORMAT ")\n",
+ value, ObjectAlignmentInBytes);
return Flag::VIOLATES_CONSTRAINT;
}
}
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -34,27 +34,27 @@
* an appropriate error value.
*/
-Flag::Error YoungPLABSizeConstraintFunc(bool verbose, size_t* value);
+Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose);
-Flag::Error MinHeapFreeRatioConstraintFunc(bool verbose, uintx* value);
-Flag::Error MaxHeapFreeRatioConstraintFunc(bool verbose, uintx* value);
+Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose);
+Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose);
-Flag::Error MinMetaspaceFreeRatioConstraintFunc(bool verbose, uintx* value);
-Flag::Error MaxMetaspaceFreeRatioConstraintFunc(bool verbose, uintx* value);
+Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose);
+Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose);
-Flag::Error InitialTenuringThresholdConstraintFunc(bool verbose, uintx* value);
-Flag::Error MaxTenuringThresholdConstraintFunc(bool verbose, uintx* value);
+Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose);
+Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose);
#if INCLUDE_ALL_GCS
-Flag::Error G1NewSizePercentConstraintFunc(bool verbose, uintx* value);
-Flag::Error G1MaxNewSizePercentConstraintFunc(bool verbose, uintx* value);
+Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose);
+Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose);
#endif // INCLUDE_ALL_GCS
-Flag::Error CMSOldPLABMinConstraintFunc(bool verbose, size_t* value);
+Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose);
-Flag::Error CMSPrecleanDenominatorConstraintFunc(bool verbose, uintx* value);
-Flag::Error CMSPrecleanNumeratorConstraintFunc(bool verbose, uintx* value);
+Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose);
+Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose);
-Flag::Error SurvivorAlignmentInBytesConstraintFunc(bool verbose, intx* value);
+Flag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose);
#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSGC_HPP */
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -25,25 +25,24 @@
#include "precompiled.hpp"
#include "runtime/arguments.hpp"
#include "runtime/commandLineFlagConstraintsRuntime.hpp"
+#include "runtime/commandLineFlagRangeList.hpp"
#include "runtime/globals.hpp"
#include "utilities/defaultStream.hpp"
-Flag::Error ObjectAlignmentInBytesConstraintFunc(bool verbose, intx* value) {
- if (!is_power_of_2(*value)) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "ObjectAlignmentInBytes=" INTX_FORMAT " must be power of 2\n",
- *value);
- }
+Flag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose) {
+ if (!is_power_of_2(value)) {
+ CommandLineError::print(verbose,
+ "ObjectAlignmentInBytes (" INTX_FORMAT ") must be "
+ "power of 2\n",
+ value);
return Flag::VIOLATES_CONSTRAINT;
}
// In case page size is very small.
- if (*value >= (intx)os::vm_page_size()) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "ObjectAlignmentInBytes=" INTX_FORMAT " must be less than page size " INTX_FORMAT "\n",
- *value, (intx)os::vm_page_size());
- }
+ if (value >= (intx)os::vm_page_size()) {
+ CommandLineError::print(verbose,
+ "ObjectAlignmentInBytes (" INTX_FORMAT ") must be "
+ "less than page size " INTX_FORMAT "\n",
+ value, (intx)os::vm_page_size());
return Flag::VIOLATES_CONSTRAINT;
}
return Flag::SUCCESS;
@@ -51,13 +50,12 @@
// Need to enforce the padding not to break the existing field alignments.
// It is sufficient to check against the largest type size.
-Flag::Error ContendedPaddingWidthConstraintFunc(bool verbose, intx* value) {
- if ((*value != 0) && ((*value % BytesPerLong) != 0)) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "ContendedPaddingWidth=" INTX_FORMAT " must be a multiple of %d\n",
- *value, BytesPerLong);
- }
+Flag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose) {
+ if ((value != 0) && ((value % BytesPerLong) != 0)) {
+ CommandLineError::print(verbose,
+ "ContendedPaddingWidth (" INTX_FORMAT ") must be "
+ "a multiple of %d\n",
+ value, BytesPerLong);
return Flag::VIOLATES_CONSTRAINT;
} else {
return Flag::SUCCESS;
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -34,8 +34,8 @@
* an appropriate error value.
*/
-Flag::Error ObjectAlignmentInBytesConstraintFunc(bool verbose, intx* value);
+Flag::Error ObjectAlignmentInBytesConstraintFunc(intx value, bool verbose);
-Flag::Error ContendedPaddingWidthConstraintFunc(bool verbose, intx* value);
+Flag::Error ContendedPaddingWidthConstraintFunc(intx value, bool verbose);
#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSRUNTIME_HPP */
--- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -32,6 +32,15 @@
#include "utilities/defaultStream.hpp"
#include "utilities/macros.hpp"
+void CommandLineError::print(bool verbose, const char* msg, ...) {
+ if (verbose) {
+ va_list listPointer;
+ va_start(listPointer, msg);
+ jio_vfprintf(defaultStream::error_stream(), msg, listPointer);
+ va_end(listPointer);
+ }
+}
+
class CommandLineFlagRange_int : public CommandLineFlagRange {
int _min;
int _max;
@@ -44,11 +53,10 @@
Flag::Error check_int(int value, bool verbose = true) {
if ((value < _min) || (value > _max)) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "int %s=%d is outside the allowed range [ %d ... %d ]\n",
- name(), value, _min, _max);
- }
+ CommandLineError::print(verbose,
+ "int %s=%d is outside the allowed range "
+ "[ %d ... %d ]\n",
+ name(), value, _min, _max);
return Flag::OUT_OF_BOUNDS;
} else {
return Flag::SUCCESS;
@@ -72,11 +80,10 @@
Flag::Error check_intx(intx value, bool verbose = true) {
if ((value < _min) || (value > _max)) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "intx %s=" INTX_FORMAT " is outside the allowed range [ " INTX_FORMAT " ... " INTX_FORMAT " ]\n",
- name(), value, _min, _max);
- }
+ CommandLineError::print(verbose,
+ "intx %s=" INTX_FORMAT " is outside the allowed range "
+ "[ " INTX_FORMAT " ... " INTX_FORMAT " ]\n",
+ name(), value, _min, _max);
return Flag::OUT_OF_BOUNDS;
} else {
return Flag::SUCCESS;
@@ -100,11 +107,10 @@
Flag::Error check_uint(uint value, bool verbose = true) {
if ((value < _min) || (value > _max)) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "uintx %s=%u is outside the allowed range [ %u ... %u ]\n",
- name(), value, _min, _max);
- }
+ CommandLineError::print(verbose,
+ "uint %s=%u is outside the allowed range "
+ "[ %u ... %u ]\n",
+ name(), value, _min, _max);
return Flag::OUT_OF_BOUNDS;
} else {
return Flag::SUCCESS;
@@ -128,11 +134,10 @@
Flag::Error check_uintx(uintx value, bool verbose = true) {
if ((value < _min) || (value > _max)) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "uintx %s=" UINTX_FORMAT " is outside the allowed range [ " UINTX_FORMAT " ... " UINTX_FORMAT " ]\n",
- name(), value, _min, _max);
- }
+ CommandLineError::print(verbose,
+ "uintx %s=" UINTX_FORMAT " is outside the allowed range "
+ "[ " UINTX_FORMAT " ... " UINTX_FORMAT " ]\n",
+ name(), value, _min, _max);
return Flag::OUT_OF_BOUNDS;
} else {
return Flag::SUCCESS;
@@ -156,11 +161,10 @@
Flag::Error check_uint64_t(uint64_t value, bool verbose = true) {
if ((value < _min) || (value > _max)) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "uint64_t %s=" UINT64_FORMAT " is outside the allowed range [ " UINT64_FORMAT " ... " UINT64_FORMAT " ]\n",
- name(), value, _min, _max);
- }
+ CommandLineError::print(verbose,
+ "uint64_t %s=" UINT64_FORMAT " is outside the allowed range "
+ "[ " UINT64_FORMAT " ... " UINT64_FORMAT " ]\n",
+ name(), value, _min, _max);
return Flag::OUT_OF_BOUNDS;
} else {
return Flag::SUCCESS;
@@ -184,11 +188,10 @@
Flag::Error check_size_t(size_t value, bool verbose = true) {
if ((value < _min) || (value > _max)) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "size_t %s=" SIZE_FORMAT " is outside the allowed range [ " SIZE_FORMAT " ... " SIZE_FORMAT " ]\n",
- name(), value, _min, _max);
- }
+ CommandLineError::print(verbose,
+ "size_t %s=" SIZE_FORMAT " is outside the allowed range "
+ "[ " SIZE_FORMAT " ... " SIZE_FORMAT " ]\n",
+ name(), value, _min, _max);
return Flag::OUT_OF_BOUNDS;
} else {
return Flag::SUCCESS;
@@ -212,11 +215,10 @@
Flag::Error check_double(double value, bool verbose = true) {
if ((value < _min) || (value > _max)) {
- if (verbose == true) {
- jio_fprintf(defaultStream::error_stream(),
- "double %s=%f is outside the allowed range [ %f ... %f ]\n",
- name(), value, _min, _max);
- }
+ CommandLineError::print(verbose,
+ "double %s=%f is outside the allowed range "
+ "[ %f ... %f ]\n",
+ name(), value, _min, _max);
return Flag::OUT_OF_BOUNDS;
} else {
return Flag::SUCCESS;
@@ -300,48 +302,48 @@
EMIT_RANGES_FOR_GLOBALS_EXT
emit_range_no(NULL ARCH_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
- EMIT_RANGE_PRODUCT_FLAG,
- EMIT_RANGE_DIAGNOSTIC_FLAG,
- EMIT_RANGE_EXPERIMENTAL_FLAG,
- EMIT_RANGE_NOTPRODUCT_FLAG,
- EMIT_RANGE_CHECK,
- IGNORE_CONSTRAINT));
+ EMIT_RANGE_PRODUCT_FLAG,
+ EMIT_RANGE_DIAGNOSTIC_FLAG,
+ EMIT_RANGE_EXPERIMENTAL_FLAG,
+ EMIT_RANGE_NOTPRODUCT_FLAG,
+ EMIT_RANGE_CHECK,
+ IGNORE_CONSTRAINT));
#ifdef COMPILER1
emit_range_no(NULL C1_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
- EMIT_RANGE_PD_DEVELOPER_FLAG,
- EMIT_RANGE_PRODUCT_FLAG,
- EMIT_RANGE_PD_PRODUCT_FLAG,
- EMIT_RANGE_DIAGNOSTIC_FLAG,
- EMIT_RANGE_NOTPRODUCT_FLAG,
- EMIT_RANGE_CHECK,
- IGNORE_CONSTRAINT));
+ EMIT_RANGE_PD_DEVELOPER_FLAG,
+ EMIT_RANGE_PRODUCT_FLAG,
+ EMIT_RANGE_PD_PRODUCT_FLAG,
+ EMIT_RANGE_DIAGNOSTIC_FLAG,
+ EMIT_RANGE_NOTPRODUCT_FLAG,
+ EMIT_RANGE_CHECK,
+ IGNORE_CONSTRAINT));
#endif // COMPILER1
#ifdef COMPILER2
emit_range_no(NULL C2_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
- EMIT_RANGE_PD_DEVELOPER_FLAG,
- EMIT_RANGE_PRODUCT_FLAG,
- EMIT_RANGE_PD_PRODUCT_FLAG,
- EMIT_RANGE_DIAGNOSTIC_FLAG,
- EMIT_RANGE_EXPERIMENTAL_FLAG,
- EMIT_RANGE_NOTPRODUCT_FLAG,
- EMIT_RANGE_CHECK,
- IGNORE_CONSTRAINT));
+ EMIT_RANGE_PD_DEVELOPER_FLAG,
+ EMIT_RANGE_PRODUCT_FLAG,
+ EMIT_RANGE_PD_PRODUCT_FLAG,
+ EMIT_RANGE_DIAGNOSTIC_FLAG,
+ EMIT_RANGE_EXPERIMENTAL_FLAG,
+ EMIT_RANGE_NOTPRODUCT_FLAG,
+ EMIT_RANGE_CHECK,
+ IGNORE_CONSTRAINT));
#endif // COMPILER2
#if INCLUDE_ALL_GCS
emit_range_no(NULL G1_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
- EMIT_RANGE_PD_DEVELOPER_FLAG,
- EMIT_RANGE_PRODUCT_FLAG,
- EMIT_RANGE_PD_PRODUCT_FLAG,
- EMIT_RANGE_DIAGNOSTIC_FLAG,
- EMIT_RANGE_EXPERIMENTAL_FLAG,
- EMIT_RANGE_NOTPRODUCT_FLAG,
- EMIT_RANGE_MANAGEABLE_FLAG,
- EMIT_RANGE_PRODUCT_RW_FLAG,
- EMIT_RANGE_CHECK,
- IGNORE_CONSTRAINT));
+ EMIT_RANGE_PD_DEVELOPER_FLAG,
+ EMIT_RANGE_PRODUCT_FLAG,
+ EMIT_RANGE_PD_PRODUCT_FLAG,
+ EMIT_RANGE_DIAGNOSTIC_FLAG,
+ EMIT_RANGE_EXPERIMENTAL_FLAG,
+ EMIT_RANGE_NOTPRODUCT_FLAG,
+ EMIT_RANGE_MANAGEABLE_FLAG,
+ EMIT_RANGE_PRODUCT_RW_FLAG,
+ EMIT_RANGE_CHECK,
+ IGNORE_CONSTRAINT));
#endif // INCLUDE_ALL_GCS
}
@@ -367,45 +369,23 @@
}
bool CommandLineFlagRangeList::check_ranges() {
-//#define PRINT_RANGES_SIZES
-#ifdef PRINT_RANGES_SIZES
- {
- size_t size_ranges = sizeof(CommandLineFlagRangeList);
- for (int i=0; i<length(); i++) {
- size_ranges += sizeof(CommandLineFlagRange);
- CommandLineFlagRange* range = at(i);
- const char* name = range->name();
- Flag* flag = Flag::find_flag(name, strlen(name), true, true);
- if (flag->is_intx()) {
- size_ranges += 2*sizeof(intx);
- size_ranges += sizeof(CommandLineFlagRange*);
- } else if (flag->is_uintx()) {
- size_ranges += 2*sizeof(uintx);
- size_ranges += sizeof(CommandLineFlagRange*);
- } else if (flag->is_uint64_t()) {
- size_ranges += 2*sizeof(uint64_t);
- size_ranges += sizeof(CommandLineFlagRange*);
- } else if (flag->is_size_t()) {
- size_ranges += 2*sizeof(size_t);
- size_ranges += sizeof(CommandLineFlagRange*);
- } else if (flag->is_double()) {
- size_ranges += 2*sizeof(double);
- size_ranges += sizeof(CommandLineFlagRange*);
- }
- }
- fprintf(stderr, "Size of %d ranges: " SIZE_FORMAT " bytes\n",
- length(), size_ranges);
- }
-#endif // PRINT_RANGES_SIZES
-
// Check ranges.
bool status = true;
for (int i=0; i<length(); i++) {
CommandLineFlagRange* range = at(i);
const char* name = range->name();
Flag* flag = Flag::find_flag(name, strlen(name), true, true);
+ // We must check for NULL here as lp64_product flags on 32 bit architecture
+ // can generate range check (despite that they are declared as constants),
+ // but they will not be returned by Flag::find_flag()
if (flag != NULL) {
- if (flag->is_intx()) {
+ if (flag->is_int()) {
+ int value = flag->get_int();
+ if (range->check_int(value, true) != Flag::SUCCESS) status = false;
+ } else if (flag->is_uint()) {
+ uint value = flag->get_uint();
+ if (range->check_uint(value, true) != Flag::SUCCESS) status = false;
+ } else if (flag->is_intx()) {
intx value = flag->get_intx();
if (range->check_intx(value, true) != Flag::SUCCESS) status = false;
} else if (flag->is_uintx()) {
--- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -38,6 +38,11 @@
* then we need to use constraint instead.
*/
+class CommandLineError : public AllStatic {
+public:
+ static void print(bool verbose, const char* msg, ...);
+};
+
class CommandLineFlagRange : public CHeapObj<mtInternal> {
private:
const char* _name;
--- a/hotspot/src/share/vm/runtime/globals.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/globals.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -310,13 +310,17 @@
void Flag::get_locked_message(char* buf, int buflen) const {
buf[0] = '\0';
if (is_diagnostic() && !is_unlocked()) {
- jio_snprintf(buf, buflen, "Error: VM option '%s' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.\n",
- _name);
+ jio_snprintf(buf, buflen,
+ "Error: VM option '%s' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.\n"
+ "Error: The unlock option must precede '%s'.\n",
+ _name, _name);
return;
}
if (is_experimental() && !is_unlocked()) {
- jio_snprintf(buf, buflen, "Error: VM option '%s' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.\n",
- _name);
+ jio_snprintf(buf, buflen,
+ "Error: VM option '%s' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.\n"
+ "Error: The unlock option must precede '%s'.\n",
+ _name, _name);
return;
}
if (is_develop() && is_product_build()) {
@@ -515,6 +519,20 @@
}
}
+const char* Flag::flag_error_str(Flag::Error error) {
+ switch (error) {
+ case Flag::MISSING_NAME: return "MISSING_NAME";
+ case Flag::MISSING_VALUE: return "MISSING_VALUE";
+ case Flag::NON_WRITABLE: return "NON_WRITABLE";
+ case Flag::OUT_OF_BOUNDS: return "OUT_OF_BOUNDS";
+ case Flag::VIOLATES_CONSTRAINT: return "VIOLATES_CONSTRAINT";
+ case Flag::INVALID_FLAG: return "INVALID_FLAG";
+ case Flag::ERR_OTHER: return "ERR_OTHER";
+ case Flag::SUCCESS: return "SUCCESS";
+ default: ShouldNotReachHere(); return "NULL";
+ }
+}
+
// 4991491 do not "optimize out" the was_set false values: omitting them
// tickles a Microsoft compiler bug causing flagTable to be malformed
@@ -758,17 +776,7 @@
e.commit();
}
-static Flag::Error get_status_error(Flag::Error status_range, Flag::Error status_constraint) {
- if (status_range != Flag::SUCCESS) {
- return status_range;
- } else if (status_constraint != Flag::SUCCESS) {
- return status_constraint;
- } else {
- return Flag::SUCCESS;
- }
-}
-
-static Flag::Error apply_constraint_and_check_range_bool(const char* name, bool* new_value, bool verbose = true) {
+static Flag::Error apply_constraint_and_check_range_bool(const char* name, bool new_value, bool verbose = true) {
Flag::Error status = Flag::SUCCESS;
CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
if (constraint != NULL) {
@@ -789,7 +797,7 @@
Flag* result = Flag::find_flag(name, len);
if (result == NULL) return Flag::INVALID_FLAG;
if (!result->is_bool()) return Flag::WRONG_FORMAT;
- Flag::Error check = apply_constraint_and_check_range_bool(name, value, !CommandLineFlagConstraintList::validated_after_ergo());
+ Flag::Error check = apply_constraint_and_check_range_bool(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
bool old_value = result->get_bool();
trace_flag_changed<EventBooleanFlagChanged, bool>(name, old_value, *value, origin);
@@ -802,7 +810,7 @@
Flag::Error CommandLineFlagsEx::boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_bool(), "wrong flag type");
- Flag::Error check = apply_constraint_and_check_range_bool(faddr->_name, &value);
+ Flag::Error check = apply_constraint_and_check_range_bool(faddr->_name, value);
if (check != Flag::SUCCESS) return check;
trace_flag_changed<EventBooleanFlagChanged, bool>(faddr->_name, faddr->get_bool(), value, origin);
faddr->set_bool(value);
@@ -810,18 +818,19 @@
return Flag::SUCCESS;
}
-static Flag::Error apply_constraint_and_check_range_int(const char* name, int* new_value, bool verbose = true) {
- Flag::Error range_status = Flag::SUCCESS;
+static Flag::Error apply_constraint_and_check_range_int(const char* name, int new_value, bool verbose = true) {
+ Flag::Error status = Flag::SUCCESS;
CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
if (range != NULL) {
- range_status = range->check_int(*new_value, verbose);
+ status = range->check_int(new_value, verbose);
}
- Flag::Error constraint_status = Flag::SUCCESS;
- CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
- if (constraint != NULL) {
- constraint_status = constraint->apply_int(new_value, verbose);
+ if (status == Flag::SUCCESS) {
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
+ if (constraint != NULL) {
+ status = constraint->apply_int(new_value, verbose);
+ }
}
- return get_status_error(range_status, constraint_status);
+ return status;
}
Flag::Error CommandLineFlags::intAt(const char* name, size_t len, int* value, bool allow_locked, bool return_flag) {
@@ -836,7 +845,7 @@
Flag* result = Flag::find_flag(name, len);
if (result == NULL) return Flag::INVALID_FLAG;
if (!result->is_int()) return Flag::WRONG_FORMAT;
- Flag::Error check = apply_constraint_and_check_range_int(name, value, !CommandLineFlagConstraintList::validated_after_ergo());
+ Flag::Error check = apply_constraint_and_check_range_int(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
int old_value = result->get_int();
trace_flag_changed<EventIntFlagChanged, s4>(name, old_value, *value, origin);
@@ -849,24 +858,27 @@
Flag::Error CommandLineFlagsEx::intAtPut(CommandLineFlagWithType flag, int value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_int(), "wrong flag type");
+ Flag::Error check = apply_constraint_and_check_range_int(faddr->_name, value, !CommandLineFlagConstraintList::validated_after_ergo());
+ if (check != Flag::SUCCESS) return check;
trace_flag_changed<EventIntFlagChanged, s4>(faddr->_name, faddr->get_int(), value, origin);
faddr->set_int(value);
faddr->set_origin(origin);
return Flag::SUCCESS;
}
-static Flag::Error apply_constraint_and_check_range_uint(const char* name, uint* new_value, bool verbose = true) {
- Flag::Error range_status = Flag::SUCCESS;
+static Flag::Error apply_constraint_and_check_range_uint(const char* name, uint new_value, bool verbose = true) {
+ Flag::Error status = Flag::SUCCESS;
CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
if (range != NULL) {
- range_status = range->check_uint(*new_value, verbose);
+ status = range->check_uint(new_value, verbose);
}
- Flag::Error constraint_status = Flag::SUCCESS;
- CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
- if (constraint != NULL) {
- constraint_status = constraint->apply_uint(new_value, verbose);
+ if (status == Flag::SUCCESS) {
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
+ if (constraint != NULL) {
+ status = constraint->apply_uint(new_value, verbose);
+ }
}
- return get_status_error(range_status, constraint_status);
+ return status;
}
Flag::Error CommandLineFlags::uintAt(const char* name, size_t len, uint* value, bool allow_locked, bool return_flag) {
@@ -881,7 +893,7 @@
Flag* result = Flag::find_flag(name, len);
if (result == NULL) return Flag::INVALID_FLAG;
if (!result->is_uint()) return Flag::WRONG_FORMAT;
- Flag::Error check = apply_constraint_and_check_range_uint(name, value, !CommandLineFlagConstraintList::validated_after_ergo());
+ Flag::Error check = apply_constraint_and_check_range_uint(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
uint old_value = result->get_uint();
trace_flag_changed<EventUnsignedIntFlagChanged, u4>(name, old_value, *value, origin);
@@ -894,6 +906,8 @@
Flag::Error CommandLineFlagsEx::uintAtPut(CommandLineFlagWithType flag, uint value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_uint(), "wrong flag type");
+ Flag::Error check = apply_constraint_and_check_range_uint(faddr->_name, value, !CommandLineFlagConstraintList::validated_after_ergo());
+ if (check != Flag::SUCCESS) return check;
trace_flag_changed<EventUnsignedIntFlagChanged, u4>(faddr->_name, faddr->get_uint(), value, origin);
faddr->set_uint(value);
faddr->set_origin(origin);
@@ -908,25 +922,26 @@
return Flag::SUCCESS;
}
-static Flag::Error apply_constraint_and_check_range_intx(const char* name, intx* new_value, bool verbose = true) {
- Flag::Error range_status = Flag::SUCCESS;
+static Flag::Error apply_constraint_and_check_range_intx(const char* name, intx new_value, bool verbose = true) {
+ Flag::Error status = Flag::SUCCESS;
CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
if (range != NULL) {
- range_status = range->check_intx(*new_value, verbose);
+ status = range->check_intx(new_value, verbose);
}
- Flag::Error constraint_status = Flag::SUCCESS;
- CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
- if (constraint != NULL) {
- constraint_status = constraint->apply_intx(new_value, verbose);
+ if (status == Flag::SUCCESS) {
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
+ if (constraint != NULL) {
+ status = constraint->apply_intx(new_value, verbose);
+ }
}
- return get_status_error(range_status, constraint_status);
+ return status;
}
Flag::Error CommandLineFlags::intxAtPut(const char* name, size_t len, intx* value, Flag::Flags origin) {
Flag* result = Flag::find_flag(name, len);
if (result == NULL) return Flag::INVALID_FLAG;
if (!result->is_intx()) return Flag::WRONG_FORMAT;
- Flag::Error check = apply_constraint_and_check_range_intx(name, value, !CommandLineFlagConstraintList::validated_after_ergo());
+ Flag::Error check = apply_constraint_and_check_range_intx(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
intx old_value = result->get_intx();
trace_flag_changed<EventLongFlagChanged, intx>(name, old_value, *value, origin);
@@ -939,7 +954,7 @@
Flag::Error CommandLineFlagsEx::intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_intx(), "wrong flag type");
- Flag::Error check = apply_constraint_and_check_range_intx(faddr->_name, &value);
+ Flag::Error check = apply_constraint_and_check_range_intx(faddr->_name, value);
if (check != Flag::SUCCESS) return check;
trace_flag_changed<EventLongFlagChanged, intx>(faddr->_name, faddr->get_intx(), value, origin);
faddr->set_intx(value);
@@ -955,25 +970,26 @@
return Flag::SUCCESS;
}
-static Flag::Error apply_constraint_and_check_range_uintx(const char* name, uintx* new_value, bool verbose = true) {
- Flag::Error range_status = Flag::SUCCESS;
+static Flag::Error apply_constraint_and_check_range_uintx(const char* name, uintx new_value, bool verbose = true) {
+ Flag::Error status = Flag::SUCCESS;
CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
if (range != NULL) {
- range_status = range->check_uintx(*new_value, verbose);
+ status = range->check_uintx(new_value, verbose);
}
- Flag::Error constraint_status = Flag::SUCCESS;
- CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
- if (constraint != NULL) {
- constraint_status = constraint->apply_uintx(new_value, verbose);
+ if (status == Flag::SUCCESS) {
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
+ if (constraint != NULL) {
+ status = constraint->apply_uintx(new_value, verbose);
+ }
}
- return get_status_error(range_status, constraint_status);
+ return status;
}
Flag::Error CommandLineFlags::uintxAtPut(const char* name, size_t len, uintx* value, Flag::Flags origin) {
Flag* result = Flag::find_flag(name, len);
if (result == NULL) return Flag::INVALID_FLAG;
if (!result->is_uintx()) return Flag::WRONG_FORMAT;
- Flag::Error check = apply_constraint_and_check_range_uintx(name, value, !CommandLineFlagConstraintList::validated_after_ergo());
+ Flag::Error check = apply_constraint_and_check_range_uintx(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
uintx old_value = result->get_uintx();
trace_flag_changed<EventUnsignedLongFlagChanged, u8>(name, old_value, *value, origin);
@@ -986,7 +1002,7 @@
Flag::Error CommandLineFlagsEx::uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_uintx(), "wrong flag type");
- Flag::Error check = apply_constraint_and_check_range_uintx(faddr->_name, &value);
+ Flag::Error check = apply_constraint_and_check_range_uintx(faddr->_name, value);
if (check != Flag::SUCCESS) return check;
trace_flag_changed<EventUnsignedLongFlagChanged, u8>(faddr->_name, faddr->get_uintx(), value, origin);
faddr->set_uintx(value);
@@ -1002,25 +1018,26 @@
return Flag::SUCCESS;
}
-static Flag::Error apply_constraint_and_check_range_uint64_t(const char* name, uint64_t* new_value, bool verbose = true) {
- Flag::Error range_status = Flag::SUCCESS;
+static Flag::Error apply_constraint_and_check_range_uint64_t(const char* name, uint64_t new_value, bool verbose = true) {
+ Flag::Error status = Flag::SUCCESS;
CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
if (range != NULL) {
- range_status = range->check_uint64_t(*new_value, verbose);
+ status = range->check_uint64_t(new_value, verbose);
}
- Flag::Error constraint_status = Flag::SUCCESS;
- CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
- if (constraint != NULL) {
- constraint_status = constraint->apply_uint64_t(new_value, verbose);
+ if (status == Flag::SUCCESS) {
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
+ if (constraint != NULL) {
+ status = constraint->apply_uint64_t(new_value, verbose);
+ }
}
- return get_status_error(range_status, constraint_status);
+ return status;
}
Flag::Error CommandLineFlags::uint64_tAtPut(const char* name, size_t len, uint64_t* value, Flag::Flags origin) {
Flag* result = Flag::find_flag(name, len);
if (result == NULL) return Flag::INVALID_FLAG;
if (!result->is_uint64_t()) return Flag::WRONG_FORMAT;
- Flag::Error check = apply_constraint_and_check_range_uint64_t(name, value, !CommandLineFlagConstraintList::validated_after_ergo());
+ Flag::Error check = apply_constraint_and_check_range_uint64_t(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
uint64_t old_value = result->get_uint64_t();
trace_flag_changed<EventUnsignedLongFlagChanged, u8>(name, old_value, *value, origin);
@@ -1033,7 +1050,7 @@
Flag::Error CommandLineFlagsEx::uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_uint64_t(), "wrong flag type");
- Flag::Error check = apply_constraint_and_check_range_uint64_t(faddr->_name, &value);
+ Flag::Error check = apply_constraint_and_check_range_uint64_t(faddr->_name, value);
if (check != Flag::SUCCESS) return check;
trace_flag_changed<EventUnsignedLongFlagChanged, u8>(faddr->_name, faddr->get_uint64_t(), value, origin);
faddr->set_uint64_t(value);
@@ -1049,25 +1066,26 @@
return Flag::SUCCESS;
}
-static Flag::Error apply_constraint_and_check_range_size_t(const char* name, size_t* new_value, bool verbose = true) {
- Flag::Error range_status = Flag::SUCCESS;
+static Flag::Error apply_constraint_and_check_range_size_t(const char* name, size_t new_value, bool verbose = true) {
+ Flag::Error status = Flag::SUCCESS;
CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
if (range != NULL) {
- range_status = range->check_size_t(*new_value, verbose);
+ status = range->check_size_t(new_value, verbose);
}
- Flag::Error constraint_status = Flag::SUCCESS;
- CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
- if (constraint != NULL) {
- constraint_status = constraint->apply_size_t(new_value, verbose);
+ if (status == Flag::SUCCESS) {
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
+ if (constraint != NULL) {
+ status = constraint->apply_size_t(new_value, verbose);
+ }
}
- return get_status_error(range_status, constraint_status);
+ return status;
}
Flag::Error CommandLineFlags::size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin) {
Flag* result = Flag::find_flag(name, len);
if (result == NULL) return Flag::INVALID_FLAG;
if (!result->is_size_t()) return Flag::WRONG_FORMAT;
- Flag::Error check = apply_constraint_and_check_range_size_t(name, value, !CommandLineFlagConstraintList::validated_after_ergo());
+ Flag::Error check = apply_constraint_and_check_range_size_t(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
size_t old_value = result->get_size_t();
trace_flag_changed<EventUnsignedLongFlagChanged, u8>(name, old_value, *value, origin);
@@ -1080,7 +1098,7 @@
Flag::Error CommandLineFlagsEx::size_tAtPut(CommandLineFlagWithType flag, size_t value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_size_t(), "wrong flag type");
- Flag::Error check = apply_constraint_and_check_range_size_t(faddr->_name, &value);
+ Flag::Error check = apply_constraint_and_check_range_size_t(faddr->_name, value);
if (check != Flag::SUCCESS) return check;
trace_flag_changed<EventUnsignedLongFlagChanged, u8>(faddr->_name, faddr->get_size_t(), value, origin);
faddr->set_size_t(value);
@@ -1096,25 +1114,26 @@
return Flag::SUCCESS;
}
-static Flag::Error apply_constraint_and_check_range_double(const char* name, double* new_value, bool verbose = true) {
- Flag::Error range_status = Flag::SUCCESS;
+static Flag::Error apply_constraint_and_check_range_double(const char* name, double new_value, bool verbose = true) {
+ Flag::Error status = Flag::SUCCESS;
CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
if (range != NULL) {
- range_status = range->check_double(*new_value, verbose);
+ status = range->check_double(new_value, verbose);
}
- Flag::Error constraint_status = Flag::SUCCESS;
- CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
- if (constraint != NULL) {
- constraint_status = constraint->apply_double(new_value, verbose);
+ if (status == Flag::SUCCESS) {
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find_if_needs_check(name);
+ if (constraint != NULL) {
+ status = constraint->apply_double(new_value, verbose);
+ }
}
- return get_status_error(range_status, constraint_status);
+ return status;
}
Flag::Error CommandLineFlags::doubleAtPut(const char* name, size_t len, double* value, Flag::Flags origin) {
Flag* result = Flag::find_flag(name, len);
if (result == NULL) return Flag::INVALID_FLAG;
if (!result->is_double()) return Flag::WRONG_FORMAT;
- Flag::Error check = apply_constraint_and_check_range_double(name, value, !CommandLineFlagConstraintList::validated_after_ergo());
+ Flag::Error check = apply_constraint_and_check_range_double(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
double old_value = result->get_double();
trace_flag_changed<EventDoubleFlagChanged, double>(name, old_value, *value, origin);
@@ -1127,7 +1146,7 @@
Flag::Error CommandLineFlagsEx::doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_double(), "wrong flag type");
- Flag::Error check = apply_constraint_and_check_range_double(faddr->_name, &value);
+ Flag::Error check = apply_constraint_and_check_range_double(faddr->_name, value);
if (check != Flag::SUCCESS) return check;
trace_flag_changed<EventDoubleFlagChanged, double>(faddr->_name, faddr->get_double(), value, origin);
faddr->set_double(value);
--- a/hotspot/src/share/vm/runtime/globals.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/globals.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -372,19 +372,7 @@
void print_kind(outputStream* st);
void print_as_flag(outputStream* st);
- static const char* flag_error_str(Flag::Error error) {
- switch (error) {
- case Flag::MISSING_NAME: return "MISSING_NAME";
- case Flag::MISSING_VALUE: return "MISSING_VALUE";
- case Flag::NON_WRITABLE: return "NON_WRITABLE";
- case Flag::OUT_OF_BOUNDS: return "OUT_OF_BOUNDS";
- case Flag::VIOLATES_CONSTRAINT: return "VIOLATES_CONSTRAINT";
- case Flag::INVALID_FLAG: return "INVALID_FLAG";
- case Flag::ERR_OTHER: return "ERR_OTHER";
- case Flag::SUCCESS: return "SUCCESS";
- default: return "NULL";
- }
- }
+ static const char* flag_error_str(Flag::Error error);
};
// debug flags control various aspects of the VM and are global accessible
@@ -1564,6 +1552,10 @@
product(uint, ParallelGCThreads, 0, \
"Number of parallel threads parallel gc will use") \
\
+ diagnostic(bool, UseSemaphoreGCThreadsSynchronization, true, \
+ "Use semaphore synchronization for the GC Threads, " \
+ "instead of synchronization based on mutexes") \
+ \
product(bool, UseDynamicNumberOfGCThreads, false, \
"Dynamically choose the number of parallel threads " \
"parallel gc will use") \
@@ -1575,7 +1567,7 @@
product(size_t, HeapSizePerGCThread, ScaleForWordSize(64*M), \
"Size of heap (bytes) per GC thread used in calculating the " \
"number of GC threads") \
- range((uintx)os::vm_page_size(), max_uintx) \
+ range((size_t)os::vm_page_size(), (size_t)max_uintx) \
\
product(bool, TraceDynamicGCThreads, false, \
"Trace the dynamic GC thread usage") \
@@ -1856,6 +1848,7 @@
product(size_t, MarkStackSize, NOT_LP64(32*K) LP64_ONLY(4*M), \
"Size of marking stack") \
\
+ /* where does the range max value of (max_jint - 1) come from? */ \
product(size_t, MarkStackSizeMax, NOT_LP64(4*M) LP64_ONLY(512*M), \
"Maximum size of marking stack") \
range(1, (max_jint - 1)) \
@@ -2920,12 +2913,6 @@
notproduct(bool, ICMissHistogram, false, \
"Produce histogram of IC misses") \
\
- notproduct(bool, PrintClassStatistics, false, \
- "Print class statistics at end of run") \
- \
- notproduct(bool, PrintMethodStatistics, false, \
- "Print method statistics at end of run") \
- \
/* interpreter */ \
develop(bool, ClearInterpreterLocals, false, \
"Always clear local variables of interpreter activations upon " \
--- a/hotspot/src/share/vm/runtime/java.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/java.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -304,13 +304,6 @@
CodeCache::print_internals();
}
- if (PrintClassStatistics) {
- SystemDictionary::print_class_statistics();
- }
- if (PrintMethodStatistics) {
- SystemDictionary::print_method_statistics();
- }
-
if (PrintVtableStats) {
klassVtable::print_statistics();
klassItable::print_statistics();
--- a/hotspot/src/share/vm/runtime/stubRoutines.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -181,7 +181,7 @@
StubGenerator_generate(&buffer, false);
// When new stubs added we need to make sure there is some space left
// to catch situation when we should increase size again.
- assert(buffer.insts_remaining() > 200, "increase code_size1");
+ assert(code_size1 == 0 || buffer.insts_remaining() > 200, "increase code_size1");
}
}
@@ -274,7 +274,7 @@
StubGenerator_generate(&buffer, true);
// When new stubs added we need to make sure there is some space left
// to catch situation when we should increase size again.
- assert(buffer.insts_remaining() > 200, "increase code_size2");
+ assert(code_size2 == 0 || buffer.insts_remaining() > 200, "increase code_size2");
}
#ifdef ASSERT
--- a/hotspot/src/share/vm/runtime/sweeper.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/sweeper.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -618,19 +618,14 @@
MutexLocker cl(CompiledIC_lock);
nm->clear_ic_stubs();
}
- // Acquiring the CompiledIC_lock may block for a safepoint and set the
- // nmethod to zombie (see 'CodeCache::make_marked_nmethods_zombies').
- // Check if nmethod is still non-entrant at this point.
- if (nm->is_not_entrant()) {
- if (PrintMethodFlushing && Verbose) {
- tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm);
- }
- // Code cache state change is tracked in make_zombie()
- nm->make_zombie();
- SWEEP(nm);
- assert(result == None, "sanity");
- result = MadeZombie;
+ if (PrintMethodFlushing && Verbose) {
+ tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm);
}
+ // Code cache state change is tracked in make_zombie()
+ nm->make_zombie();
+ SWEEP(nm);
+ assert(result == None, "sanity");
+ result = MadeZombie;
assert(nm->is_zombie(), "nmethod must be zombie");
} else {
// Still alive, clean up its inline caches
--- a/hotspot/src/share/vm/runtime/thread.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/thread.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -3331,7 +3331,6 @@
// Final check of all 'AfterErgo' constraints after ergonomics which may change values.
bool constraint_result = CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::AfterErgo);
- Arguments::post_after_ergo_constraint_check(constraint_result);
if (!constraint_result) {
return JNI_EINVAL;
}
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -405,7 +405,7 @@
nonstatic_field(ObjArrayKlass, _element_klass, Klass*) \
nonstatic_field(ObjArrayKlass, _bottom_klass, Klass*) \
volatile_nonstatic_field(Symbol, _refcount, short) \
- nonstatic_field(Symbol, _identity_hash, int) \
+ nonstatic_field(Symbol, _identity_hash, short) \
nonstatic_field(Symbol, _length, unsigned short) \
unchecked_nonstatic_field(Symbol, _body, sizeof(jbyte)) /* NOTE: no type */ \
nonstatic_field(TypeArrayKlass, _max_length, int) \
@@ -1565,6 +1565,7 @@
declare_toplevel_type(Generation*) \
declare_toplevel_type(GenerationSpec**) \
declare_toplevel_type(HeapWord*) \
+ declare_toplevel_type(HeapWord* volatile) \
declare_toplevel_type(MemRegion*) \
declare_toplevel_type(OffsetTableContigSpace*) \
declare_toplevel_type(Space*) \
--- a/hotspot/src/share/vm/runtime/vm_operations.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/runtime/vm_operations.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -109,8 +109,8 @@
// Deoptimize all activations depending on marked nmethods
Deoptimization::deoptimize_dependents();
- // Make the dependent methods zombies
- CodeCache::make_marked_nmethods_zombies();
+ // Make the dependent methods not entrant
+ CodeCache::make_marked_nmethods_not_entrant();
}
void VM_MarkActiveNMethods::doit() {
--- a/hotspot/src/share/vm/trace/trace.xml Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/trace/trace.xml Tue Sep 08 14:40:44 2015 -0700
@@ -346,6 +346,29 @@
<value type="BYTES64" field="totalSize" label="Total Size" />
</event>
+ <struct id="G1EvacStats">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="BYTES64" field="allocated" label="Allocated" description="Total memory allocated by PLABs"/>
+ <value type="BYTES64" field="wasted" label="Wasted" description="Total memory wasted within PLABs due to alignment or refill"/>
+ <value type="BYTES64" field="used" label="Used" description="Total memory occupied by objects within PLABs"/>
+ <value type="BYTES64" field="undoWaste" label="Undo Wasted" description="Total memory wasted due to allocation undo within PLABs"/>
+ <value type="BYTES64" field="regionEndWaste" label="Region End Wasted" description="Total memory wasted at the end of regions due to refill"/>
+ <value type="UINT" field="regionsRefilled" label="Region Refills" description="Total memory wasted at the end of regions due to refill"/>
+ <value type="BYTES64" field="directAllocated" label="Allocated (direct)" description="Total memory allocated using direct allocation outside of PLABs"/>
+ <value type="BYTES64" field="failureUsed" label="Used (failure)" description="Total memory occupied by objects in regions where evacuation failed"/>
+ <value type="BYTES64" field="failureWaste" label="Wasted (failure)" description="Total memory left unused in regions where evacuation failed"/>
+ </struct>
+
+ <event id="GCG1EvacuationYoungStatistics" path="vm/gc/detailed/g1_evac_young_stats" label="G1 Evacuation Statistics for Young" is_instant="true"
+ description="Memory related evacuation statistics during GC for the young generation">
+ <structvalue type="G1EvacStats" field="stats" label="Evacuation statistics"/>
+ </event>
+
+ <event id="GCG1EvacuationOldStatistics" path="vm/gc/detailed/g1_evac_old_stats" label="G1 Evacuation Memory Statistics for Old" is_instant="true"
+ description="Memory related evacuation statistics during GC for the old generation">
+ <structvalue type="G1EvacStats" field="stats" label="Evacuation statistics"/>
+ </event>
+
<!-- Promotion events, Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. -->
<event id="PromoteObjectInNewPLAB" path="vm/gc/detailed/object_promotion_in_new_PLAB" label="Promotion in new PLAB"
description="Object survived scavenge and was copied to a new Promotion Local Allocation Buffer (PLAB). Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. Due to promotion being done in parallel an object might be reported multiple times as the GC threads race to copy all objects."
--- a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -161,7 +161,7 @@
//----------------------------------------------------------------------------------------------------
-// Constant for jlong (specifying an long long canstant is C++ compiler specific)
+// Constant for jlong (specifying a long long constant is C++ compiler specific)
// Build a 64bit integer constant
#define CONST64(x) (x ## LL)
--- a/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -178,7 +178,7 @@
//----------------------------------------------------------------------------------------------------
-// Constant for jlong (specifying an long long constant is C++ compiler specific)
+// Constant for jlong (specifying a long long constant is C++ compiler specific)
// Build a 64bit integer constant
#define CONST64(x) (x ## LL)
--- a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -148,9 +148,9 @@
inline int g_isfinite(jdouble f) { return _finite(f); }
//----------------------------------------------------------------------------------------------------
-// Constant for jlong (specifying an long long constant is C++ compiler specific)
+// Constant for jlong (specifying a long long constant is C++ compiler specific)
-// Build a 64bit integer constant on with Visual C++
+// Build a 64bit integer constant with Visual C++
#define CONST64(x) (x ## i64)
#define UCONST64(x) (x ## ui64)
--- a/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp Tue Sep 08 14:40:44 2015 -0700
@@ -108,7 +108,7 @@
//----------------------------------------------------------------------------------------------------
-// Constant for jlong (specifying an long long canstant is C++ compiler specific)
+// Constant for jlong (specifying a long long constant is C++ compiler specific)
// Build a 64bit integer constant
#define CONST64(x) (x ## LL)
--- a/hotspot/test/compiler/arguments/CheckCICompilerCount.java Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/test/compiler/arguments/CheckCICompilerCount.java Tue Sep 08 14:40:44 2015 -0700
@@ -68,7 +68,7 @@
private static final String[][] NON_TIERED_EXPECTED_OUTPUTS = {
{
- "CICompilerCount=0 must be at least 1",
+ "CICompilerCount (0) must be at least 1",
"Improperly specified VM option 'CICompilerCount=0'"
},
{
@@ -123,7 +123,7 @@
private static final String[][] TIERED_EXPECTED_OUTPUTS = {
{
- "CICompilerCount=1 must be at least 2",
+ "CICompilerCount (1) must be at least 2",
"Improperly specified VM option 'CICompilerCount=1'"
},
{
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/arraycopy/TestEliminatedArrayCopyDeopt.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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 8130847
+ * @summary Eliminated instance/array written to by an array copy variant must be correctly initialized when reallocated at a deopt
+ * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestEliminatedArrayCopyDeopt
+ *
+ */
+
+// Test that if an ArrayCopy node is eliminated because it doesn't
+// escape, then the correct field/array element values are captured so
+// on a deoptimization, when the object/array is reallocated, it is
+// correctly initialized
+
+public class TestEliminatedArrayCopyDeopt {
+
+ static class A implements Cloneable {
+ int f0;
+ int f1;
+ int f2;
+ int f3;
+ int f4;
+ int f5;
+ int f6;
+ int f7;
+ int f8;
+ int f9;
+ int f10;
+ int f11;
+ int f12;
+ int f13;
+ int f14;
+ int f15;
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+ }
+
+ // Clone
+ static boolean m1(A a, boolean flag) throws CloneNotSupportedException {
+ A c = (A)a.clone();
+ if (flag) {
+ // never taken branch that causes the deoptimization
+ if (c.f0 != 0x42) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Array clone
+ static int[] m2_src = null;
+ static boolean m2(boolean flag) throws CloneNotSupportedException {
+ int[] src = new int[10];
+ m2_src = src;
+ for (int i = 0; i < src.length; i++) {
+ src[i] = 0x42+i;
+ }
+ int[] c = (int[])src.clone();
+ if (flag) {
+ for (int i = 0; i < c.length; i++) {
+ if (c[i] != src[i]) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ // Array copy
+ static boolean m3(int[] src, boolean flag) {
+ int[] dst = new int[10];
+ System.arraycopy(src, 0, dst, 0, 10);
+ if (flag) {
+ for (int i = 0; i < dst.length; i++) {
+ if (dst[i] != src[i]) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ // Array copy of subrange
+ static boolean m4(int[] src, boolean flag) {
+ int[] dst = new int[10];
+ dst[0] = 0x42;
+ dst[1] = 0x42 - 1;
+ dst[2] = 0x42 - 2;
+ dst[8] = 0x42 - 8;
+ dst[9] = 0x42 - 9;
+ int src_off = 2;
+ int dst_off = 3;
+ int len = 5;
+ System.arraycopy(src, src_off, dst, dst_off, len);
+ if (flag) {
+ for (int i = 0; i < dst.length; i++) {
+ if (i >= dst_off && i < dst_off + len) {
+ if (dst[i] != src[i - dst_off + src_off]) {
+ return false;
+ }
+ } else {
+ if (dst[i] != 0x42-i) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ // Array copy with Phi
+ static boolean m5(int[] src, boolean flag1, boolean flag2) {
+ int[] dst = new int[10];
+ if (flag1) {
+ System.arraycopy(src, 0, dst, 0, 10);
+ }
+ if (flag2) {
+ for (int i = 0; i < dst.length; i++) {
+ if (dst[i] != src[i]) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ static public void main(String[] args) throws Exception {
+ boolean success = true;
+ A a = new A();
+ a.f0 = 0x42;
+ for (int i = 0; i < 20000; i++) {
+ m1(a, false);
+ }
+ if (!m1(a, true)) {
+ System.out.println("m1 failed");
+ success = false;
+ }
+
+ for (int i = 0; i < 20000; i++) {
+ m2(false);
+ }
+ if (!m2(true)) {
+ System.out.println("m2 failed");
+ success = false;
+ }
+
+ int[] src = new int[10];
+ for (int i = 0; i < src.length; i++) {
+ src[i] = 0x42+i;
+ }
+
+ for (int i = 0; i < 20000; i++) {
+ m3(src, false);
+ }
+ if (!m3(src, true)) {
+ System.out.println("m3 failed");
+ success = false;
+ }
+
+ for (int i = 0; i < 20000; i++) {
+ m4(src, false);
+ }
+ if (!m4(src, true)) {
+ System.out.println("m4 failed");
+ success = false;
+ }
+
+ for (int i = 0; i < 20000; i++) {
+ m5(src, i%2 == 0, false);
+ }
+ if (!m5(src, true, true)) {
+ System.out.println("m4 failed");
+ success = false;
+ }
+
+ if (!success) {
+ throw new RuntimeException("Test failed");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/arraycopy/TestEliminatedArrayCopyPhi.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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 8134321
+ * @summary Code that capture field values of eliminated allocation at a safepoint when there's an arraycopy behind a Phi is broken
+ * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestEliminatedArrayCopyPhi
+ *
+ */
+
+public class TestEliminatedArrayCopyPhi {
+
+ static int[] escaped;
+
+ static void test(int[] src, boolean flag1, boolean flag2) {
+ int[] array = new int[10];
+ if (flag1) {
+ System.arraycopy(src, 0, array, 0, src.length);
+ } else {
+ }
+
+ if (flag2) {
+ // never taken
+ escaped = array;
+ }
+ }
+
+ public static void main(String[] args) {
+ int[] src = new int[10];
+ for (int i = 0; i < 20000; i++) {
+ test(src, (i % 2) == 0, false);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/floatingpoint/NaNTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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 8076373
+ * @summary Verify if signaling NaNs are preserved.
+ * @run main NaNTest
+ */
+public class NaNTest {
+ static void testFloat() {
+ int originalValue = 0x7f800001;
+ int readBackValue = Float.floatToRawIntBits(Float.intBitsToFloat(originalValue));
+ if (originalValue != readBackValue) {
+ String errorMessage = String.format("Original and read back float values mismatch\n0x%X 0x%X\n",
+ originalValue,
+ readBackValue);
+ throw new RuntimeException(errorMessage);
+ } else {
+ System.out.printf("Written and read back float values match\n0x%X 0x%X\n",
+ originalValue,
+ readBackValue);
+ }
+ }
+
+ static void testDouble() {
+ long originalValue = 0xFFF0000000000001L;
+ long readBackValue = Double.doubleToRawLongBits(Double.longBitsToDouble(originalValue));
+ if (originalValue != readBackValue) {
+ String errorMessage = String.format("Original and read back double values mismatch\n0x%X 0x%X\n",
+ originalValue,
+ readBackValue);
+ throw new RuntimeException(errorMessage);
+ } else {
+ System.out.printf("Written and read back double values match\n0x%X 0x%X\n",
+ originalValue,
+ readBackValue);
+ }
+
+ }
+
+ public static void main(String args[]) {
+ System.out.println("### NanTest started");
+
+ testFloat();
+ testDouble();
+
+ System.out.println("### NanTest ended");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoops.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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 8080289
+ * @summary Sink stores out of loops if possible
+ * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+PrintCompilation -XX:CompileCommand=dontinline,TestMoveStoresOutOfLoops::test* TestMoveStoresOutOfLoops
+ *
+ */
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.function.*;
+
+public class TestMoveStoresOutOfLoops {
+
+ private static long[] array = new long[10];
+ private static long[] array2 = new long[10];
+ private static boolean[] array3 = new boolean[1000];
+ private static byte[] byte_array = new byte[10];
+
+ // Array store should be moved out of the loop, value stored
+ // should be 999, the loop should be eliminated
+ static void test_after_1(int idx) {
+ for (int i = 0; i < 1000; i++) {
+ array[idx] = i;
+ }
+ }
+
+ // Array store can't be moved out of loop because of following
+ // non loop invariant array access
+ static void test_after_2(int idx) {
+ for (int i = 0; i < 1000; i++) {
+ array[idx] = i;
+ array2[i%10] = i;
+ }
+ }
+
+ // Array store can't be moved out of loop because of following
+ // use
+ static void test_after_3(int idx) {
+ for (int i = 0; i < 1000; i++) {
+ array[idx] = i;
+ if (array[0] == -1) {
+ break;
+ }
+ }
+ }
+
+ // Array store can't be moved out of loop because of preceding
+ // use
+ static void test_after_4(int idx) {
+ for (int i = 0; i < 1000; i++) {
+ if (array[0] == -2) {
+ break;
+ }
+ array[idx] = i;
+ }
+ }
+
+ // All array stores should be moved out of the loop, one after
+ // the other
+ static void test_after_5(int idx) {
+ for (int i = 0; i < 1000; i++) {
+ array[idx] = i;
+ array[idx+1] = i;
+ array[idx+2] = i;
+ array[idx+3] = i;
+ array[idx+4] = i;
+ array[idx+5] = i;
+ }
+ }
+
+ // Array store can be moved after the loop but needs to be
+ // cloned on both exit paths
+ static void test_after_6(int idx) {
+ for (int i = 0; i < 1000; i++) {
+ array[idx] = i;
+ if (array3[i]) {
+ return;
+ }
+ }
+ }
+
+ // Optimize out redundant stores
+ static void test_stores_1(int ignored) {
+ array[0] = 0;
+ array[1] = 1;
+ array[2] = 2;
+ array[0] = 0;
+ array[1] = 1;
+ array[2] = 2;
+ }
+
+ static void test_stores_2(int idx) {
+ array[idx+0] = 0;
+ array[idx+1] = 1;
+ array[idx+2] = 2;
+ array[idx+0] = 0;
+ array[idx+1] = 1;
+ array[idx+2] = 2;
+ }
+
+ static void test_stores_3(int idx) {
+ byte_array[idx+0] = 0;
+ byte_array[idx+1] = 1;
+ byte_array[idx+2] = 2;
+ byte_array[idx+0] = 0;
+ byte_array[idx+1] = 1;
+ byte_array[idx+2] = 2;
+ }
+
+ // Array store can be moved out of the loop before the loop header
+ static void test_before_1(int idx) {
+ for (int i = 0; i < 1000; i++) {
+ array[idx] = 999;
+ }
+ }
+
+ // Array store can't be moved out of the loop before the loop
+ // header because there's more than one store on this slice
+ static void test_before_2(int idx) {
+ for (int i = 0; i < 1000; i++) {
+ array[idx] = 999;
+ array[i%2] = 0;
+ }
+ }
+
+ // Array store can't be moved out of the loop before the loop
+ // header because of use before store
+ static int test_before_3(int idx) {
+ int res = 0;
+ for (int i = 0; i < 1000; i++) {
+ res += array[i%10];
+ array[idx] = 999;
+ }
+ return res;
+ }
+
+ // Array store can't be moved out of the loop before the loop
+ // header because of possible early exit
+ static void test_before_4(int idx) {
+ for (int i = 0; i < 1000; i++) {
+ if (idx / (i+1) > 0) {
+ return;
+ }
+ array[idx] = 999;
+ }
+ }
+
+ // Array store can't be moved out of the loop before the loop
+ // header because it doesn't postdominate the loop head
+ static void test_before_5(int idx) {
+ for (int i = 0; i < 1000; i++) {
+ if (i % 2 == 0) {
+ array[idx] = 999;
+ }
+ }
+ }
+
+ // Array store can be moved out of the loop before the loop header
+ static int test_before_6(int idx) {
+ int res = 0;
+ for (int i = 0; i < 1000; i++) {
+ if (i%2 == 1) {
+ res *= 2;
+ } else {
+ res++;
+ }
+ array[idx] = 999;
+ }
+ return res;
+ }
+
+ final HashMap<String,Method> tests = new HashMap<>();
+ {
+ for (Method m : this.getClass().getDeclaredMethods()) {
+ if (m.getName().matches("test_(before|after|stores)_[0-9]+")) {
+ assert(Modifier.isStatic(m.getModifiers())) : m;
+ tests.put(m.getName(), m);
+ }
+ }
+ }
+
+ boolean success = true;
+ void doTest(String name, Runnable init, Function<String, Boolean> check) throws Exception {
+ Method m = tests.get(name);
+ for (int i = 0; i < 20000; i++) {
+ init.run();
+ m.invoke(null, 0);
+ success = success && check.apply(name);
+ if (!success) {
+ break;
+ }
+ }
+ }
+
+ static void array_init() {
+ array[0] = -1;
+ }
+
+ static boolean array_check(String name) {
+ boolean success = true;
+ if (array[0] != 999) {
+ success = false;
+ System.out.println(name + " failed: array[0] = " + array[0]);
+ }
+ return success;
+ }
+
+ static void array_init2() {
+ for (int i = 0; i < 6; i++) {
+ array[i] = -1;
+ }
+ }
+
+ static boolean array_check2(String name) {
+ boolean success = true;
+ for (int i = 0; i < 6; i++) {
+ if (array[i] != 999) {
+ success = false;
+ System.out.println(name + " failed: array[" + i + "] = " + array[i]);
+ }
+ }
+ return success;
+ }
+
+ static void array_init3() {
+ for (int i = 0; i < 3; i++) {
+ array[i] = -1;
+ }
+ }
+
+ static boolean array_check3(String name) {
+ boolean success = true;
+ for (int i = 0; i < 3; i++) {
+ if (array[i] != i) {
+ success = false;
+ System.out.println(name + " failed: array[" + i + "] = " + array[i]);
+ }
+ }
+ return success;
+ }
+
+ static void array_init4() {
+ for (int i = 0; i < 3; i++) {
+ byte_array[i] = -1;
+ }
+ }
+
+ static boolean array_check4(String name) {
+ boolean success = true;
+ for (int i = 0; i < 3; i++) {
+ if (byte_array[i] != i) {
+ success = false;
+ System.out.println(name + " failed: byte_array[" + i + "] = " + byte_array[i]);
+ }
+ }
+ return success;
+ }
+
+ static public void main(String[] args) throws Exception {
+ TestMoveStoresOutOfLoops test = new TestMoveStoresOutOfLoops();
+ test.doTest("test_after_1", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
+ test.doTest("test_after_2", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
+ test.doTest("test_after_3", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
+ test.doTest("test_after_4", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
+ test.doTest("test_after_5", TestMoveStoresOutOfLoops::array_init2, TestMoveStoresOutOfLoops::array_check2);
+ test.doTest("test_after_6", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
+ array3[999] = true;
+ test.doTest("test_after_6", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
+
+ test.doTest("test_stores_1", TestMoveStoresOutOfLoops::array_init3, TestMoveStoresOutOfLoops::array_check3);
+ test.doTest("test_stores_2", TestMoveStoresOutOfLoops::array_init3, TestMoveStoresOutOfLoops::array_check3);
+ test.doTest("test_stores_3", TestMoveStoresOutOfLoops::array_init4, TestMoveStoresOutOfLoops::array_check4);
+
+ test.doTest("test_before_1", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
+ test.doTest("test_before_2", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
+ test.doTest("test_before_3", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
+ test.doTest("test_before_4", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
+ test.doTest("test_before_5", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
+ test.doTest("test_before_6", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check);
+
+ if (!test.success) {
+ throw new RuntimeException("Some tests failed");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/regalloc/TestVectorRegAlloc.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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 8131969
+ * @summary assert in register allocation code when vector Phi for a loop is processed because code assumes all inputs already processed
+ * @run main/othervm -Xbatch TestVectorRegAlloc
+ *
+ */
+
+public class TestVectorRegAlloc {
+
+ static int test_helper_i;
+ static boolean test_helper() {
+ test_helper_i++;
+ return (test_helper_i & 7) != 0;
+ }
+
+ static void test(double[] src, double[] dst, boolean flag) {
+ double j = 0.0;
+ while(test_helper()) {
+ for (int i = 0; i < src.length; i++) {
+ dst[i] = src[i] + j;
+ }
+ // Loop will be unswitched and ReplicateD of zero will be
+ // split through the Phi of outer loop
+ for (int i = 0; i < src.length; i++) {
+ double k;
+ if (flag) {
+ k = j;
+ } else {
+ k = 0;
+ }
+ dst[i] = src[i] + k;
+ }
+ j++;
+ }
+ }
+
+ static public void main(String[] args) {
+ double[] src = new double[10];
+ double[] dst = new double[10];
+ for (int i = 0; i < 20000; i++) {
+ test(src, dst, (i % 2) == 0);
+ }
+ }
+}
--- a/hotspot/test/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java Tue Sep 08 16:01:29 2015 +0400
+++ b/hotspot/test/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java Tue Sep 08 14:40:44 2015 -0700
@@ -28,7 +28,6 @@
* when their age exceeded tenuring threshold are not aligned to
* SurvivorAlignmentInBytes value.
* @library /testlibrary /../../test/lib
- * @ignore 8130308
* @modules java.base/sun.misc
* java.management
* @build TestPromotionFromSurvivorToTenuredAfterMinorGC
@@ -99,11 +98,18 @@
.getActualMemoryUsage();
test.allocate();
- for (int i = 0; i <= SurvivorAlignmentTestMain.MAX_TENURING_THRESHOLD;
- i++) {
+ for (int i = 0; i <= SurvivorAlignmentTestMain.MAX_TENURING_THRESHOLD; i++) {
SurvivorAlignmentTestMain.WHITE_BOX.youngGC();
}
+ // Sometimes we see that data unrelated to the test has been allocated during
+ // the loop. This data is included in the expectedMemoryUsage since we look
+ // through all threads to see what they allocated. If this data is still in
+ // the survivor area however, it should not be included in expectedMemoryUsage
+ // since the verification below only look at what's in tenured space.
+ expectedMemoryUsage -= SurvivorAlignmentTestMain.getAlignmentHelper(
+ SurvivorAlignmentTestMain.HeapSpace.SURVIVOR)
+ .getActualMemoryUsage();
test.verifyMemoryUsage(expectedMemoryUsage);
}
}
--- a/jaxp/.hgtags Tue Sep 08 16:01:29 2015 +0400
+++ b/jaxp/.hgtags Tue Sep 08 14:40:44 2015 -0700
@@ -322,3 +322,4 @@
be357705874c4ba1a69c38fb211e5e31e35bf9cb jdk9-b77
5b1899c9822db4a80a29cac82af492afea9f8f41 jdk9-b78
cf809edc840ff7546677d38b13ebd8b3cae2bbda jdk9-b79
+f464f9b2fb1178f6a957e5730b4b5252c6149ed9 jdk9-b80
--- a/jaxws/.hgtags Tue Sep 08 16:01:29 2015 +0400
+++ b/jaxws/.hgtags Tue Sep 08 14:40:44 2015 -0700
@@ -325,3 +325,4 @@
bd6ece68cf8aca34c8d992569892060c82cfd3f1 jdk9-b77
ac1748bab0743137574be3451307b6a6361719eb jdk9-b78
42ae657e0e104fa7877996b8095f2e3ab1596118 jdk9-b79
+e9940bf1c8ddaa6f1f5f1813846b080f0ccaf50b jdk9-b80
--- a/jdk/.hgtags Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/.hgtags Tue Sep 08 14:40:44 2015 -0700
@@ -322,3 +322,4 @@
7fd081100f48828431e7c1bff65c906ee759069b jdk9-b77
0940ce86c614458f5bdd72278b190abbf36b7b45 jdk9-b78
d99c2ffdd0f15753e69126583688f2f075a0a5e8 jdk9-b79
+4947810137ae53abba3028cc366af953d90fa81a jdk9-b80
--- a/jdk/README Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/README Tue Sep 08 14:40:44 2015 -0700
@@ -25,5 +25,3 @@
5. Construct the images:
cd make && gnumake images
The resulting JDK image should be found in build/*/j2sdk-image
-
-
--- a/jdk/make/mapfiles/libj2ucrypto/mapfile-vers Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/make/mapfiles/libj2ucrypto/mapfile-vers Tue Sep 08 14:40:44 2015 -0700
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
# 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,6 +39,7 @@
Java_com_oracle_security_ucrypto_NativeCipher_nativeUpdate;
Java_com_oracle_security_ucrypto_NativeCipher_nativeFinal;
Java_com_oracle_security_ucrypto_NativeKey_nativeFree;
+ Java_com_oracle_security_ucrypto_NativeKey_00024RSAPrivate_nativeInit;
Java_com_oracle_security_ucrypto_NativeKey_00024RSAPrivateCrt_nativeInit;
Java_com_oracle_security_ucrypto_NativeKey_00024RSAPublic_nativeInit;
Java_com_oracle_security_ucrypto_NativeRSASignature_nativeInit;
@@ -56,6 +57,7 @@
JavaCritical_com_oracle_security_ucrypto_NativeCipher_nativeUpdate;
JavaCritical_com_oracle_security_ucrypto_NativeCipher_nativeFinal;
JavaCritical_com_oracle_security_ucrypto_NativeKey_nativeFree;
+ JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPrivate_nativeInit;
JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPrivateCrt_nativeInit;
JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPublic_nativeInit;
JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeInit;
--- a/jdk/make/netbeans/jdbc/build.properties Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/make/netbeans/jdbc/build.properties Tue Sep 08 14:40:44 2015 -0700
@@ -43,4 +43,4 @@
build.number = b00
jdbc.version = ${build.release}-${user.name}-${build.number}
jdbc.args = -debug
-javadoc.options=-J-Xmx256m -Xdoclint:none -keywords -quiet
\ No newline at end of file
+javadoc.options=-J-Xmx256m -Xdoclint:none -keywords -quiet
--- a/jdk/src/demo/share/applets/Fractal/example1.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/demo/share/applets/Fractal/example1.html Tue Sep 08 14:40:44 2015 -0700
@@ -23,5 +23,3 @@
<a href="CLSFractal.java">The source</a>.
</body>
</html>
-
-
--- a/jdk/src/demo/share/applets/MoleculeViewer/example1.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/demo/share/applets/MoleculeViewer/example1.html Tue Sep 08 14:40:44 2015 -0700
@@ -14,9 +14,3 @@
<a href="XYZApp.java">The source</a>.
</body>
</html>
-
-
-
-
-
-
--- a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties Tue Sep 08 14:40:44 2015 -0700
@@ -60,8 +60,8 @@
\ -dsa | -disablesystemassertions\n\
\ disable system assertions\n\
\ -agentlib:<libname>[=<options>]\n\
-\ load native agent library <libname>, e.g. -agentlib:hprof\n\
-\ see also, -agentlib:jdwp=help and -agentlib:hprof=help\n\
+\ load native agent library <libname>, e.g. -agentlib:jdwp\n\
+\ see also -agentlib:jdwp=help\n\
\ -agentpath:<pathname>[=<options>]\n\
\ load native agent library by full pathname\n\
\ -javaagent:<jarpath>[=<options>]\n\
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSPNonceExtension.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSPNonceExtension.java Tue Sep 08 14:40:44 2015 -0700
@@ -26,15 +26,13 @@
package sun.security.provider.certpath;
import java.io.IOException;
-import java.io.OutputStream;
-import java.util.Enumeration;
+import java.util.Objects;
import java.security.SecureRandom;
-import sun.security.x509.AttributeNameEnumeration;
-import sun.security.x509.CertAttrSet;
import sun.security.x509.Extension;
import sun.security.x509.PKIXExtensions;
-import sun.security.util.*;
+import sun.security.util.Debug;
+import sun.security.util.DerValue;
/**
* Represent the OCSP Nonce Extension.
@@ -43,252 +41,139 @@
* and help to prevent replay attacks (see RFC 6960, section 4.4.1).
*
* @see Extension
- * @see CertAttrSet
*/
-public class OCSPNonceExtension extends Extension
-implements CertAttrSet<String> {
+public final class OCSPNonceExtension extends Extension {
/**
* Attribute name.
*/
- public static final String NAME = "OCSPNonce";
- public static final String NONCE = "nonce";
-
+ private static final String EXTENSION_NAME = "OCSPNonce";
private byte[] nonceData = null;
- private String extensionName;
-
- /**
- * Encode this extension value to DER and assign it to the
- * {@code extensionName} data member.
- *
- * @throws IOException if any errors occur during DER encoding
- */
- private void encodeInternal() throws IOException {
- if (nonceData == null) {
- this.extensionValue = null;
- return;
- }
- DerOutputStream os = new DerOutputStream();
- os.putOctetString(this.nonceData);
- this.extensionValue = os.toByteArray();
- }
/**
* Create a {@code OCSPNonceExtension} by providing the nonce length.
- * The criticality is set to false. The random bytes will be generated
- * using the SUN provider.
+ * The criticality is set to false, and the OID for the extension will
+ * be the value defined by "id-pkix-ocsp-nonce" from RFC 6960.
*
* @param length the number of random bytes composing the nonce
*
* @throws IOException if any errors happen during encoding of the
* extension.
+ * @throws IllegalArgumentException if length is not a positive integer.
*/
public OCSPNonceExtension(int length) throws IOException {
- this(PKIXExtensions.OCSPNonce_Id, false, length, NAME);
- }
-
- /**
- * Creates the extension (also called by the subclass).
- *
- * @param extensionId the {@code ObjectIdentifier} for the OCSP Nonce
- * extension
- * @param isCritical a boolean flag indicating if the criticality bit
- * is to be set for this extension
- * @param length the length of the nonce in bytes
- * @param extensionName the name of the extension
- *
- * @throws IOException if any errors happen during encoding of the
- * extension.
- */
- protected OCSPNonceExtension(ObjectIdentifier extensionId,
- boolean isCritical, int length, String extensionName)
- throws IOException {
- SecureRandom rng = new SecureRandom();
- this.nonceData = new byte[length];
- rng.nextBytes(nonceData);
- this.extensionId = extensionId;
- this.critical = isCritical;
- this.extensionName = extensionName;
- encodeInternal();
- }
-
- /**
- * Create the extension using the provided criticality bit setting and
- * DER encoding.
- *
- * @param critical true if the extension is to be treated as critical.
- * @param value an array of DER encoded bytes of the extnValue for the
- * extension. It must not include the encapsulating OCTET STRING
- * tag and length. For an {@code OCSPNonceExtension} the data value
- * should be a simple OCTET STRING containing random bytes
- * (see RFC 6960, section 4.4.1).
- *
- * @throws ClassCastException if value is not an array of bytes
- * @throws IOException if any errors happen during encoding of the
- * extension
- */
- public OCSPNonceExtension(Boolean critical, Object value)
- throws IOException {
- this(PKIXExtensions.OCSPNonce_Id, critical, value, NAME);
+ this(false, length);
}
/**
- * Creates the extension (also called by the subclass).
- *
- * @param extensionId the {@code ObjectIdentifier} for the OCSP Nonce
- * extension
- * @param critical a boolean flag indicating if the criticality bit
- * is to be set for this extension
- * @param value an array of DER encoded bytes of the extnValue for the
- * extension. It must not include the encapsulating OCTET STRING
- * tag and length. For an {@code OCSPNonceExtension} the data value
- * should be a simple OCTET STRING containing random bytes
- * (see RFC 6960, section 4.4.1).
- * @param extensionName the name of the extension
+ * Create a {@code OCSPNonceExtension} by providing the nonce length and
+ * criticality setting. The OID for the extension will
+ * be the value defined by "id-pkix-ocsp-nonce" from RFC 6960.
*
- * @throws ClassCastException if value is not an array of bytes
- * @throws IOException if any errors happen during encoding of the
- * extension
- */
- protected OCSPNonceExtension(ObjectIdentifier extensionId,
- Boolean critical, Object value, String extensionName)
- throws IOException {
- this.extensionId = extensionId;
- this.critical = critical;
- this.extensionValue = (byte[]) value;
- DerValue val = new DerValue(this.extensionValue);
- this.nonceData = val.getOctetString();
- this.extensionName = extensionName;
- }
-
- /**
- * Set the attribute value.
- *
- * @param name the name of the attribute.
- * @param obj an array of nonce bytes for the extension. It must not
- * contain any DER tags or length.
+ * @param isCritical a boolean flag indicating whether the criticality bit
+ * is set for this extension
+ * @param length the number of random bytes composing the nonce
*
- * @throws IOException if an unsupported name is provided or the supplied
- * {@code obj} is not a byte array
+ * @throws IOException if any errors happen during encoding of the
+ * extension.
+ * @throws IllegalArgumentException if length is not a positive integer.
*/
- @Override
- public void set(String name, Object obj) throws IOException {
- if (name.equalsIgnoreCase(NONCE)) {
- if (!(obj instanceof byte[])) {
- throw new IOException("Attribute must be of type byte[].");
- }
- nonceData = (byte[])obj;
- } else {
- throw new IOException("Attribute name not recognized by"
- + " CertAttrSet:" + extensionName + ".");
- }
- encodeInternal();
- }
+ public OCSPNonceExtension(boolean isCritical, int length)
+ throws IOException {
+ this.extensionId = PKIXExtensions.OCSPNonce_Id;
+ this.critical = isCritical;
- /**
- * Get the attribute value.
- *
- * @param name the name of the attribute to retrieve. Only "OCSPNonce"
- * is currently supported.
- *
- * @return an array of bytes that are the nonce data. It will not contain
- * any DER tags or length, only the random nonce bytes.
- *
- * @throws IOException if an unsupported name is provided.
- */
- @Override
- public Object get(String name) throws IOException {
- if (name.equalsIgnoreCase(NONCE)) {
- return nonceData;
+ if (length > 0) {
+ SecureRandom rng = new SecureRandom();
+ this.nonceData = new byte[length];
+ rng.nextBytes(nonceData);
+ this.extensionValue = new DerValue(DerValue.tag_OctetString,
+ nonceData).toByteArray();
} else {
- throw new IOException("Attribute name not recognized by"
- + " CertAttrSet:" + extensionName + ".");
+ throw new IllegalArgumentException(
+ "Length must be a positive integer");
}
}
/**
- * Delete the attribute value.
+ * Create a {@code OCSPNonceExtension} by providing a nonce value.
+ * The criticality is set to false, and the OID for the extension will
+ * be the value defined by "id-pkix-ocsp-nonce" from RFC 6960.
*
- * @param name the name of the attribute to retrieve. Only "OCSPNonce"
- * is currently supported.
+ * @param incomingNonce The nonce data to be set for the extension. This
+ * must be a non-null array of at least one byte long.
*
- * @throws IOException if an unsupported name is provided or an error
- * occurs during re-encoding of the extension.
+ * @throws IOException if any errors happen during encoding of the
+ * extension.
+ * @throws IllegalArgumentException if the incomingNonce length is not a
+ * positive integer.
+ * @throws NullPointerException if the incomingNonce is null.
*/
- @Override
- public void delete(String name) throws IOException {
- if (name.equalsIgnoreCase(NONCE)) {
- nonceData = null;
+ public OCSPNonceExtension(byte[] incomingNonce) throws IOException {
+ this(false, incomingNonce);
+ }
+
+ /**
+ * Create a {@code OCSPNonceExtension} by providing a nonce value and
+ * criticality setting. The OID for the extension will
+ * be the value defined by "id-pkix-ocsp-nonce" from RFC 6960.
+ *
+ * @param isCritical a boolean flag indicating whether the criticality bit
+ * is set for this extension
+ * @param incomingNonce The nonce data to be set for the extension. This
+ * must be a non-null array of at least one byte long.
+ *
+ * @throws IOException if any errors happen during encoding of the
+ * extension.
+ * @throws IllegalArgumentException if the incomingNonce length is not a
+ * positive integer.
+ * @throws NullPointerException if the incomingNonce is null.
+ */
+ public OCSPNonceExtension(boolean isCritical, byte[] incomingNonce)
+ throws IOException {
+ this.extensionId = PKIXExtensions.OCSPNonce_Id;
+ this.critical = isCritical;
+
+ Objects.requireNonNull(incomingNonce, "Nonce data must be non-null");
+ if (incomingNonce.length > 0) {
+ this.nonceData = incomingNonce.clone();
+ this.extensionValue = new DerValue(DerValue.tag_OctetString,
+ nonceData).toByteArray();
} else {
- throw new IOException("Attribute name not recognized by"
- + " CertAttrSet:" + extensionName + ".");
+ throw new IllegalArgumentException(
+ "Nonce data must be at least 1 byte in length");
}
- encodeInternal();
+ }
+
+ /**
+ * Return the nonce bytes themselves, without any DER encoding.
+ *
+ * @return A copy of the underlying nonce bytes
+ */
+ public byte[] getNonceValue() {
+ return nonceData.clone();
}
/**
* Returns a printable representation of the {@code OCSPNonceExtension}.
+ *
+ * @return a string representation of the extension.
*/
@Override
public String toString() {
- String s = super.toString() + extensionName + ": " +
- ((nonceData == null) ? "" : Debug.toString(nonceData))
- + "\n";
- return (s);
- }
-
- /**
- * Write the extension to an {@code OutputStream}
- *
- * @param out the {@code OutputStream} to write the extension to.
- *
- * @throws IOException on encoding errors.
- */
- @Override
- public void encode(OutputStream out) throws IOException {
- encode(out, PKIXExtensions.OCSPNonce_Id, this.critical);
+ StringBuilder sb = new StringBuilder();
+ sb.append(super.toString()).append(EXTENSION_NAME).append(": ");
+ sb.append((nonceData == null) ? "" : Debug.toString(nonceData));
+ sb.append("\n");
+ return sb.toString();
}
/**
- * Write the extension to the DerOutputStream.
+ * Return the name of the extension as a {@code String}
*
- * @param out the {@code OutputStream} to write the extension to.
- * @param extensionId the {@code ObjectIdentifier} used for this extension
- * @param isCritical a flag indicating if the criticality bit is set for
- * this extension.
- *
- * @throws IOException on encoding errors.
+ * @return the name of the extension
*/
- protected void encode(OutputStream out, ObjectIdentifier extensionId,
- boolean isCritical) throws IOException {
-
- DerOutputStream tmp = new DerOutputStream();
-
- if (this.extensionValue == null) {
- this.extensionId = extensionId;
- this.critical = isCritical;
- encodeInternal();
- }
- super.encode(tmp);
- out.write(tmp.toByteArray());
- }
-
- /**
- * Return an enumeration of names of attributes existing within this
- * attribute.
- */
- @Override
- public Enumeration<String> getElements() {
- AttributeNameEnumeration elements = new AttributeNameEnumeration();
- elements.addElement(NONCE);
- return (elements.elements());
- }
-
- /**
- * Return the name of this attribute.
- */
- @Override
public String getName() {
- return (extensionName);
+ return EXTENSION_NAME;
}
}
--- a/jdk/src/java.base/share/native/libnet/InetAddress.c Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.base/share/native/libnet/InetAddress.c Tue Sep 08 14:40:44 2015 -0700
@@ -57,6 +57,7 @@
c = (*env)->FindClass(env,"java/net/InetAddress$InetAddressHolder");
CHECK_NULL(c);
iac_class = (*env)->NewGlobalRef(env, c);
+ CHECK_NULL(iac_class);
ia_holderID = (*env)->GetFieldID(env, ia_class, "holder", "Ljava/net/InetAddress$InetAddressHolder;");
CHECK_NULL(ia_holderID);
ia_preferIPv6AddressID = (*env)->GetStaticFieldID(env, ia_class, "preferIPv6Address", "Z");
--- a/jdk/src/java.base/share/native/libzip/Adler32.c Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.base/share/native/libzip/Adler32.c Tue Sep 08 14:40:44 2015 -0700
@@ -66,5 +66,3 @@
}
return adler;
}
-
-
--- a/jdk/src/java.base/unix/classes/sun/net/www/content-types.properties Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.base/unix/classes/sun/net/www/content-types.properties Tue Sep 08 14:40:44 2015 -0700
@@ -275,6 +275,3 @@
application/xml: \
description=XML document;\
file_extensions=.xml
-
-
-
--- a/jdk/src/java.base/unix/native/libjava/FileDescriptor_md.c Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.base/unix/native/libjava/FileDescriptor_md.c Tue Sep 08 14:40:44 2015 -0700
@@ -26,9 +26,11 @@
#include <unistd.h>
#include <fcntl.h>
+#include "jni.h"
+#include "jni_util.h"
#include "jvm.h"
+
#include "io_util_md.h"
-
#include "java_io_FileDescriptor.h"
/*******************************************************************/
@@ -47,8 +49,8 @@
JNIEXPORT void JNICALL
Java_java_io_FileDescriptor_initIDs(JNIEnv *env, jclass fdClass) {
- IO_fd_fdID = (*env)->GetFieldID(env, fdClass, "fd", "I");
- IO_append_fdID = (*env)->GetFieldID(env, fdClass, "append", "Z");
+ CHECK_NULL(IO_fd_fdID = (*env)->GetFieldID(env, fdClass, "fd", "I"));
+ CHECK_NULL(IO_append_fdID = (*env)->GetFieldID(env, fdClass, "append", "Z"));
}
/**************************************************************
--- a/jdk/src/java.base/windows/classes/sun/net/www/content-types.properties Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.base/windows/classes/sun/net/www/content-types.properties Tue Sep 08 14:40:44 2015 -0700
@@ -272,5 +272,3 @@
application/xml: \
description=XML document;\
file_extensions=.xml
-
-
--- a/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c Tue Sep 08 14:40:44 2015 -0700
@@ -45,9 +45,10 @@
jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
CHECK_NULL(cls);
isa_class = (*env)->NewGlobalRef(env, cls);
+ CHECK_NULL(isa_class);
isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
"(Ljava/net/InetAddress;I)V");
-
+ CHECK_NULL(isa_ctorID);
initInetAddressIDs(env);
// implement read timeout with select.
--- a/jdk/src/java.desktop/macosx/classes/com/apple/eawt/_OpenAppHandler.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/macosx/classes/com/apple/eawt/_OpenAppHandler.java Tue Sep 08 14:40:44 2015 -0700
@@ -27,4 +27,4 @@
interface _OpenAppHandler {
void handleOpenApp();
-}
\ No newline at end of file
+}
--- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java Tue Sep 08 14:40:44 2015 -0700
@@ -1096,4 +1096,4 @@
};
table.putDefaults(uiDefaults);
}
-}
\ No newline at end of file
+}
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDataTransferer.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDataTransferer.java Tue Sep 08 14:40:44 2015 -0700
@@ -278,5 +278,3 @@
return false;
}
}
-
-
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m Tue Sep 08 14:40:44 2015 -0700
@@ -1406,5 +1406,3 @@
return underMouse;
}
-
-
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CClipboard.m Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CClipboard.m Tue Sep 08 14:40:44 2015 -0700
@@ -289,4 +289,4 @@
JNF_COCOA_EXIT(env);
return ret;
-}
\ No newline at end of file
+}
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/MultiResolutionCachedImage.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/MultiResolutionCachedImage.java Tue Sep 08 14:40:44 2015 -0700
@@ -183,4 +183,4 @@
return false;
}
}
-}
\ No newline at end of file
+}
--- a/jdk/src/java.desktop/share/native/libfontmanager/layout/AnchorTables.h Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/AnchorTables.h Tue Sep 08 14:40:44 2015 -0700
@@ -80,5 +80,3 @@
U_NAMESPACE_END
#endif
-
-
--- a/jdk/src/java.desktop/share/native/libfontmanager/layout/CharSubstitutionFilter.h Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/CharSubstitutionFilter.h Tue Sep 08 14:40:44 2015 -0700
@@ -104,5 +104,3 @@
U_NAMESPACE_END
#endif
-
-
--- a/jdk/src/java.desktop/share/native/libfontmanager/layout/CursiveAttachmentSubtables.h Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/CursiveAttachmentSubtables.h Tue Sep 08 14:40:44 2015 -0700
@@ -63,5 +63,3 @@
U_NAMESPACE_END
#endif
-
-
--- a/jdk/src/java.desktop/share/native/libfontmanager/layout/DeviceTables.h Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/DeviceTables.h Tue Sep 08 14:40:44 2015 -0700
@@ -61,5 +61,3 @@
U_NAMESPACE_END
#endif
-
-
--- a/jdk/src/java.desktop/share/native/libfontmanager/layout/MPreFixups.h Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/MPreFixups.h Tue Sep 08 14:40:44 2015 -0700
@@ -63,5 +63,3 @@
U_NAMESPACE_END
#endif
-
-
--- a/jdk/src/java.desktop/share/native/libfontmanager/layout/MarkArrays.h Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/MarkArrays.h Tue Sep 08 14:40:44 2015 -0700
@@ -62,5 +62,3 @@
U_NAMESPACE_END
#endif
-
-
--- a/jdk/src/java.desktop/share/native/libfontmanager/layout/PairPositioningSubtables.h Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/PairPositioningSubtables.h Tue Sep 08 14:40:44 2015 -0700
@@ -109,5 +109,3 @@
U_NAMESPACE_END
#endif
-
-
--- a/jdk/src/java.desktop/share/native/libfontmanager/layout/SinglePositioningSubtables.h Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/SinglePositioningSubtables.h Tue Sep 08 14:40:44 2015 -0700
@@ -71,5 +71,3 @@
U_NAMESPACE_END
#endif
-
-
--- a/jdk/src/java.desktop/share/native/libfontmanager/layout/SingleSubstitutionSubtables.h Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/SingleSubstitutionSubtables.h Tue Sep 08 14:40:44 2015 -0700
@@ -68,5 +68,3 @@
U_NAMESPACE_END
#endif
-
-
--- a/jdk/src/java.desktop/share/native/libfontmanager/layout/ThaiShaping.h Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/ThaiShaping.h Tue Sep 08 14:40:44 2015 -0700
@@ -129,5 +129,3 @@
U_NAMESPACE_END
#endif
-
-
--- a/jdk/src/java.desktop/share/native/libfontmanager/layout/ValueRecords.h Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/ValueRecords.h Tue Sep 08 14:40:44 2015 -0700
@@ -94,5 +94,3 @@
U_NAMESPACE_END
#endif
-
-
--- a/jdk/src/java.desktop/share/native/liblcms/cmslut.c Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/liblcms/cmslut.c Tue Sep 08 14:40:44 2015 -0700
@@ -1836,5 +1836,3 @@
return TRUE;
}
-
-
--- a/jdk/src/java.desktop/share/native/liblcms/cmsmtrx.c Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/liblcms/cmsmtrx.c Tue Sep 08 14:40:44 2015 -0700
@@ -201,5 +201,3 @@
r->n[VY] = a->v[1].n[VX]*v->n[VX] + a->v[1].n[VY]*v->n[VY] + a->v[1].n[VZ]*v->n[VZ];
r->n[VZ] = a->v[2].n[VX]*v->n[VX] + a->v[2].n[VY]*v->n[VY] + a->v[2].n[VZ]*v->n[VZ];
}
-
-
--- a/jdk/src/java.desktop/share/native/liblcms/cmsplugin.c Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/liblcms/cmsplugin.c Tue Sep 08 14:40:44 2015 -0700
@@ -989,5 +989,3 @@
{
return _cmsContextGetClientChunk(ContextID, UserPtr);
}
-
-
--- a/jdk/src/java.desktop/share/native/liblcms/cmswtpnt.c Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/liblcms/cmswtpnt.c Tue Sep 08 14:40:44 2015 -0700
@@ -376,5 +376,3 @@
return TRUE;
}
-
-
--- a/jdk/src/java.desktop/share/native/libsplashscreen/java_awt_SplashScreen.c Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/share/native/libsplashscreen/java_awt_SplashScreen.c Tue Sep 08 14:40:44 2015 -0700
@@ -234,4 +234,4 @@
return 1;
}
return splash->scaleFactor;
-}
\ No newline at end of file
+}
--- a/jdk/src/java.desktop/windows/native/libawt/windows/DllUtil.cpp Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/DllUtil.cpp Tue Sep 08 14:40:44 2015 -0700
@@ -84,5 +84,3 @@
}
throw FunctionUnavailableException();
}
-
-
--- a/jdk/src/java.desktop/windows/native/libawt/windows/README.JNI Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/README.JNI Tue Sep 08 14:40:44 2015 -0700
@@ -131,5 +131,3 @@
2. Handle exceptions properly. The current code lacks error checking
and recovery. This leads to random runtime crashes.
-
-
--- a/jdk/src/java.logging/share/classes/java/util/logging/package.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.logging/share/classes/java/util/logging/package.html Tue Sep 08 14:40:44 2015 -0700
@@ -126,8 +126,3 @@
</body>
</html>
-
-
-
-
-
--- a/jdk/src/java.management/share/classes/javax/management/ObjectName.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.management/share/classes/javax/management/ObjectName.java Tue Sep 08 14:40:44 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -218,9 +218,19 @@
* <p>The <b>serialVersionUID</b> of this class is <code>1081892073854801359L</code>.
*
* @since 1.5
+ *
+ * @implNote The maximum allowed length of the domain name in this implementation
+ * is {@code Integer.MAX_VALUE/4}
*/
@SuppressWarnings("serial") // don't complain serialVersionUID not constant
public class ObjectName implements Comparable<ObjectName>, QueryExp {
+ private static final int DOMAIN_PATTERN = 0x8000_0000;
+ private static final int PROPLIST_PATTERN = 0x4000_0000;
+ private static final int PROPVAL_PATTERN = 0x2000_0000;
+
+ private static final int FLAG_MASK = DOMAIN_PATTERN | PROPLIST_PATTERN |
+ PROPVAL_PATTERN;
+ private static final int DOMAIN_LENGTH_MASK = ~FLAG_MASK;
/**
* A structure recording property structure and
@@ -365,33 +375,25 @@
/**
- * The length of the domain part of built objectname
- */
- private transient int _domain_length = 0;
-
-
- /**
* The propertyList of built object name. Initialized lazily.
* Table that contains all the pairs (key,value) for this ObjectName.
*/
private transient Map<String,String> _propertyList;
/**
- * boolean that declares if this ObjectName domain part is a pattern
- */
- private transient boolean _domain_pattern = false;
-
- /**
- * boolean that declares if this ObjectName contains a pattern on the
- * key property list
+ * This field encodes _domain_pattern, _property_list_pattern and
+ * _property_value_pattern booleans and _domain_length integer.
+ * <p>
+ * The following masks can be used to extract the value:
+ * <ul>
+ * <li>{@linkplain ObjectName#DOMAIN_PATTERN}</li>
+ * <li>{@linkplain ObjectName#PROPLIST_PATTERN}</li>
+ * <li>{@linkplain ObjectName#PROPVAL_PATTERN}</li>
+ * <li>{@linkplain ObjectName#DOMAIN_LENGTH_MASK}</li>
+ * </ul>
+ * </p>.
*/
- private transient boolean _property_list_pattern = false;
-
- /**
- * boolean that declares if this ObjectName contains a pattern on the
- * value of at least one key property
- */
- private transient boolean _property_value_pattern = false;
+ private transient int _compressed_storage = 0x0;
// Instance private fields <=======================================
@@ -426,11 +428,11 @@
_canonicalName = "*:*";
_kp_array = _Empty_property_array;
_ca_array = _Empty_property_array;
- _domain_length = 1;
+ setDomainLength(1);
_propertyList = null;
- _domain_pattern = true;
- _property_list_pattern = true;
- _property_value_pattern = false;
+ setDomainPattern(true);
+ setPropertyListPattern(true);
+ setPropertyValuePattern(false);
return;
}
@@ -448,7 +450,7 @@
while (index < len) {
switch (name_chars[index]) {
case ':' :
- _domain_length = index++;
+ setDomainLength(index++);
break domain_parsing;
case '=' :
// ":" omission check.
@@ -469,7 +471,7 @@
"Invalid character '\\n' in domain name");
case '*' :
case '?' :
- _domain_pattern = true;
+ setDomainPattern(true);
index++;
break;
default :
@@ -484,6 +486,7 @@
"Key properties cannot be empty");
// we have got the domain part, begins building of _canonicalName
+ int _domain_length = getDomainLength();
System.arraycopy(name_chars, 0, canonical_chars, 0, _domain_length);
canonical_chars[_domain_length] = ':';
cname_index = _domain_length + 1;
@@ -500,20 +503,20 @@
keys = new String[10];
_kp_array = new Property[10];
- _property_list_pattern = false;
- _property_value_pattern = false;
+ setPropertyListPattern(false);
+ setPropertyValuePattern(false);
while (index < len) {
c = name_chars[index];
// case of pattern properties
if (c == '*') {
- if (_property_list_pattern)
+ if (isPropertyListPattern())
throw new MalformedObjectNameException(
"Cannot have several '*' characters in pattern " +
"property list");
else {
- _property_list_pattern = true;
+ setPropertyListPattern(true);
if ((++index < len ) && (name_chars[index] != ','))
throw new MalformedObjectNameException(
"Invalid character found after '*': end of " +
@@ -639,7 +642,7 @@
if (!value_pattern) {
prop = new Property(key_index, key_length, value_length);
} else {
- _property_value_pattern = true;
+ setPropertyValuePattern(true);
prop = new PatternProperty(key_index, key_length, value_length);
}
key_name = name.substring(key_index, key_index + key_length);
@@ -670,7 +673,8 @@
* @exception MalformedObjectNameException The <code>domain</code>
* contains an illegal character, or one of the keys or values in
* <code>table</code> contains an illegal character, or one of the
- * values in <code>table</code> does not follow the rules for quoting.
+ * values in <code>table</code> does not follow the rules for quoting,
+ * or the domain's length exceeds the maximum allowed length.
* @exception NullPointerException One of the parameters is null.
*/
private void construct(String domain, Map<String,String> props)
@@ -696,7 +700,7 @@
// init canonicalname
final StringBuilder sb = new StringBuilder();
sb.append(domain).append(':');
- _domain_length = domain.length();
+ setDomainLength(domain.length());
// allocates the property array
int nb_props = props.size();
@@ -729,7 +733,7 @@
key.length(),
value.length());
} else {
- _property_value_pattern = true;
+ setPropertyValuePattern(true);
prop = new PatternProperty(key_index,
key.length(),
value.length());
@@ -743,10 +747,10 @@
char[] initial_chars = new char[len];
sb.getChars(0, len, initial_chars, 0);
char[] canonical_chars = new char[len];
- System.arraycopy(initial_chars, 0, canonical_chars, 0,
- _domain_length + 1);
+ int copyLen = getDomainLength() + 1;
+ System.arraycopy(initial_chars, 0, canonical_chars, 0, copyLen);
setCanonicalName(initial_chars, canonical_chars, keys, keys_map,
- _domain_length + 1, _kp_array.length);
+ copyLen, _kp_array.length);
}
// Category : Instance construction <==============================
@@ -822,7 +826,7 @@
}
// terminate canonicalname with '*' in case of pattern
- if (_property_list_pattern) {
+ if (isPropertyListPattern()) {
if (_kp_array != _Empty_property_array)
canonical_chars[prop_index++] = ',';
canonical_chars[prop_index++] = '*';
@@ -1051,13 +1055,32 @@
return false;
case '*' :
case '?' :
- _domain_pattern = true;
+ setDomainPattern(true);
break;
}
}
return true;
}
+ private int getDomainLength() {
+ return _compressed_storage & DOMAIN_LENGTH_MASK;
+ }
+
+ /**
+ * Validates and sets the domain length
+ * @param length The domain length
+ * @throws MalformedObjectNameException
+ * When the given domain length exceeds the maximum allowed length
+ */
+ private void setDomainLength(int length) throws MalformedObjectNameException {
+ if ((length & FLAG_MASK) != 0 ) {
+ throw new MalformedObjectNameException(
+ "Domain name too long. Maximum allowed domain name length is:" +
+ DOMAIN_LENGTH_MASK);
+ }
+ _compressed_storage = (_compressed_storage & FLAG_MASK) | length;
+ }
+
// Category : Internal accessors <==============================
// Category : Serialization ----------------------------------->
@@ -1225,12 +1248,12 @@
// Serializes this instance in the old serial form
// Read CR 6441274 before making any changes to this code
ObjectOutputStream.PutField fields = out.putFields();
- fields.put("domain", _canonicalName.substring(0, _domain_length));
+ fields.put("domain", _canonicalName.substring(0, getDomainLength()));
fields.put("propertyList", getKeyPropertyList());
fields.put("propertyListString", getKeyPropertyListString());
fields.put("canonicalName", _canonicalName);
- fields.put("pattern", (_domain_pattern || _property_list_pattern));
- fields.put("propertyPattern", _property_list_pattern);
+ fields.put("pattern", (_compressed_storage & (DOMAIN_PATTERN | PROPLIST_PATTERN)) != 0);
+ fields.put("propertyPattern", isPropertyListPattern());
out.writeFields();
}
else
@@ -1291,7 +1314,8 @@
* @exception MalformedObjectNameException The
* <code>domain</code>, <code>key</code>, or <code>value</code>
* contains an illegal character, or <code>value</code> does not
- * follow the rules for quoting.
+ * follow the rules for quoting, or the domain's length exceeds
+ * the maximum allowed length.
* @exception NullPointerException One of the parameters is null.
*
*/
@@ -1322,7 +1346,7 @@
* contains an illegal character, or one of the keys or values in
* <code>table</code> contains an illegal character, or one of the
* values in <code>table</code> does not follow the rules for
- * quoting.
+ * quoting, or the domain's length exceeds the maximum allowed length.
* @exception NullPointerException One of the parameters is null.
*
*/
@@ -1392,7 +1416,8 @@
* @exception MalformedObjectNameException The
* <code>domain</code>, <code>key</code>, or <code>value</code>
* contains an illegal character, or <code>value</code> does not
- * follow the rules for quoting.
+ * follow the rules for quoting, or the domain's length exceeds
+ * the maximum allowed length.
* @exception NullPointerException One of the parameters is null.
*/
public ObjectName(String domain, String key, String value)
@@ -1417,7 +1442,7 @@
* contains an illegal character, or one of the keys or values in
* <code>table</code> contains an illegal character, or one of the
* values in <code>table</code> does not follow the rules for
- * quoting.
+ * quoting, or the domain's length exceeds the maximum allowed length.
* @exception NullPointerException One of the parameters is null.
*/
public ObjectName(String domain, Hashtable<String,String> table)
@@ -1443,9 +1468,7 @@
* @return True if the name is a pattern, otherwise false.
*/
public boolean isPattern() {
- return (_domain_pattern ||
- _property_list_pattern ||
- _property_value_pattern);
+ return (_compressed_storage & FLAG_MASK) != 0;
}
/**
@@ -1455,7 +1478,20 @@
*
*/
public boolean isDomainPattern() {
- return _domain_pattern;
+ return (_compressed_storage & DOMAIN_PATTERN) != 0;
+ }
+
+ /**
+ * Marks the object name as representing a pattern on the domain part.
+ * @param value {@code true} if the domain name is a pattern,
+ * {@code false} otherwise
+ */
+ private void setDomainPattern(boolean value) {
+ if (value) {
+ _compressed_storage |= DOMAIN_PATTERN;
+ } else {
+ _compressed_storage &= ~DOMAIN_PATTERN;
+ }
}
/**
@@ -1468,7 +1504,7 @@
* @return True if the name is a property pattern, otherwise false.
*/
public boolean isPropertyPattern() {
- return _property_list_pattern || _property_value_pattern;
+ return (_compressed_storage & (PROPVAL_PATTERN | PROPLIST_PATTERN)) != 0;
}
/**
@@ -1482,7 +1518,20 @@
* @since 1.6
*/
public boolean isPropertyListPattern() {
- return _property_list_pattern;
+ return (_compressed_storage & PROPLIST_PATTERN) != 0;
+ }
+
+ /**
+ * Marks the object name as representing a pattern on the key property list.
+ * @param value {@code true} if the key property list is a pattern,
+ * {@code false} otherwise
+ */
+ private void setPropertyListPattern(boolean value) {
+ if (value) {
+ _compressed_storage |= PROPLIST_PATTERN;
+ } else {
+ _compressed_storage &= ~PROPLIST_PATTERN;
+ }
}
/**
@@ -1497,7 +1546,20 @@
* @since 1.6
*/
public boolean isPropertyValuePattern() {
- return _property_value_pattern;
+ return (_compressed_storage & PROPVAL_PATTERN) != 0;
+ }
+
+ /**
+ * Marks the object name as representing a pattern on the value part.
+ * @param value {@code true} if the value part of at least one of the
+ * key properties is a pattern, {@code false} otherwise
+ */
+ private void setPropertyValuePattern(boolean value) {
+ if (value) {
+ _compressed_storage |= PROPVAL_PATTERN;
+ } else {
+ _compressed_storage &= ~PROPVAL_PATTERN;
+ }
}
/**
@@ -1563,7 +1625,7 @@
* @return The domain.
*/
public String getDomain() {
- return _canonicalName.substring(0, _domain_length);
+ return _canonicalName.substring(0, getDomainLength());
}
/**
@@ -1640,8 +1702,8 @@
// the size of the string is the canonical one minus domain
// part and pattern part
- final int total_size = _canonicalName.length() - _domain_length - 1
- - (_property_list_pattern?2:0);
+ final int total_size = _canonicalName.length() - getDomainLength() - 1
+ - (isPropertyListPattern()?2:0);
final char[] dest_chars = new char[total_size];
final char[] value = _canonicalName.toCharArray();
@@ -1665,7 +1727,7 @@
final int total_size = _canonicalName.length();
final char[] dest_chars = new char[total_size];
final char[] value = _canonicalName.toCharArray();
- final int offset = _domain_length+1;
+ final int offset = getDomainLength() + 1;
// copy "domain:" into dest_chars
//
@@ -1675,7 +1737,7 @@
final int end = writeKeyPropertyListString(value,dest_chars,offset);
// Add ",*" if necessary
- if (_property_list_pattern) {
+ if (isPropertyListPattern()) {
if (end == offset) {
// Property list string is empty.
dest_chars[end] = '*';
@@ -1737,8 +1799,8 @@
if (_ca_array.length == 0) return "";
int len = _canonicalName.length();
- if (_property_list_pattern) len -= 2;
- return _canonicalName.substring(_domain_length +1, len);
+ if (isPropertyListPattern()) len -= 2;
+ return _canonicalName.substring(getDomainLength() + 1, len);
}
// Category : Getter methods <===================================
@@ -1944,22 +2006,18 @@
if (name == null) throw new NullPointerException();
- if (name._domain_pattern ||
- name._property_list_pattern ||
- name._property_value_pattern)
+ if (name.isPattern())
return false;
// No pattern
- if (!_domain_pattern &&
- !_property_list_pattern &&
- !_property_value_pattern)
+ if (!isPattern())
return _canonicalName.equals(name._canonicalName);
return matchDomains(name) && matchKeys(name);
}
private final boolean matchDomains(ObjectName name) {
- if (_domain_pattern) {
+ if (isDomainPattern()) {
// wildmatch domains
// This ObjectName is the pattern
// The other ObjectName is the string.
@@ -1972,15 +2030,15 @@
// If key property value pattern but not key property list
// pattern, then the number of key properties must be equal
//
- if (_property_value_pattern &&
- !_property_list_pattern &&
+ if (isPropertyValuePattern() &&
+ !isPropertyListPattern() &&
(name._ca_array.length != _ca_array.length))
return false;
// If key property value pattern or key property list pattern,
// then every property inside pattern should exist in name
//
- if (_property_value_pattern || _property_list_pattern) {
+ if (isPropertyPattern()) {
final Map<String,String> nameProps = name._getKeyPropertyList();
final Property[] props = _ca_array;
final String cn = _canonicalName;
@@ -1996,7 +2054,7 @@
if (v == null) return false;
// If this property is ok (same key, same value), go to next
//
- if (_property_value_pattern && (p instanceof PatternProperty)) {
+ if (isPropertyValuePattern() && (p instanceof PatternProperty)) {
// wildmatch key property values
// p is the property pattern, v is the string
if (Util.wildmatch(v,p.getValueString(cn)))
--- a/jdk/src/java.security.jgss/share/classes/javax/security/auth/kerberos/DelegationPermission.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.security.jgss/share/classes/javax/security/auth/kerberos/DelegationPermission.java Tue Sep 08 14:40:44 2015 -0700
@@ -132,7 +132,9 @@
* Checks if this Kerberos delegation permission object "implies" the
* specified permission.
* <P>
- * If none of the above are true, {@code implies} returns false.
+ * This method returns true if this {@code DelegationPermission}
+ * is equal to {@code p}, and returns false otherwise.
+ *
* @param p the permission to check against.
*
* @return true if the specified permission is implied by this object,
--- a/jdk/src/java.security.jgss/share/classes/javax/security/auth/kerberos/ServicePermission.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.security.jgss/share/classes/javax/security/auth/kerberos/ServicePermission.java Tue Sep 08 14:40:44 2015 -0700
@@ -179,7 +179,16 @@
* Checks if this Kerberos service permission object "implies" the
* specified permission.
* <P>
- * If none of the above are true, {@code implies} returns false.
+ * More specifically, this method returns true if all of the following
+ * are true (and returns false if any of them are not):
+ * <ul>
+ * <li> <i>p</i> is an instanceof {@code ServicePermission},
+ * <li> <i>p</i>'s actions are a proper subset of this
+ * {@code ServicePermission}'s actions,
+ * <li> <i>p</i>'s name is equal to this {@code ServicePermission}'s name
+ * or this {@code ServicePermission}'s name is "*".
+ * </ul>
+ *
* @param p the permission to check against.
*
* @return true if the specified permission is implied by this object,
--- a/jdk/src/java.sql.rowset/share/classes/javax/sql/rowset/BaseRowSet.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.sql.rowset/share/classes/javax/sql/rowset/BaseRowSet.java Tue Sep 08 14:40:44 2015 -0700
@@ -4467,4 +4467,4 @@
static final long serialVersionUID = 4886719666485113312L;
-} //end class
\ No newline at end of file
+} //end class
--- a/jdk/src/java.sql.rowset/share/classes/javax/sql/rowset/RowSetFactory.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.sql.rowset/share/classes/javax/sql/rowset/RowSetFactory.java Tue Sep 08 14:40:44 2015 -0700
@@ -96,4 +96,4 @@
*/
public WebRowSet createWebRowSet() throws SQLException;
-}
\ No newline at end of file
+}
--- a/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/algorithms/package.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/algorithms/package.html Tue Sep 08 14:40:44 2015 -0700
@@ -1,3 +1,3 @@
<HTML><HEAD></HEAD><BODY><P>
algorithm factories.
-</P></BODY></HTML>
\ No newline at end of file
+</P></BODY></HTML>
--- a/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/package.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/package.html Tue Sep 08 14:40:44 2015 -0700
@@ -1,3 +1,3 @@
<HTML><HEAD></HEAD><BODY><P>
basic handlers for elements that can occur inside <CODE>ds:KeyValue</CODE>.
-</P></BODY></HTML>
\ No newline at end of file
+</P></BODY></HTML>
--- a/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/content/package.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/content/package.html Tue Sep 08 14:40:44 2015 -0700
@@ -1,3 +1,3 @@
<HTML><HEAD></HEAD><BODY><P>
basic handlers for elements that can occur inside <CODE>ds:KeyInfo</CODE>.
-</P></BODY></HTML>
\ No newline at end of file
+</P></BODY></HTML>
--- a/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/package.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/package.html Tue Sep 08 14:40:44 2015 -0700
@@ -1,3 +1,3 @@
<HTML><HEAD></HEAD><BODY><P>
basic handlers for elements that can occur inside <CODE>ds:X509Data</CODE>.
-</P></BODY></HTML>
\ No newline at end of file
+</P></BODY></HTML>
--- a/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/package.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/package.html Tue Sep 08 14:40:44 2015 -0700
@@ -1,3 +1,3 @@
<HTML><HEAD></HEAD><BODY><P>
implementations for retrieval of certificates and public keys from elements.
-</P></BODY></HTML>
\ No newline at end of file
+</P></BODY></HTML>
--- a/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/package.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/package.html Tue Sep 08 14:40:44 2015 -0700
@@ -1,3 +1,3 @@
<HTML><HEAD></HEAD><BODY><P>
the resolver framework for retrieval of certificates and public keys from elements.
-</P></BODY></HTML>
\ No newline at end of file
+</P></BODY></HTML>
--- a/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/package.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/package.html Tue Sep 08 14:40:44 2015 -0700
@@ -1,3 +1,3 @@
<HTML><HEAD></HEAD><BODY><P>
implementations of resolvers for retrieval for certificates and public keys from user-specified locations.
-</P></BODY></HTML>
\ No newline at end of file
+</P></BODY></HTML>
--- a/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/package.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/package.html Tue Sep 08 14:40:44 2015 -0700
@@ -1,3 +1,3 @@
<HTML><HEAD></HEAD><BODY><P>
a resolver framework for certificates and public keys from user-specified locations.
-</P></BODY></HTML>
\ No newline at end of file
+</P></BODY></HTML>
--- a/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/transforms/TransformParam.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/transforms/TransformParam.java Tue Sep 08 14:40:44 2015 -0700
@@ -24,4 +24,4 @@
package com.sun.org.apache.xml.internal.security.transforms;
public interface TransformParam {
-}
\ No newline at end of file
+}
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeKey.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeKey.java Tue Sep 08 14:40:44 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,19 +31,9 @@
import java.lang.ref.*;
import java.math.BigInteger;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.Key;
-import java.security.PublicKey;
-import java.security.PrivateKey;
-import java.security.KeyFactorySpi;
-import java.security.interfaces.RSAPrivateCrtKey;
-import java.security.interfaces.RSAPublicKey;
-
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.security.spec.RSAPrivateCrtKeySpec;
-import java.security.spec.RSAPublicKeySpec;
+import java.security.*;
+import java.security.interfaces.*;
+import java.security.spec.*;
/**
* Wrapper class for native keys needed for using ucrypto APIs.
@@ -87,6 +77,41 @@
return b;
}
+ static final class RSAPrivate extends NativeKey implements RSAPrivateKey {
+
+ private static final long serialVersionUID = 1622705588904302831L;
+
+ private final RSAPrivateKeySpec keySpec;
+ private final long keyId;
+
+ RSAPrivate(KeySpec keySpec) throws InvalidKeySpecException {
+ super(2);
+ long pKey = 0L;
+ if (keySpec instanceof RSAPrivateKeySpec) {
+ RSAPrivateKeySpec ks = (RSAPrivateKeySpec) keySpec;
+ BigInteger mod = ks.getModulus();
+ BigInteger privateExp = ks.getPrivateExponent();
+ pKey = nativeInit(NativeKey.getMagnitude(mod),
+ NativeKey.getMagnitude(privateExp));
+ } else {
+ throw new InvalidKeySpecException("Only supports RSAPrivateKeySpec");
+ }
+ if (pKey == 0L) {
+ throw new UcryptoException("Error constructing RSA PrivateKey");
+ }
+ // track native resource clean up
+ new KeyRef(this, pKey);
+ this.keySpec = (RSAPrivateKeySpec) keySpec;
+ this.keyId = pKey;
+ }
+
+ long value() { return keyId; }
+ public BigInteger getModulus() { return keySpec.getModulus(); };
+ public BigInteger getPrivateExponent() { return keySpec.getPrivateExponent(); };
+
+ private native static long nativeInit(byte[] mod, byte[] privExp);
+ }
+
static final class RSAPrivateCrt extends NativeKey implements RSAPrivateCrtKey {
private static final long serialVersionUID = 6812507588904302831L;
@@ -119,7 +144,7 @@
throw new InvalidKeySpecException("Only supports RSAPrivateCrtKeySpec");
}
if (pKey == 0L) {
- throw new UcryptoException("Error constructing RSA PrivateKey");
+ throw new UcryptoException("Error constructing RSA PrivateCrtKey");
}
// track native resource clean up
new KeyRef(this, pKey);
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSACipher.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSACipher.java Tue Sep 08 14:40:44 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,9 +37,11 @@
import java.security.PublicKey;
import java.security.PrivateKey;
import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.interfaces.RSAKey;
import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.KeyFactory;
@@ -205,8 +207,8 @@
// Make sure the proper opmode uses the proper key
if (doEncrypt && (!(newKey instanceof RSAPublicKey))) {
throw new InvalidKeyException("RSAPublicKey required for encryption");
- } else if (!doEncrypt && (!(newKey instanceof RSAPrivateCrtKey))) {
- throw new InvalidKeyException("RSAPrivateCrtKey required for decryption");
+ } else if (!doEncrypt && (!(newKey instanceof RSAPrivateKey))) {
+ throw new InvalidKeyException("RSAPrivateKey required for decryption");
}
NativeKey nativeKey = null;
@@ -223,17 +225,26 @@
throw new InvalidKeyException(ikse);
}
} else {
- RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) newKey;
try {
- nativeKey = (NativeKey) keyFactory.engineGeneratePrivate
- (new RSAPrivateCrtKeySpec(privateKey.getModulus(),
- privateKey.getPublicExponent(),
- privateKey.getPrivateExponent(),
- privateKey.getPrimeP(),
- privateKey.getPrimeQ(),
- privateKey.getPrimeExponentP(),
- privateKey.getPrimeExponentQ(),
- privateKey.getCrtCoefficient()));
+ if (newKey instanceof RSAPrivateCrtKey) {
+ RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) newKey;
+ nativeKey = (NativeKey) keyFactory.engineGeneratePrivate
+ (new RSAPrivateCrtKeySpec(privateKey.getModulus(),
+ privateKey.getPublicExponent(),
+ privateKey.getPrivateExponent(),
+ privateKey.getPrimeP(),
+ privateKey.getPrimeQ(),
+ privateKey.getPrimeExponentP(),
+ privateKey.getPrimeExponentQ(),
+ privateKey.getCrtCoefficient()));
+ } else if (newKey instanceof RSAPrivateKey) {
+ RSAPrivateKey privateKey = (RSAPrivateKey) newKey;
+ nativeKey = (NativeKey) keyFactory.engineGeneratePrivate
+ (new RSAPrivateKeySpec(privateKey.getModulus(),
+ privateKey.getPrivateExponent()));
+ } else {
+ throw new InvalidKeyException("Unsupported type of RSAPrivateKey");
+ }
} catch (InvalidKeySpecException ikse) {
throw new InvalidKeyException(ikse);
}
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSAKeyFactory.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSAKeyFactory.java Tue Sep 08 14:40:44 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,16 +38,11 @@
import java.security.PrivateKey;
import java.security.KeyFactorySpi;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.security.spec.RSAPrivateCrtKeySpec;
-import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.*;
/**
* Ucrypto-private KeyFactory class for generating native keys
- * needed for using ucrypto APIs. Given that it's not used
- * externally, it only needs to support RSAPrivateCrtKeySpec
- * and RSAPublicKeySpec objects.
+ * needed for using ucrypto APIs.
*
* @since 1.9
*/
@@ -56,7 +51,13 @@
@Override
protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
throws InvalidKeySpecException {
- return new NativeKey.RSAPrivateCrt(keySpec);
+ if (keySpec instanceof RSAPrivateCrtKeySpec) {
+ return new NativeKey.RSAPrivateCrt(keySpec);
+ } else if (keySpec instanceof RSAPrivateKeySpec) {
+ return new NativeKey.RSAPrivate(keySpec);
+ } else {
+ throw new InvalidKeySpecException("Unsupported key spec");
+ }
}
@Override
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSASignature.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSASignature.java Tue Sep 08 14:40:44 2015 -0700
@@ -43,9 +43,8 @@
import java.security.*;
import java.security.interfaces.*;
-import java.security.spec.RSAPrivateCrtKeySpec;
-import java.security.spec.RSAPublicKeySpec;
-import java.security.spec.InvalidKeySpecException;
+import java.security.spec.*;
+
import sun.nio.ch.DirectBuffer;
import java.nio.ByteBuffer;
@@ -192,25 +191,31 @@
int newSigLength = sigLength;
// Need to check RSA key length whenever a new private key is set
if (privateKey != key) {
- if (privateKey instanceof RSAPrivateCrtKey) {
- RSAPrivateCrtKey rsaPrivKey = (RSAPrivateCrtKey) privateKey;
- BigInteger mod = rsaPrivKey.getModulus();
- newSigLength = checkRSAKeyLength(mod);
- try {
+ if (!(privateKey instanceof RSAPrivateKey)) {
+ throw new InvalidKeyException("RSAPrivateKey required");
+ }
+ RSAPrivateKey rsaPrivKey = (RSAPrivateKey) privateKey;
+ BigInteger mod = rsaPrivKey.getModulus();
+ newSigLength = checkRSAKeyLength(mod);
+ BigInteger pe = rsaPrivKey.getPrivateExponent();
+ try {
+ if (rsaPrivKey instanceof RSAPrivateCrtKey) {
+ RSAPrivateCrtKey rsaPrivCrtKey = (RSAPrivateCrtKey) rsaPrivKey;
newKey = (NativeKey) keyFactory.engineGeneratePrivate
(new RSAPrivateCrtKeySpec(mod,
- rsaPrivKey.getPublicExponent(),
- rsaPrivKey.getPrivateExponent(),
- rsaPrivKey.getPrimeP(),
- rsaPrivKey.getPrimeQ(),
- rsaPrivKey.getPrimeExponentP(),
- rsaPrivKey.getPrimeExponentQ(),
- rsaPrivKey.getCrtCoefficient()));
- } catch (InvalidKeySpecException ikse) {
- throw new InvalidKeyException(ikse);
+ rsaPrivCrtKey.getPublicExponent(),
+ pe,
+ rsaPrivCrtKey.getPrimeP(),
+ rsaPrivCrtKey.getPrimeQ(),
+ rsaPrivCrtKey.getPrimeExponentP(),
+ rsaPrivCrtKey.getPrimeExponentQ(),
+ rsaPrivCrtKey.getCrtCoefficient()));
+ } else {
+ newKey = (NativeKey) keyFactory.engineGeneratePrivate
+ (new RSAPrivateKeySpec(mod, pe));
}
- } else {
- throw new InvalidKeyException("RSAPrivateCrtKey required");
+ } catch (InvalidKeySpecException ikse) {
+ throw new InvalidKeyException(ikse);
}
}
init(true, newKey, newSigLength);
--- a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.c Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.c Tue Sep 08 14:40:44 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -435,6 +435,11 @@
int rv = 0;
context = (crypto_ctx_t *) pContext;
+ // Avoid null output buffer to workaround Solaris bug21481818 (fixed in S12)
+ if (bufOut == NULL) {
+ bufOut = (unsigned char *)(&outLen);
+ outLen = 0;
+ }
rv = CipherFinal(context, encrypt, (unsigned char*)bufOut, outOfs, &outLen);
free(context);
if (rv) {
@@ -648,7 +653,8 @@
// out is null when nativeFinal() is called solely for resource clean up
if (out == NULL) {
- bufOut = NULL;
+ // Avoid null output buffer to workaround Solaris bug21481818 (fixed in S12)
+ bufOut = (unsigned char *)(&outLen);
outLen = 0;
} else {
outLen = (*env)->GetArrayLength(env, out) - outOfs;
@@ -661,10 +667,12 @@
rv = CipherFinal(context, encrypt, bufOut, 0, &outLen);
if (rv) {
free(context);
- free(bufOut);
+ if (outLen != 0) {
+ free(bufOut);
+ }
return -rv;
} else {
- if (bufOut != NULL) {
+ if (bufOut != NULL && outLen != 0) {
(*env)->SetByteArrayRegion(env, out, outOfs, outLen, (jbyte *)bufOut);
free(bufOut);
}
@@ -697,6 +705,86 @@
}
/*
+ * Class: com_oracle_security_ucrypto_NativeKey_RSAPrivate
+ * Method: nativeInit
+ * Signature: ([B[B)J
+ */
+jlong JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPrivate_nativeInit
+(int modLen, jbyte* jMod, int privLen, jbyte* jPriv) {
+
+ unsigned char *mod, *priv;
+ crypto_object_attribute_t* pKey = NULL;
+
+ pKey = calloc(2, sizeof(crypto_object_attribute_t));
+ if (pKey == NULL) {
+ return 0L;
+ }
+ mod = priv = NULL;
+ mod = malloc(modLen);
+ priv = malloc(privLen);
+ if (mod == NULL || priv == NULL) {
+ free(pKey);
+ free(mod);
+ free(priv);
+ return 0L;
+ } else {
+ memcpy(mod, jMod, modLen);
+ memcpy(priv, jPriv, privLen);
+ }
+
+ // NOTE: numOfComponents should be 2
+ pKey[0].oa_type = SUN_CKA_MODULUS;
+ pKey[0].oa_value = (char*) mod;
+ pKey[0].oa_value_len = (size_t) modLen;
+ pKey[1].oa_type = SUN_CKA_PRIVATE_EXPONENT;
+ pKey[1].oa_value = (char*) priv;
+ pKey[1].oa_value_len = (size_t) privLen;
+
+ return (jlong) pKey;
+}
+
+JNIEXPORT jlong JNICALL
+Java_com_oracle_security_ucrypto_NativeKey_00024RSAPrivate_nativeInit
+ (JNIEnv *env, jclass jCls, jbyteArray jMod, jbyteArray jPriv) {
+
+ int modLen, privLen;
+ jbyte *bufMod, *bufPriv;
+ crypto_object_attribute_t* pKey = NULL;
+
+ bufMod = bufPriv = NULL;
+
+ modLen = (*env)->GetArrayLength(env, jMod);
+ bufMod = getBytes(env, jMod, 0, modLen);
+ if ((*env)->ExceptionCheck(env)) goto cleanup;
+
+ privLen = (*env)->GetArrayLength(env, jPriv);
+ bufPriv = getBytes(env, jPriv, 0, privLen);
+ if ((*env)->ExceptionCheck(env)) goto cleanup;
+
+ // proceed if no error; otherwise free allocated memory
+ pKey = calloc(2, sizeof(crypto_object_attribute_t));
+ if (pKey == NULL) {
+ throwOutOfMemoryError(env, NULL);
+ goto cleanup;
+ }
+
+ // NOTE: numOfComponents should be 2
+ pKey[0].oa_type = SUN_CKA_MODULUS;
+ pKey[0].oa_value = (char*) bufMod;
+ pKey[0].oa_value_len = (size_t) modLen;
+ pKey[1].oa_type = SUN_CKA_PRIVATE_EXPONENT;
+ pKey[1].oa_value = (char*) bufPriv;
+ pKey[1].oa_value_len = (size_t) privLen;
+ return (jlong) pKey;
+
+cleanup:
+ free(bufMod);
+ free(bufPriv);
+
+ return 0L;
+}
+
+/*
* Class: com_oracle_security_ucrypto_NativeKey_RSAPrivateCrt
* Method: nativeInit
* Signature: ([B[B[B[B[B[B[B[B)J
--- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jps/Jps.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jps/Jps.java Tue Sep 08 14:40:44 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
* 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,11 @@
errorString = " -- jvm args information unavailable";
String jvmArgs = MonitoredVmUtil.jvmArgs(vm);
if (jvmArgs != null && jvmArgs.length() > 0) {
- output.append(' ').append(jvmArgs);
+ output.append(' ')
+ .append(
+ // multi-line args are permitted
+ jvmArgs.replace("\n", "\\n").replace("\r", "\\r")
+ );
}
}
if (arguments.showVmFlags()) {
--- a/jdk/src/jdk.management/linux/native/libmanagement_ext/UnixOperatingSystem.c Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/jdk.management/linux/native/libmanagement_ext/UnixOperatingSystem.c Tue Sep 08 14:40:44 2015 -0700
@@ -77,14 +77,17 @@
static int get_totalticks(int which, ticks *pticks) {
FILE *fh;
uint64_t userTicks, niceTicks, systemTicks, idleTicks;
+ uint64_t iowTicks = 0, irqTicks = 0, sirqTicks= 0;
int n;
if((fh = fopen("/proc/stat", "r")) == NULL) {
return -1;
}
- n = fscanf(fh, "cpu " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64,
- &userTicks, &niceTicks, &systemTicks, &idleTicks);
+ n = fscanf(fh, "cpu " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 " "
+ DEC_64 " " DEC_64,
+ &userTicks, &niceTicks, &systemTicks, &idleTicks,
+ &iowTicks, &irqTicks, &sirqTicks);
// Move to next line
next_line(fh);
@@ -93,24 +96,30 @@
if (which != -1) {
int i;
for (i = 0; i < which; i++) {
- if (fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64, &userTicks, &niceTicks, &systemTicks, &idleTicks) != 4) {
+ if (fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 " "
+ DEC_64 " " DEC_64 " " DEC_64,
+ &userTicks, &niceTicks, &systemTicks, &idleTicks,
+ &iowTicks, &irqTicks, &sirqTicks) < 4) {
fclose(fh);
return -2;
}
next_line(fh);
}
- n = fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 "\n",
- &userTicks, &niceTicks, &systemTicks, &idleTicks);
+ n = fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 " "
+ DEC_64 " " DEC_64 " " DEC_64 "\n",
+ &userTicks, &niceTicks, &systemTicks, &idleTicks,
+ &iowTicks, &irqTicks, &sirqTicks);
}
fclose(fh);
- if (n != 4) {
+ if (n < 4) {
return -2;
}
pticks->used = userTicks + niceTicks;
- pticks->usedKernel = systemTicks;
- pticks->total = userTicks + niceTicks + systemTicks + idleTicks;
+ pticks->usedKernel = systemTicks + irqTicks + sirqTicks;
+ pticks->total = userTicks + niceTicks + systemTicks + idleTicks +
+ iowTicks + irqTicks + sirqTicks;
return 0;
}
--- a/jdk/src/sample/share/annotations/DependencyChecker/PluginChecker/src/checker/Kettle.xml Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/sample/share/annotations/DependencyChecker/PluginChecker/src/checker/Kettle.xml Tue Sep 08 14:40:44 2015 -0700
@@ -54,4 +54,4 @@
<value>4</value>
</entry>
</supportedModules>
-</device>
\ No newline at end of file
+</device>
--- a/jdk/src/sample/share/annotations/index.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/sample/share/annotations/index.html Tue Sep 08 14:40:44 2015 -0700
@@ -64,4 +64,4 @@
Sources: <a href="Validator/src/">Validator/src/</a>
</ul>
</body>
-</html>
\ No newline at end of file
+</html>
--- a/jdk/src/sample/share/lambda/BulkDataOperations/index.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/sample/share/lambda/BulkDataOperations/index.html Tue Sep 08 14:40:44 2015 -0700
@@ -46,4 +46,4 @@
Source: <a href="src/WC.java">src/WC.java</a>
</ul>
</body>
-</html>
\ No newline at end of file
+</html>
--- a/jdk/src/sample/share/try-with-resources/index.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/src/sample/share/try-with-resources/index.html Tue Sep 08 14:40:44 2015 -0700
@@ -33,4 +33,4 @@
</ul>
</body>
-</html>
\ No newline at end of file
+</html>
--- a/jdk/test/ProblemList.txt Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/ProblemList.txt Tue Sep 08 14:40:44 2015 -0700
@@ -136,9 +136,6 @@
# 8133552
java/lang/ProcessHandle/InfoTest.java generic-all
-# 8134677
-java/lang/SecurityManager/CheckPackageMatching.java windows-all
-
############################################################################
# jdk_instrument
@@ -322,6 +319,9 @@
# jdk_time
+# 8134979
+java/time/tck/java/time/chrono/TCKJapaneseChronology.java generic-all
+
############################################################################
# jdk_tools
@@ -387,11 +387,6 @@
# 6456333
sun/tools/jps/TestJpsJarRelative.java generic-all
-# 8134420
-sun/tools/jps/TestJpsClass.java generic-all
-sun/tools/jps/TestJpsJar.java generic-all
-sun/tools/jps/TestJpsSanity.java generic-all
-
# 6734748
sun/tools/jinfo/JInfoRunningProcessFlagTest.java generic-all
--- a/jdk/test/com/oracle/security/ucrypto/CipherSignNotSupported.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/com/oracle/security/ucrypto/CipherSignNotSupported.java Tue Sep 08 14:40:44 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
/**
* @test
- * @bug 8029849
+ * @bug 8029849 8132082
* @summary Make sure signing via encrypt and verifying via decrypt are not
* supported by OracleUcrypto provider.
* @author Anthony Scarpino
@@ -31,12 +31,10 @@
*/
import java.util.Random;
-import java.security.KeyPairGenerator;
-import java.security.KeyPair;
+import java.security.*;
+import java.security.interfaces.*;
+import java.security.spec.RSAPrivateKeySpec;
import javax.crypto.Cipher;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.Provider;
public class CipherSignNotSupported extends UcryptoTest {
@@ -69,27 +67,43 @@
c.init(Cipher.ENCRYPT_MODE, kp.getPublic());
ct = c.doFinal(pt);
// Decryption
- c.init(Cipher.DECRYPT_MODE, kp.getPrivate());
- c.doFinal(ct);
- // Sign
- try {
- c.init(Cipher.ENCRYPT_MODE, kp.getPrivate());
- ct = c.doFinal(pt);
- throw new RuntimeException("Encrypt operation should have failed.");
- } catch (InvalidKeyException e) {
- if (e.getMessage().compareTo("RSAPublicKey required for " +
- "encryption") != 0) {
- System.out.println("Wrong exception thrown.");
- throw e;
+ PrivateKey[] privKeys = new PrivateKey[2];
+ privKeys[0] = kp.getPrivate();
+ if (privKeys[0] instanceof RSAPrivateCrtKey) {
+ RSAPrivateCrtKey k = (RSAPrivateCrtKey) privKeys[0];
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ privKeys[1] = kf.generatePrivate
+ (new RSAPrivateKeySpec(k.getModulus(), k.getPrivateExponent()));
+ } else {
+ privKeys = new PrivateKey[] {privKeys[0]};
+ }
+
+ for (PrivateKey pk : privKeys) {
+ System.out.println("Testing " + pk);
+ c.init(Cipher.DECRYPT_MODE, pk);
+ c.doFinal(ct);
+
+ // Sign
+ try {
+ c.init(Cipher.ENCRYPT_MODE, pk);
+ ct = c.doFinal(pt);
+ throw new RuntimeException("Encrypt operation should have failed.");
+ } catch (InvalidKeyException e) {
+ if (e.getMessage().compareTo("RSAPublicKey required for " +
+ "encryption") != 0) {
+ System.out.println("Wrong exception thrown.");
+ throw e;
+ }
}
}
+
// Verify
try {
c.init(Cipher.DECRYPT_MODE, kp.getPublic());
c.doFinal(ct);
throw new RuntimeException("Decrypt operation should have failed.");
} catch (InvalidKeyException e) {
- if (e.getMessage().compareTo("RSAPrivateCrtKey required for " +
+ if (e.getMessage().compareTo("RSAPrivateKey required for " +
"decryption") != 0) {
System.out.println("Wrong exception thrown.");
throw e;
--- a/jdk/test/com/sun/awt/SecurityWarning/GetSizeShouldNotReturnZero.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/com/sun/awt/SecurityWarning/GetSizeShouldNotReturnZero.java Tue Sep 08 14:40:44 2015 -0700
@@ -374,5 +374,3 @@
}
}// TestDialog class
-
-
--- a/jdk/test/com/sun/crypto/provider/Mac/Utils.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/com/sun/crypto/provider/Mac/Utils.java Tue Sep 08 14:40:44 2015 -0700
@@ -76,4 +76,4 @@
interface MacTest {
void doTest(String alg) throws Exception;
-}
\ No newline at end of file
+}
--- a/jdk/test/com/sun/jdi/InterfaceMethodsTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/com/sun/jdi/InterfaceMethodsTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -442,6 +442,3 @@
}
}
}
-
-
-
--- a/jdk/test/com/sun/jdi/ShellScaffold.sh Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/com/sun/jdi/ShellScaffold.sh Tue Sep 08 14:40:44 2015 -0700
@@ -1215,5 +1215,3 @@
# Don't know how this arises
debuggeeFailIfPresent "Internal exception"
}
-
-
--- a/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Client/ConfigKey.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Client/ConfigKey.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,4 +23,4 @@
public enum ConfigKey {
CONSTANT3, CONSTANT2;
-}
\ No newline at end of file
+}
--- a/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Server/ConfigKey.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Server/ConfigKey.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,4 +23,4 @@
public enum ConfigKey {
CONSTANT1, CONSTANT2;
-}
\ No newline at end of file
+}
--- a/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Server/Ste.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Server/Ste.java Tue Sep 08 14:40:44 2015 -0700
@@ -29,4 +29,4 @@
public void foo() {
sendNotification(new TestNotification("test", this, count++));
}
-}
\ No newline at end of file
+}
--- a/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Server/SteMBean.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/com/sun/jmx/remote/NotificationMarshalVersions/Server/SteMBean.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,4 +23,4 @@
public interface SteMBean {
public void foo();
-}
\ No newline at end of file
+}
--- a/jdk/test/com/sun/security/auth/module/LdapLoginModule/CheckConfigs.policy Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/com/sun/security/auth/module/LdapLoginModule/CheckConfigs.policy Tue Sep 08 14:40:44 2015 -0700
@@ -7,5 +7,3 @@
//permission java.net.SocketPermission "*:636", "connect";
//permission javax.security.auth.AuthPermission "modifyPrincipals";
};
-
-
--- a/jdk/test/java/awt/Component/DimensionEncapsulation/DimensionEncapsulation.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/Component/DimensionEncapsulation/DimensionEncapsulation.java Tue Sep 08 14:40:44 2015 -0700
@@ -212,4 +212,4 @@
throw new RuntimeException(e);
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/awt/Component/InsetsEncapsulation/InsetsEncapsulation.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/Component/InsetsEncapsulation/InsetsEncapsulation.java Tue Sep 08 14:40:44 2015 -0700
@@ -163,4 +163,4 @@
throw new RuntimeException(e);
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/awt/Component/SetEnabledPerformance/SetEnabledPerformance.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/Component/SetEnabledPerformance/SetEnabledPerformance.java Tue Sep 08 14:40:44 2015 -0700
@@ -69,4 +69,4 @@
}
});
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/awt/Cursor/MultiResolutionCursorTest/MultiResolutionCursorTest.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/Cursor/MultiResolutionCursorTest/MultiResolutionCursorTest.html Tue Sep 08 14:40:44 2015 -0700
@@ -29,4 +29,4 @@
<applet CODE="MultiResolutionCursorTest.class" WIDTH=300 HEIGHT=100></applet>
<p> See the dialog box (usually in upper left corner) for instructions</p>
</body>
-</html>
\ No newline at end of file
+</html>
--- a/jdk/test/java/awt/FileDialog/ModalFocus/FileDialogModalFocusTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/FileDialog/ModalFocus/FileDialogModalFocusTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -134,4 +134,4 @@
throw new RuntimeException("file chooser is underneath");
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/awt/Focus/6981400/Test3.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/Focus/6981400/Test3.java Tue Sep 08 14:40:44 2015 -0700
@@ -135,5 +135,3 @@
}
}
}
-
-
--- a/jdk/test/java/awt/FontClass/LCDScale.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/FontClass/LCDScale.java Tue Sep 08 14:40:44 2015 -0700
@@ -79,5 +79,3 @@
}
}
}
-
-
--- a/jdk/test/java/awt/Frame/FramesGC/FramesGC.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/Frame/FramesGC/FramesGC.java Tue Sep 08 14:40:44 2015 -0700
@@ -156,4 +156,4 @@
refs.add(new PhantomReference<Frame>(frame, que));
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/awt/Frame/MaximizedToUnmaximized/MaximizedToUnmaximized.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/Frame/MaximizedToUnmaximized/MaximizedToUnmaximized.java Tue Sep 08 14:40:44 2015 -0700
@@ -76,4 +76,4 @@
frame.dispose();
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/awt/MenuBar/RemoveHelpMenu/RemoveHelpMenu.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/MenuBar/RemoveHelpMenu/RemoveHelpMenu.java Tue Sep 08 14:40:44 2015 -0700
@@ -129,4 +129,4 @@
checkMenuCount(menuBar, 0);
checkHelpMenu(helpMenu, false);
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/awt/Mixing/JButtonInGlassPane.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/Mixing/JButtonInGlassPane.java Tue Sep 08 14:40:44 2015 -0700
@@ -426,5 +426,3 @@
}
}// TestDialog class
-
-
--- a/jdk/test/java/awt/Mixing/LWComboBox.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/Mixing/LWComboBox.java Tue Sep 08 14:40:44 2015 -0700
@@ -421,5 +421,3 @@
}
}// TestDialog class
-
-
--- a/jdk/test/java/awt/Mixing/MixingInHwPanel.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/Mixing/MixingInHwPanel.java Tue Sep 08 14:40:44 2015 -0700
@@ -424,5 +424,3 @@
}
}// TestDialog class
-
-
--- a/jdk/test/java/awt/Mixing/MixingOnShrinkingHWButton.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/Mixing/MixingOnShrinkingHWButton.java Tue Sep 08 14:40:44 2015 -0700
@@ -425,5 +425,3 @@
}
}// TestDialog class
-
-
--- a/jdk/test/java/awt/Mixing/NonOpaqueInternalFrame.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/Mixing/NonOpaqueInternalFrame.java Tue Sep 08 14:40:44 2015 -0700
@@ -430,5 +430,3 @@
}
}// TestDialog class
-
-
--- a/jdk/test/java/awt/Mouse/MouseDragEvent/MouseDraggedTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/Mouse/MouseDragEvent/MouseDraggedTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -100,4 +100,4 @@
frame.add(panel, BorderLayout.CENTER);
frame.setVisible(true);
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/awt/MouseInfo/JContainerMousePositionTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/MouseInfo/JContainerMousePositionTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -144,5 +144,3 @@
frame1.setVisible(true);
}
}
-
-
--- a/jdk/test/java/awt/Robot/RobotWheelTest/RobotWheelTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/Robot/RobotWheelTest/RobotWheelTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -80,4 +80,4 @@
}
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/awt/ScrollPane/bug8077409Test.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/ScrollPane/bug8077409Test.java Tue Sep 08 14:40:44 2015 -0700
@@ -112,4 +112,4 @@
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -148,4 +148,4 @@
"JPopupMenu shown and menu item selected using keyboard");
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/awt/Window/AlwaysOnTop/SyncAlwaysOnTopFieldTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/Window/AlwaysOnTop/SyncAlwaysOnTopFieldTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -59,4 +59,4 @@
window.setVisible(true);
return window;
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/awt/applet/Applet/AppletFlipBuffer.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/applet/Applet/AppletFlipBuffer.java Tue Sep 08 14:40:44 2015 -0700
@@ -52,4 +52,4 @@
frame.dispose();
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/awt/appletviewer/IOExceptionIfEncodedURLTest/test.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/appletviewer/IOExceptionIfEncodedURLTest/test.html Tue Sep 08 14:40:44 2015 -0700
@@ -41,4 +41,4 @@
<APPLET CODE="IOExceptionIfEncodedURLTest.class" WIDTH=200 HEIGHT=200></APPLET>
</body>
-</html>
\ No newline at end of file
+</html>
--- a/jdk/test/java/awt/datatransfer/ClipboardInterVMTest/ClipboardInterVMTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/datatransfer/ClipboardInterVMTest/ClipboardInterVMTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -168,4 +168,4 @@
}
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/awt/datatransfer/DataFlavor/XJavaUrlDataFlavorTest/XJavaUrlDataFlavorTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/datatransfer/DataFlavor/XJavaUrlDataFlavorTest/XJavaUrlDataFlavorTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -342,4 +342,4 @@
}
}
-}// TestDialog class
\ No newline at end of file
+}// TestDialog class
--- a/jdk/test/java/awt/datatransfer/MissedHtmlAndRtfBug/MyTransferable.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/datatransfer/MissedHtmlAndRtfBug/MyTransferable.java Tue Sep 08 14:40:44 2015 -0700
@@ -59,4 +59,4 @@
throw new UnsupportedFlavorException(flavor);
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/awt/event/MouseEvent/CTORRestrictions/CTORRestrictions_Disable.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/event/MouseEvent/CTORRestrictions/CTORRestrictions_Disable.java Tue Sep 08 14:40:44 2015 -0700
@@ -120,5 +120,3 @@
frame.dispatchEvent( ( AWTEvent )meOld );
}
}
-
-
--- a/jdk/test/java/awt/im/4490692/bug4490692.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/im/4490692/bug4490692.html Tue Sep 08 14:40:44 2015 -0700
@@ -59,5 +59,3 @@
<APPLET CODE="bug4490692.class" WIDTH=0 HEIGHT=0></APPLET>
</body>
</html>
-
-
--- a/jdk/test/java/awt/im/4959409/bug4959409.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/awt/im/4959409/bug4959409.html Tue Sep 08 14:40:44 2015 -0700
@@ -45,5 +45,3 @@
<APPLET CODE="bug4959409.class" WIDTH=0 HEIGHT=0></APPLET>
</body>
</html>
-
-
--- a/jdk/test/java/beans/README Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/beans/README Tue Sep 08 14:40:44 2015 -0700
@@ -73,4 +73,4 @@
If this object is not null it will be encoded and decoded.
Also the object updating will be tested in this case.
The test() method has a boolean parameter,
-which indicates that the test should be started in secure context.
\ No newline at end of file
+which indicates that the test should be started in secure context.
--- a/jdk/test/java/beans/SimpleBeanInfo/LoadingStandardIcons/java.policy Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/beans/SimpleBeanInfo/LoadingStandardIcons/java.policy Tue Sep 08 14:40:44 2015 -0700
@@ -1,1 +1,1 @@
-;
\ No newline at end of file
+;
--- a/jdk/test/java/io/Serializable/evolution/AddedSuperClass/README Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/io/Serializable/evolution/AddedSuperClass/README Tue Sep 08 14:40:44 2015 -0700
@@ -12,6 +12,3 @@
rm A.class AddedSuperClass.class
javac ReadAddedSuperClass2.java
java ReadAddedSuperClass2
-
-
-
--- a/jdk/test/java/lang/ClassLoader/getdotresource.sh Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/lang/ClassLoader/getdotresource.sh Tue Sep 08 14:40:44 2015 -0700
@@ -44,5 +44,3 @@
# now start the test
${TESTJAVA}/bin/java ${TESTVMOPTS} -cp ${TESTSRC}${FS}resource.jar${PS}${TESTCLASSES} GetDotResource
-
-
--- a/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest2.sh Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest2.sh Tue Sep 08 14:40:44 2015 -0700
@@ -69,5 +69,3 @@
then echo "$failures test(s) failed";
else echo "All test(s) passed"; fi
exit $failures
-
-
--- a/jdk/test/java/net/SocketPermission/policy Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/net/SocketPermission/policy Tue Sep 08 14:40:44 2015 -0700
@@ -1,3 +1,3 @@
grant {
permission java.security.AllPermission;
-};
\ No newline at end of file
+};
--- a/jdk/test/java/nio/channels/SocketChannel/Open.sh Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/nio/channels/SocketChannel/Open.sh Tue Sep 08 14:40:44 2015 -0700
@@ -33,6 +33,3 @@
* )
echo "unrecognized system: $OS" ;;
esac
-
-
-
--- a/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/README Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/README Tue Sep 08 14:40:44 2015 -0700
@@ -31,5 +31,3 @@
(c) Execute the make script :-
Solaris: gnumake all
Linux: gmake all
-
-
--- a/jdk/test/java/nio/file/Files/StreamLinesTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/nio/file/Files/StreamLinesTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -138,18 +138,25 @@
StandardCharsets.ISO_8859_1,
StandardCharsets.UTF_16);
String[] lines = {"", "A", "AB", "ABC", "ABCD"};
- int[] linesSizes = {1, 2, 3, 4, 16, 256, 1024};
+ int[] linesSizes = {0, 1, 2, 3, 4, 16, 256, 1024};
for (Charset charset : charsets) {
- for (String line : lines) {
- for (int linesSize : linesSizes) {
- for (LineSeparator ls : EnumSet.complementOf(EnumSet.of(LineSeparator.NONE))) {
- String description = String.format("%d lines of \"%s\" with separator %s", linesSize, line, ls);
- l.add(of(description,
- i -> line,
- i -> ls,
- linesSize, charset));
+ for (int linesSize : linesSizes) {
+ if (linesSize > 0) {
+ for (String line : lines) {
+ for (LineSeparator ls : EnumSet.complementOf(EnumSet.of(LineSeparator.NONE))) {
+ String description = String.format("%d lines of \"%s\" with separator %s", linesSize, line, ls);
+ l.add(of(description,
+ i -> line,
+ i -> ls,
+ linesSize, charset));
+ }
}
+ } else {
+ l.add(of("Empty file: 0 lines",
+ i -> "",
+ i -> LineSeparator.NONE,
+ 0, charset));
}
}
}
--- a/jdk/test/java/rmi/registry/readTest/readTest.sh Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/rmi/registry/readTest/readTest.sh Tue Sep 08 14:40:44 2015 -0700
@@ -125,5 +125,3 @@
fi
rm -rf OUT.TXT ${RMIREG_OUT} rmi_tmp
exit ${exitCode}
-
-
--- a/jdk/test/java/security/KeyStore/PKCS12/README Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/security/KeyStore/PKCS12/README Tue Sep 08 14:40:44 2015 -0700
@@ -25,4 +25,4 @@
3. Import certificate
<JAVA-HOME>/bin/keytool -import -alias pkcs12test -keystore ks-pkcs.data
--storepass storepass -file pkcs12testCA.cer.data
\ No newline at end of file
+-storepass storepass -file pkcs12testCA.cer.data
--- a/jdk/test/java/security/SignedObject/Copy.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/security/SignedObject/Copy.java Tue Sep 08 14:40:44 2015 -0700
@@ -119,5 +119,3 @@
}
}
}
-
-
--- a/jdk/test/java/util/AbstractCollection/ToArrayTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/util/AbstractCollection/ToArrayTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -211,5 +211,3 @@
else {System.out.println(x + " not equal to " + y); fail(); }
}
}
-
-
--- a/jdk/test/java/util/Arrays/SetAllTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/util/Arrays/SetAllTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -278,4 +278,4 @@
// expected
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/util/Locale/bug4123285.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/util/Locale/bug4123285.html Tue Sep 08 14:40:44 2015 -0700
@@ -1,1 +1,1 @@
-<APPLET CODE="bug4123285.class" CODEBASE="./" WIDTH="250" HEIGHT="325" ALIGN="TOP"></APPLET>
\ No newline at end of file
+<APPLET CODE="bug4123285.class" CODEBASE="./" WIDTH="250" HEIGHT="325" ALIGN="TOP"></APPLET>
--- a/jdk/test/java/util/concurrent/CompletableFuture/ThenComposeExceptionTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/util/concurrent/CompletableFuture/ThenComposeExceptionTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -120,4 +120,4 @@
Assert.assertTrue(eOnWhenComplete.get() instanceof CompletionException,
"Incorrect exception passed to whenComplete: " + eOnWhenComplete.get());
}
-}
\ No newline at end of file
+}
--- a/jdk/test/java/util/logging/LogManager/Configuration/TestConfigurationLock.properties Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/util/logging/LogManager/Configuration/TestConfigurationLock.properties Tue Sep 08 14:40:44 2015 -0700
@@ -18,5 +18,3 @@
foo.bar.l10.level = INFO
foo.bar.l100.level = INFO
foo.bar.l1000.level = INFO
-
-
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/DefaultMethodStreams.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/java/util/stream/bootlib/java/util/stream/DefaultMethodStreams.java Tue Sep 08 14:40:44 2015 -0700
@@ -981,4 +981,4 @@
s.close();
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/javax/crypto/SecretKeyFactory/PBKDF2TranslateTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/crypto/SecretKeyFactory/PBKDF2TranslateTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -267,4 +267,4 @@
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/javax/imageio/plugins/shared/CanWriteSequence.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/imageio/plugins/shared/CanWriteSequence.java Tue Sep 08 14:40:44 2015 -0700
@@ -75,4 +75,4 @@
writer.dispose();
ios.close();
}
-}
\ No newline at end of file
+}
--- a/jdk/test/javax/management/MustBeValidMBeanInfo/logging.properties Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/management/MustBeValidMBeanInfo/logging.properties Tue Sep 08 14:40:44 2015 -0700
@@ -11,4 +11,4 @@
java.util.logging.ConsoleHandler.level = FINEST
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
-javax.management.misc.level = FINEST
\ No newline at end of file
+javax.management.misc.level = FINEST
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/ObjectName/CompressedStorageTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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 8041565
+ * @summary Tests the limits imposed on the domain name part of an
+ * ObjectName instance
+ * @author Jaroslav Bachorik
+ * @modules java.management
+ * @run main CompressedStorageTest
+ */
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.function.Consumer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+public class CompressedStorageTest {
+ private static Method setDomainLengthM;
+ private static Field compressedStorageFld;
+
+ private static int DOMAIN_PATTERN;
+ private static int PROPLIST_PATTERN;
+ private static int PROPVAL_PATTERN;
+
+ private static Method setDomainPattern;
+ private static Method setPropertyListPattern;
+ private static Method setPropertyValuePattern;
+
+
+ static {
+ try {
+ Class<?> clz = ObjectName.class;
+ setDomainLengthM = clz.getDeclaredMethod("setDomainLength", int.class);
+ setDomainLengthM.setAccessible(true);
+
+ compressedStorageFld = clz.getDeclaredField("_compressed_storage");
+ compressedStorageFld.setAccessible(true);
+
+ setDomainPattern = clz.getDeclaredMethod("setDomainPattern", boolean.class);
+ setDomainPattern.setAccessible(true);
+ setPropertyListPattern = clz.getDeclaredMethod("setPropertyListPattern", boolean.class);
+ setPropertyListPattern.setAccessible(true);
+ setPropertyValuePattern = clz.getDeclaredMethod("setPropertyValuePattern", boolean.class);
+ setPropertyValuePattern.setAccessible(true);
+
+ DOMAIN_PATTERN = getStaticIntFld("DOMAIN_PATTERN");
+ PROPLIST_PATTERN = getStaticIntFld("PROPLIST_PATTERN");
+ PROPVAL_PATTERN = getStaticIntFld("PROPVAL_PATTERN");
+
+ } catch (Exception e) {
+ throw new Error(e);
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ testZeroLength();
+ testNegativeLength();
+ testMaxLength();
+
+ testSetDomainPattern();
+ testSetPropertyListPattern();
+ testSetPropertyValuePattern();
+ }
+
+ private static ObjectName getObjectName()
+ throws MalformedObjectNameException {
+ return new ObjectName("domain", "key", "value");
+ }
+
+ /**
+ * Test for accepting 0 being passed as argument to
+ * {@linkplain ObjectName#setDomainLength(int)}.
+ *
+ */
+ private static void testZeroLength() throws Exception {
+ setDomainNameLength(0);
+ }
+
+ /**
+ * Test for rejecting negative value being passed as argument to
+ * {@linkplain ObjectName#setDomainLength(int)}.
+ */
+ private static void testNegativeLength() throws Exception {
+ try {
+ setDomainNameLength(-1);
+ } catch (MalformedObjectNameException e) {
+ return;
+ }
+ fail("Allowing negative domain name length");
+ }
+
+ /**
+ * Test for rejecting value exceeding the maximum allowed length
+ * being passed as argument to {@linkplain ObjectName#setDomainLength(int)}.
+ */
+ private static void testMaxLength() throws Exception {
+ try {
+ setDomainNameLength(Integer.MAX_VALUE / 4 + 1);
+ } catch (MalformedObjectNameException e) {
+ return;
+ }
+ fail("Maximum domain name length is not respected");
+ }
+
+ /**
+ * Tests that calling {@linkplain ObjectName#setDomainPattern(boolean)}
+ * results in setting correct bits in {@linkplain ObjectName#_compressed_storage}.
+ */
+ private static void testSetDomainPattern() throws Exception {
+ ObjectName on = getObjectName();
+
+ checkMask(DOMAIN_PATTERN, setDomainPattern, on);
+ }
+
+ /**
+ * Tests that calling {@linkplain ObjectName#setPropertyListPattern(boolean)}
+ * results in setting correct bits in {@linkplain ObjectName#_compressed_storage}.
+ */
+ private static void testSetPropertyListPattern() throws Exception {
+ ObjectName on = getObjectName();
+
+ checkMask(PROPLIST_PATTERN, setPropertyListPattern, on);
+ }
+
+ /**
+ * Tests that calling {@linkplain ObjectName#setPropertyValuePattern(boolean)}
+ * results in setting correct bits in {@linkplain ObjectName#_compressed_storage}.
+ */
+ private static void testSetPropertyValuePattern() throws Exception {
+ ObjectName on = getObjectName();
+
+ checkMask(PROPVAL_PATTERN, setPropertyValuePattern, on);
+ }
+
+ /**
+ * Helper method to call {@linkplain ObjectName#setDomainLength(int)}
+ * method via reflection.
+ * @param len The domain name length
+ * @throws MalformedObjectNameException Propagated from
+ * {@linkplain ObjectName#setDomainLength(int)} invocation.
+ */
+ private static void setDomainNameLength(int len)
+ throws MalformedObjectNameException {
+ try {
+ setDomainLengthM.invoke(getObjectName(), len);
+ } catch (InvocationTargetException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof MalformedObjectNameException) {
+ throw (MalformedObjectNameException)cause;
+ }
+ throw new Error(cause);
+ } catch (IllegalAccessException | IllegalArgumentException e) {
+ throw new Error(e);
+ }
+ }
+
+ /**
+ * Helper method to assert that a particular boolean setter affects only
+ * a particular bit in the {@linkplain ObjectName#_compressed_storage} field.
+ * @param mask bitmask for storing the boolean value
+ * @param setter setter method reference
+ * @param on {@linkplain ObjectName} instance
+ */
+ private static void checkMask(int mask, Method setter, ObjectName on)
+ throws Exception {
+ int valBefore = compressedStorageFld.getInt(on);
+ setter.invoke(on, true);
+ int valAfter = compressedStorageFld.getInt(on);
+
+ checkMask(mask, valAfter ^ valBefore);
+
+ valBefore = valAfter;
+ setter.invoke(on, false);
+ valAfter = compressedStorageFld.getInt(on);
+
+ checkMask(mask, valAfter ^ valBefore);
+ }
+
+ /**
+ * Compare the changed bits with the given mask.
+ * @param mask bitmask
+ * @param val the changed bits; may be 0 if there was no change
+ */
+ private static void checkMask(int mask, int val) {
+ if (val != 0 && val != mask) {
+ fail("Invalid mask: expecting '" +
+ Integer.toBinaryString(mask) + "' , received '" +
+ Integer.toBinaryString(val) + "'");
+ }
+ }
+
+ /**
+ * Helper method to obtain the value of a static field via reflection.
+ * @param name static field name
+ * @return static field value
+ */
+ private static int getStaticIntFld(String name) throws Exception {
+ Field fld = ObjectName.class.getDeclaredField(name);
+ fld.setAccessible(true);
+
+ return fld.getInt(null);
+ }
+
+ private static void fail(String msg) {
+ throw new Error(msg);
+ }
+}
--- a/jdk/test/javax/management/modelmbean/SimpleModelMBean/logging.properties Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/management/modelmbean/SimpleModelMBean/logging.properties Tue Sep 08 14:40:44 2015 -0700
@@ -11,4 +11,4 @@
java.util.logging.ConsoleHandler.level = FINEST
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
-javax.management.misc.level = FINEST
\ No newline at end of file
+javax.management.misc.level = FINEST
--- a/jdk/test/javax/security/auth/Subject/doAs/policy.expect.ace Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/security/auth/Subject/doAs/policy.expect.ace Tue Sep 08 14:40:44 2015 -0700
@@ -24,4 +24,4 @@
grant codeBase "file:ReadPropertyNegativeAction.jar"
Principal javax.security.auth.x500.X500Principal "cn=Duke" {
permission java.security.AllPermission;
-};
\ No newline at end of file
+};
--- a/jdk/test/javax/security/auth/Subject/doAs/policy.one.principal Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/security/auth/Subject/doAs/policy.one.principal Tue Sep 08 14:40:44 2015 -0700
@@ -33,4 +33,4 @@
permission javax.security.auth.AuthPermission "getSubject";
permission javax.security.auth.AuthPermission "doAs";
permission java.util.PropertyPermission "java.class.path", "read";
-};
\ No newline at end of file
+};
--- a/jdk/test/javax/security/auth/Subject/doAs/policy.two.principals Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/security/auth/Subject/doAs/policy.two.principals Tue Sep 08 14:40:44 2015 -0700
@@ -34,4 +34,4 @@
permission javax.security.auth.AuthPermission "getSubject";
permission javax.security.auth.AuthPermission "doAs";
permission java.util.PropertyPermission "java.class.path", "read";
-};
\ No newline at end of file
+};
--- a/jdk/test/javax/security/auth/login/LoginContext/shared.config Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/security/auth/login/LoginContext/shared.config Tue Sep 08 14:40:44 2015 -0700
@@ -1,4 +1,4 @@
SharedState {
SharedState$FirstModule required;
SharedState$SecondModule required;
-};
\ No newline at end of file
+};
--- a/jdk/test/javax/sound/midi/Gervill/ModelStandardIndexedDirector/ModelStandardIndexedDirectorTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/sound/midi/Gervill/ModelStandardIndexedDirector/ModelStandardIndexedDirectorTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -184,5 +184,3 @@
}
}
-
-
--- a/jdk/test/javax/swing/JColorChooser/8065098/bug8065098.html Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/swing/JColorChooser/8065098/bug8065098.html Tue Sep 08 14:40:44 2015 -0700
@@ -37,4 +37,4 @@
<applet width="500" height="1" code="bug8065098.class">
</applet>
</body>
-</html>
\ No newline at end of file
+</html>
--- a/jdk/test/javax/swing/JFileChooser/8062561/security2.policy Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/swing/JFileChooser/8062561/security2.policy Tue Sep 08 14:40:44 2015 -0700
@@ -1,1 +1,1 @@
-// Autogenerated file
\ No newline at end of file
+// Autogenerated file
--- a/jdk/test/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.java Tue Sep 08 14:40:44 2015 -0700
@@ -82,4 +82,4 @@
return "CustomFileFilter";
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/javax/swing/JMenu/8072900/WrongSelectionOnMouseOver.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/swing/JMenu/8072900/WrongSelectionOnMouseOver.java Tue Sep 08 14:40:44 2015 -0700
@@ -195,4 +195,4 @@
}
System.out.println("Test passed");
}
-}
\ No newline at end of file
+}
--- a/jdk/test/javax/swing/JMenuBar/MisplacedBorder/MisplacedBorder.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/swing/JMenuBar/MisplacedBorder/MisplacedBorder.java Tue Sep 08 14:40:44 2015 -0700
@@ -132,4 +132,4 @@
throw new RuntimeException(e);
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/javax/swing/JOptionPane/8081019/bug8081019.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/swing/JOptionPane/8081019/bug8081019.java Tue Sep 08 14:40:44 2015 -0700
@@ -103,4 +103,4 @@
throw new RuntimeException("Exception in the output!");
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/javax/swing/JTextArea/4697612/bug4697612.txt Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/swing/JTextArea/4697612/bug4697612.txt Tue Sep 08 14:40:44 2015 -0700
@@ -219,5 +219,3 @@
Copyright 2003 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
California 95054, U.S.A. All rights reserved.
-
-
--- a/jdk/test/javax/swing/JTree/8072676/TreeClipTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/swing/JTree/8072676/TreeClipTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -94,4 +94,4 @@
System.out.println("Passed.");
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/javax/swing/JTree/DnD/LastNodeLowerHalfDrop.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/swing/JTree/DnD/LastNodeLowerHalfDrop.java Tue Sep 08 14:40:44 2015 -0700
@@ -381,4 +381,4 @@
return nodesFlavor.equals(flavor);
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/javax/swing/UIDefaults/7180976/Pending.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/swing/UIDefaults/7180976/Pending.java Tue Sep 08 14:40:44 2015 -0700
@@ -47,4 +47,4 @@
UIManager.get("foobar");
passed = true;
}
-}
\ No newline at end of file
+}
--- a/jdk/test/javax/swing/plaf/basic/BasicLabelUI/bug7172652.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/swing/plaf/basic/BasicLabelUI/bug7172652.java Tue Sep 08 14:40:44 2015 -0700
@@ -169,4 +169,4 @@
frame.setVisible(true);
}
-}
\ No newline at end of file
+}
--- a/jdk/test/javax/swing/text/View/8015853/bug8015853.txt Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/swing/text/View/8015853/bug8015853.txt Tue Sep 08 14:40:44 2015 -0700
@@ -64,4 +64,4 @@
frame.add(editorPane);
frame.setVisible(<b>true</b>);
}
-}
\ No newline at end of file
+}
--- a/jdk/test/javax/swing/text/html/8005391/bug8005391.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/swing/text/html/8005391/bug8005391.java Tue Sep 08 14:40:44 2015 -0700
@@ -58,4 +58,4 @@
}
}
}
-}
\ No newline at end of file
+}
--- a/jdk/test/javax/swing/text/html/HTMLDocument/8058120/bug8058120.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/swing/text/html/HTMLDocument/8058120/bug8058120.java Tue Sep 08 14:40:44 2015 -0700
@@ -109,5 +109,3 @@
frame.setVisible(true);
}
}
-
-
--- a/jdk/test/javax/xml/bind/xjc/8032884/optional-property-schema.xsd Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/xml/bind/xjc/8032884/optional-property-schema.xsd Tue Sep 08 14:40:44 2015 -0700
@@ -11,4 +11,4 @@
<xs:element name="foo" type="xs:int" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
-</xs:schema>
\ No newline at end of file
+</xs:schema>
--- a/jdk/test/javax/xml/jaxp/testng/validation/jdk8036951/idc.xml Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/xml/jaxp/testng/validation/jdk8036951/idc.xml Tue Sep 08 14:40:44 2015 -0700
@@ -4,4 +4,4 @@
<item uniqueAttr="ONE">2</item>
<item uniqueAttr="TWO">2</item>
<itemRef>3</itemRef>
-</itemList>
\ No newline at end of file
+</itemList>
--- a/jdk/test/javax/xml/jaxp/testng/validation/jdk8036951/idc.xsd Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/xml/jaxp/testng/validation/jdk8036951/idc.xsd Tue Sep 08 14:40:44 2015 -0700
@@ -38,4 +38,4 @@
</xsd:simpleContent>
</xsd:complexType>
-</xsd:schema>
\ No newline at end of file
+</xsd:schema>
--- a/jdk/test/javax/xml/jaxp/testng/validation/jdk8036951/simpleType.xml Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/xml/jaxp/testng/validation/jdk8036951/simpleType.xml Tue Sep 08 14:40:44 2015 -0700
@@ -1,2 +1,2 @@
<?xml version="1.0"?>
-<S>-12345</S>
\ No newline at end of file
+<S>-12345</S>
--- a/jdk/test/javax/xml/jaxp/testng/validation/jdk8036951/xerces1128_1.xml Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/xml/jaxp/testng/validation/jdk8036951/xerces1128_1.xml Tue Sep 08 14:40:44 2015 -0700
@@ -2,4 +2,4 @@
<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<B />
<C xsi:type="X" />
-</A>
\ No newline at end of file
+</A>
--- a/jdk/test/javax/xml/jaxp/testng/validation/jdk8036951/xerces1128_2.xml Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/xml/jaxp/testng/validation/jdk8036951/xerces1128_2.xml Tue Sep 08 14:40:44 2015 -0700
@@ -2,4 +2,4 @@
<A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<B xsi:type="X" />
<C />
-</A>
\ No newline at end of file
+</A>
--- a/jdk/test/javax/xml/jaxp/testng/validation/jdk8037819/unparsedEntity.dtd Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/xml/jaxp/testng/validation/jdk8037819/unparsedEntity.dtd Tue Sep 08 14:40:44 2015 -0700
@@ -1,2 +1,2 @@
<!NOTATION myNotation SYSTEM "somethingElse" >
-<!ENTITY myUnparsedEntity SYSTEM "something" NDATA myNotation >
\ No newline at end of file
+<!ENTITY myUnparsedEntity SYSTEM "something" NDATA myNotation >
--- a/jdk/test/javax/xml/jaxp/transform/8004476/tokenize.xml Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/javax/xml/jaxp/transform/8004476/tokenize.xml Tue Sep 08 14:40:44 2015 -0700
@@ -4,4 +4,4 @@
<b>Is this EXSLT? No. no</b>
<c>Is this EXSLT? No. no</c>
</a>
-</html>
\ No newline at end of file
+</html>
--- a/jdk/test/sun/jvmstat/testlibrary/utils.sh Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/jvmstat/testlibrary/utils.sh Tue Sep 08 14:40:44 2015 -0700
@@ -221,5 +221,3 @@
fi
echo "${port1}"
}
-
-
--- a/jdk/test/sun/management/jmxremote/bootstrap/PasswordFilePermissionTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/management/jmxremote/bootstrap/PasswordFilePermissionTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -57,5 +57,3 @@
}
}
-
-
--- a/jdk/test/sun/management/jmxremote/bootstrap/SSLConfigFilePermissionTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/management/jmxremote/bootstrap/SSLConfigFilePermissionTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -61,5 +61,3 @@
test.runTest(args);
}
}
-
-
--- a/jdk/test/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -186,4 +186,4 @@
private Properties getCounters() throws IOException, InterruptedException {
return jcmd.perfCounters("sun\\.management\\.JMXConnectorServer\\..*");
}
-}
\ No newline at end of file
+}
--- a/jdk/test/sun/management/jmxremote/startstop/REMOTE_TESTING.txt Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/management/jmxremote/startstop/REMOTE_TESTING.txt Tue Sep 08 14:40:44 2015 -0700
@@ -15,5 +15,3 @@
6. connect jconsole to host2:50234
Make sure jconsole works
Make sure only host2.50234 and host2.50235 appears in tcpdump output.
-
-
--- a/jdk/test/sun/management/windows/README Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/management/windows/README Tue Sep 08 14:40:44 2015 -0700
@@ -26,5 +26,3 @@
Note that a 32-bit version of revokeall.exe is checked into SCCS
- this 32-bit application is also used when running on 64-bit
versions of Windows (AMD64 and IA64).
-
-
--- a/jdk/test/sun/net/www/http/HttpClient/IsKeepingAlive.policy Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/net/www/http/HttpClient/IsKeepingAlive.policy Tue Sep 08 14:40:44 2015 -0700
@@ -45,5 +45,3 @@
permission java.util.PropertyPermission "java.vm.vendor", "read";
permission java.util.PropertyPermission "java.vm.name", "read";
};
-
-
--- a/jdk/test/sun/net/www/http/HttpClient/OpenServer.policy Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/net/www/http/HttpClient/OpenServer.policy Tue Sep 08 14:40:44 2015 -0700
@@ -45,5 +45,3 @@
permission java.util.PropertyPermission "java.vm.vendor", "read";
permission java.util.PropertyPermission "java.vm.name", "read";
};
-
-
--- a/jdk/test/sun/net/www/protocol/http/spnegoTest Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/net/www/protocol/http/spnegoTest Tue Sep 08 14:40:44 2015 -0700
@@ -205,4 +205,4 @@
rm err.log
rm out.log
-exit 0
\ No newline at end of file
+exit 0
--- a/jdk/test/sun/security/ec/SignatureOffsets.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/security/ec/SignatureOffsets.java Tue Sep 08 14:40:44 2015 -0700
@@ -49,4 +49,4 @@
InvalidKeyException, SignatureException {
Offsets.main(args);
}
-}
\ No newline at end of file
+}
--- a/jdk/test/sun/security/krb5/IPv6.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/security/krb5/IPv6.java Tue Sep 08 14:40:44 2015 -0700
@@ -127,5 +127,3 @@
}
}
}
-
-
--- a/jdk/test/sun/security/mscapi/KeytoolChangeAlias.sh Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/security/mscapi/KeytoolChangeAlias.sh Tue Sep 08 14:40:44 2015 -0700
@@ -132,6 +132,3 @@
exit 0
;;
esac
-
-
-
--- a/jdk/test/sun/security/mscapi/SignatureOffsets.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/security/mscapi/SignatureOffsets.java Tue Sep 08 14:40:44 2015 -0700
@@ -50,4 +50,4 @@
InvalidKeyException, SignatureException {
Offsets.main(args);
}
-}
\ No newline at end of file
+}
--- a/jdk/test/sun/security/pkcs11/Provider/Absolute.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/security/pkcs11/Provider/Absolute.java Tue Sep 08 14:40:44 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,40 +22,31 @@
*/
/**
* @test
- * @bug 7003952
+ * @bug 7003952 7191662
+ * @library ..
* @summary load DLLs and launch executables using fully qualified path
*/
import java.security.*;
-import java.lang.reflect.*;
public class Absolute {
public static void main(String[] args) throws Exception {
- Constructor cons;
- try {
- Class clazz = Class.forName("sun.security.pkcs11.SunPKCS11");
- cons = clazz.getConstructor(new Class[] {String.class});
- } catch (Exception ex) {
- System.out.println("Skipping test - no PKCS11 provider available");
- return;
- }
-
String config =
System.getProperty("test.src", ".") + "/Absolute.cfg";
try {
- Object obj = cons.newInstance(new Object[] {config});
- } catch (InvocationTargetException ite) {
- Throwable cause = ite.getCause();
- if (cause instanceof ProviderException) {
- Throwable cause2 = cause.getCause();
- if ((cause2 == null) ||
- !cause2.getMessage().startsWith(
- "Absolute path required for library value:")) {
- // rethrow
- throw (ProviderException) cause;
- }
- System.out.println("Caught expected Exception: \n" + cause2);
+ Provider p = PKCS11Test.getSunPKCS11(config);
+ if (p == null) {
+ System.out.println("Skipping test - no PKCS11 provider available");
+ }
+ } catch (InvalidParameterException ipe) {
+ Throwable ex = ipe.getCause();
+ if (ex.getMessage().indexOf(
+ "Absolute path required for library value:") != -1) {
+ System.out.println("Test Passed: expected exception thrown");
+ } else {
+ // rethrow
+ throw ipe;
}
}
}
--- a/jdk/test/sun/security/pkcs11/Provider/ConfigShortPath.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/security/pkcs11/Provider/ConfigShortPath.java Tue Sep 08 14:40:44 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,44 +33,52 @@
public class ConfigShortPath {
- private static final String[] configNames = {
- "csp.cfg", "cspPlus.cfg", "cspSpace.cfg", "cspQuotedPath.cfg"
+ private static final String[] winConfigNames = {
+ "csp.cfg", "cspSpace.cfg", "cspQuotedPath.cfg"
+ };
+ private static final String[] solConfigNames = {
+ "cspPlus.cfg"
};
public static void main(String[] args) throws Exception {
- Constructor cons = null;
- try {
- Class clazz = Class.forName("sun.security.pkcs11.SunPKCS11");
- cons = clazz.getConstructor(String.class);
- } catch (Exception ex) {
- System.out.println("Skipping test - no PKCS11 provider available");
- return;
+ Provider p = Security.getProvider("SunPKCS11");
+ if (p == null) {
+ // re-try w/ SunPKCS11-Solaris
+ p = Security.getProvider("SunPKCS11-Solaris");
+ if (p == null) {
+ System.out.println("Skipping test - no PKCS11 provider available");
+ return;
+ }
}
+
+ String osInfo = System.getProperty("os.name", "");
+ String[] configNames = (osInfo.contains("Windows")?
+ winConfigNames : solConfigNames);
+
String testSrc = System.getProperty("test.src", ".");
for (int i = 0; i < configNames.length; i++) {
String configFile = testSrc + File.separator + configNames[i];
System.out.println("Testing against " + configFile);
try {
- Object obj = cons.newInstance(configFile);
- } catch (InvocationTargetException ite) {
- Throwable cause = ite.getCause();
- System.out.println(cause);
- if (cause instanceof ProviderException) {
- while ((cause = cause.getCause()) != null) {
- System.out.println(cause);
- String causeMsg = cause.getMessage();
- // Indicate failure if due to parsing config
- if (causeMsg.indexOf("Unexpected") != -1) {
- throw (ProviderException) cause;
- }
+ p.configure(configFile);
+ } catch (InvalidParameterException ipe) {
+ ipe.printStackTrace();
+ Throwable cause = ipe.getCause();
+ // Indicate failure if due to parsing config
+ if (cause.getClass().getName().equals
+ ("sun.security.pkcs11.ConfigurationException")) {
+ // Error occurred during parsing
+ if (cause.getMessage().indexOf("Unexpected") != -1) {
+ throw (ProviderException) cause;
}
- // Consider the test passes if the exception is
- // thrown after parsing, i.e. due to the absolute
- // path requirement or the non-existent path.
- } else {
- // unexpected exception
- throw new RuntimeException("Unexpected Exception", cause);
+ }
+ } catch (ProviderException pe) {
+ pe.printStackTrace();
+ if (pe.getCause() instanceof IOException) {
+ // Thrown when the directory does not exist which is ok
+ System.out.println("Pass: config parsed ok");
+ continue;
}
}
}
--- a/jdk/test/sun/security/pkcs11/Provider/cspSpace.cfg Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/security/pkcs11/Provider/cspSpace.cfg Tue Sep 08 14:40:44 2015 -0700
@@ -1,5 +1,3 @@
showInfo = false
name = test
library = C:\pki DLL\x64\acpkcs211.dll
-
-
--- a/jdk/test/sun/security/provider/certpath/Extensions/OCSPNonceExtensionTests.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/security/provider/certpath/Extensions/OCSPNonceExtensionTests.java Tue Sep 08 14:40:44 2015 -0700
@@ -79,14 +79,11 @@
Map<String, TestCase> testList =
new LinkedHashMap<String, TestCase>() {{
put("CTOR Test (provide length)", testCtorByLength);
+ put("CTOR Test (provide nonce bytes)", testCtorByValue);
+ put("CTOR Test (set criticality forms)", testCtorCritForms);
put("CTOR Test (provide extension DER encoding)",
testCtorSuperByDerValue);
- put("Use set() call to provide random data", testResetValue);
- put("Test get() method", testGet);
- put("test set() method", testSet);
- put("Test getElements() method", testGetElements);
put("Test getName() method", testGetName);
- put("Test delete() method", testDelete);
}};
System.out.println("============ Tests ============");
@@ -179,6 +176,20 @@
Boolean pass = Boolean.FALSE;
String message = null;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+ // Try sending in a negative length
+ try {
+ Extension negLenNonce = new OCSPNonceExtension(-8);
+ throw new RuntimeException(
+ "Accepted a negative length nonce");
+ } catch (IllegalArgumentException iae) { }
+
+ // How about a zero length?
+ try {
+ Extension zeroLenNonce = new OCSPNonceExtension(0);
+ throw new RuntimeException("Accepted a zero length nonce");
+ } catch (IllegalArgumentException iae) { }
+
+ // Valid input to constructor
Extension nonceByLen = new OCSPNonceExtension(32);
// Verify overall encoded extension structure
@@ -216,6 +227,82 @@
}
};
+ public static final TestCase testCtorByValue = new TestCase() {
+ @Override
+ public Map.Entry<Boolean, String> runTest() {
+ Boolean pass = Boolean.FALSE;
+ String message = null;
+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+
+ // Try giving a null value for the nonce
+ try {
+ Extension nullNonce = new OCSPNonceExtension(null);
+ throw new RuntimeException("Accepted a null nonce");
+ } catch (NullPointerException npe) { }
+
+ // How about a zero-length byte array?
+ try {
+ Extension zeroLenNonce =
+ new OCSPNonceExtension(new byte[0]);
+ throw new RuntimeException("Accepted a zero length nonce");
+ } catch (IllegalArgumentException iae) { }
+
+ OCSPNonceExtension nonceByValue =
+ new OCSPNonceExtension(DEADBEEF_16);
+
+ // Verify overall encoded extension structure
+ nonceByValue.encode(baos);
+ verifyExtStructure(baos.toByteArray());
+
+ // Verify the name, elements, and data conform to
+ // expected values for this specific object.
+ boolean crit = nonceByValue.isCritical();
+ String oid = nonceByValue.getId();
+ byte[] nonceData = nonceByValue.getNonceValue();
+
+ if (crit) {
+ message = "Extension incorrectly marked critical";
+ } else if (!oid.equals(OCSP_NONCE_OID)) {
+ message = "Incorrect OID (Got " + oid + ", Expected " +
+ OCSP_NONCE_OID + ")";
+ } else if (!Arrays.equals(nonceData, DEADBEEF_16)) {
+ message = "Returned nonce value did not match input";
+ } else {
+ pass = Boolean.TRUE;
+ }
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ message = e.getClass().getName();
+ }
+
+ return new AbstractMap.SimpleEntry<>(pass, message);
+ }
+ };
+
+ public static final TestCase testCtorCritForms = new TestCase() {
+ @Override
+ public Map.Entry<Boolean, String> runTest() {
+ Boolean pass = Boolean.FALSE;
+ String message = null;
+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+ Extension nonceByLength = new OCSPNonceExtension(true, 32);
+ Extension nonceByValue =
+ new OCSPNonceExtension(true, DEADBEEF_16);
+ pass = nonceByLength.isCritical() && nonceByValue.isCritical();
+ if (!pass) {
+ message = "nonceByLength or nonceByValue was not marked " +
+ "critical as expected";
+ }
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ message = e.getClass().getName();
+ }
+
+ return new AbstractMap.SimpleEntry<>(pass, message);
+ }
+ };
+
+
public static final TestCase testCtorSuperByDerValue = new TestCase() {
@Override
public Map.Entry<Boolean, String> runTest() {
@@ -260,145 +347,6 @@
}
};
- public static final TestCase testResetValue = new TestCase() {
- @Override
- public Map.Entry<Boolean, String> runTest() {
- Boolean pass = Boolean.FALSE;
- String message = null;
- try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
- OCSPNonceExtension nonce = new OCSPNonceExtension(32);
-
- // Reset the nonce data to reflect 16 bytes of DEADBEEF
- nonce.set(OCSPNonceExtension.NONCE, (Object)DEADBEEF_16);
-
- // Verify overall encoded extension content
- nonce.encode(baos);
- dumpHexBytes(OCSP_NONCE_DB16);
- System.out.println();
- dumpHexBytes(baos.toByteArray());
-
- pass = Arrays.equals(baos.toByteArray(), OCSP_NONCE_DB16);
- } catch (Exception e) {
- e.printStackTrace(System.out);
- message = e.getClass().getName();
- }
-
- return new AbstractMap.SimpleEntry<>(pass, message);
- }
- };
-
- public static final TestCase testSet = new TestCase() {
- @Override
- public Map.Entry<Boolean, String> runTest() {
- Boolean pass = Boolean.FALSE;
- String message = null;
- try {
- OCSPNonceExtension nonceByLen = new OCSPNonceExtension(32);
-
- // Set the nonce data to 16 bytes of DEADBEEF
- nonceByLen.set(ELEMENT_NONCE, DEADBEEF_16);
- byte[] nonceData = (byte[])nonceByLen.get(ELEMENT_NONCE);
- if (!Arrays.equals(nonceData, DEADBEEF_16)) {
- throw new RuntimeException("Retuned nonce data does not " +
- "match expected result");
- }
-
- // Now try to set a value using an object that is not a byte
- // array
- int[] INT_DB_16 = {
- 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF
- };
- try {
- nonceByLen.set(ELEMENT_NONCE, INT_DB_16);
- throw new RuntimeException("Accepted get() for " +
- "unsupported element name");
- } catch (IOException ioe) { } // Expected result
-
- // And try setting a value using an unknown element name
- try {
- nonceByLen.set("FOO", DEADBEEF_16);
- throw new RuntimeException("Accepted get() for " +
- "unsupported element name");
- } catch (IOException ioe) { } // Expected result
-
- pass = Boolean.TRUE;
- } catch (Exception e) {
- e.printStackTrace(System.out);
- message = e.getClass().getName();
- }
-
- return new AbstractMap.SimpleEntry<>(pass, message);
- }
- };
-
- public static final TestCase testGet = new TestCase() {
- @Override
- public Map.Entry<Boolean, String> runTest() {
- Boolean pass = Boolean.FALSE;
- String message = null;
- try {
- OCSPNonceExtension nonceByLen = new OCSPNonceExtension(32);
-
- // Grab the nonce data by its correct element name
- byte[] nonceData = (byte[])nonceByLen.get(ELEMENT_NONCE);
- if (nonceData == null || nonceData.length != 32) {
- throw new RuntimeException("Unexpected return value from " +
- "get() method: either null or incorrect length");
- }
-
- // Now try to get any kind of data using an element name that
- // doesn't exist for this extension.
- try {
- nonceByLen.get("FOO");
- throw new RuntimeException("Accepted get() for " +
- "unsupported element name");
- } catch (IOException ioe) { } // Expected result
-
- pass = Boolean.TRUE;
- } catch (Exception e) {
- e.printStackTrace(System.out);
- message = e.getClass().getName();
- }
-
- return new AbstractMap.SimpleEntry<>(pass, message);
- }
- };
-
- public static final TestCase testGetElements = new TestCase() {
- @Override
- public Map.Entry<Boolean, String> runTest() {
- Boolean pass = Boolean.FALSE;
- String message = null;
- try {
- OCSPNonceExtension nonceByLen = new OCSPNonceExtension(32);
-
- int elementCount = 0;
- boolean foundElement = false;
-
- // There should be exactly one element and its name should
- // be "nonce"
- for (Enumeration<String> elements = nonceByLen.getElements();
- elements.hasMoreElements(); elementCount++) {
- if (elements.nextElement().equals(ELEMENT_NONCE)) {
- foundElement = true;
- }
- }
-
- if (!foundElement || elementCount != 1) {
- throw new RuntimeException("Unexpected or missing " +
- "Enumeration element");
- }
-
- pass = Boolean.TRUE;
- } catch (Exception e) {
- e.printStackTrace(System.out);
- message = e.getClass().getName();
- }
-
- return new AbstractMap.SimpleEntry<>(pass, message);
- }
- };
-
public static final TestCase testGetName = new TestCase() {
@Override
public Map.Entry<Boolean, String> runTest() {
@@ -415,44 +363,4 @@
return new AbstractMap.SimpleEntry<>(pass, message);
}
};
-
- public static final TestCase testDelete = new TestCase() {
- @Override
- public Map.Entry<Boolean, String> runTest() {
- Boolean pass = Boolean.FALSE;
- String message = null;
- try {
- OCSPNonceExtension nonceByLen = new OCSPNonceExtension(32);
-
- // First verify that there's data to begin with
- byte[] nonceData = (byte[])nonceByLen.get(ELEMENT_NONCE);
- if (nonceData == null || nonceData.length != 32) {
- throw new RuntimeException("Unexpected return value from " +
- "get() method: either null or incorrect length");
- }
-
- // Attempt to delete using an element name that doesn't exist
- // for this extension.
- try {
- nonceByLen.delete("FOO");
- throw new RuntimeException("Accepted delete() for " +
- "unsupported element name");
- } catch (IOException ioe) { } // Expected result
-
- // Now attempt to properly delete the extension data
- nonceByLen.delete(ELEMENT_NONCE);
- nonceData = (byte[])nonceByLen.get(ELEMENT_NONCE);
- if (nonceData != null) {
- throw new RuntimeException("Unexpected non-null return");
- }
-
- pass = Boolean.TRUE;
- } catch (Exception e) {
- e.printStackTrace(System.out);
- message = e.getClass().getName();
- }
-
- return new AbstractMap.SimpleEntry<>(pass, message);
- }
- };
}
--- a/jdk/test/sun/security/rsa/SignatureOffsets.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/security/rsa/SignatureOffsets.java Tue Sep 08 14:40:44 2015 -0700
@@ -50,4 +50,4 @@
InvalidKeyException, SignatureException {
Offsets.main(args);
}
-}
\ No newline at end of file
+}
--- a/jdk/test/sun/security/ssl/StatusStapling/TestCase.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/security/ssl/StatusStapling/TestCase.java Tue Sep 08 14:40:44 2015 -0700
@@ -28,5 +28,3 @@
public interface TestCase {
Map.Entry<Boolean, String> runTest();
}
-
-
--- a/jdk/test/sun/security/ssl/StatusStapling/TestUtils.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/security/ssl/StatusStapling/TestUtils.java Tue Sep 08 14:40:44 2015 -0700
@@ -122,5 +122,3 @@
return resultBuf;
}
}
-
-
--- a/jdk/test/sun/security/ssl/rsa/SignatureOffsets.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/security/ssl/rsa/SignatureOffsets.java Tue Sep 08 14:40:44 2015 -0700
@@ -47,4 +47,4 @@
InvalidKeyException, SignatureException {
Offsets.main(args);
}
-}
\ No newline at end of file
+}
--- a/jdk/test/sun/security/tools/jarsigner/collator.sh Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/security/tools/jarsigner/collator.sh Tue Sep 08 14:40:44 2015 -0700
@@ -72,5 +72,3 @@
echo "ERR is $ERR"
exit 1
fi
-
-
--- a/jdk/test/sun/security/tools/jarsigner/jvindex.sh Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/security/tools/jarsigner/jvindex.sh Tue Sep 08 14:40:44 2015 -0700
@@ -72,5 +72,3 @@
echo "ERR is $ERR"
exit 1
fi
-
-
--- a/jdk/test/sun/security/tools/jarsigner/warnings.sh Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/security/tools/jarsigner/warnings.sh Tue Sep 08 14:40:44 2015 -0700
@@ -115,5 +115,3 @@
echo "ERR is $ERR"
exit 1
fi
-
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/x509/X509CertImpl/V3Certificate.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import static java.lang.System.out;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+import sun.misc.BASE64Encoder;
+import sun.security.util.BitArray;
+import sun.security.util.ObjectIdentifier;
+import sun.security.x509.*;
+
+/**
+ * @test
+ * @bug 8049237
+ * @modules java.base/sun.security.x509
+ * java.base/sun.security.util
+ * java.base/sun.misc
+ * @summary This test generates V3 certificate with all the supported
+ * extensions. Writes back the generated certificate in to a file and checks for
+ * equality with the original certificate.
+ */
+public class V3Certificate {
+
+ public static final String V3_FILE = "certV3";
+ public static final String V3_B64_FILE = "certV3.b64";
+
+ public static void main(String[] args) throws IOException,
+ NoSuchAlgorithmException, InvalidKeyException, CertificateException,
+ NoSuchProviderException, SignatureException {
+
+ boolean success = true;
+
+ success &= test("RSA", "SHA256withRSA", 2048);
+ success &= test("DSA", "SHA256withDSA", 2048);
+ success &= test("EC", "SHA256withECDSA", 384);
+
+ if (!success) {
+ throw new RuntimeException("At least one test case failed");
+ }
+ }
+
+ public static boolean test(String algorithm, String sigAlg, int keyLength)
+ throws IOException,
+ NoSuchAlgorithmException,
+ InvalidKeyException,
+ CertificateException,
+ NoSuchProviderException,
+ SignatureException {
+
+ byte[] issuerId = {1, 2, 3, 4, 5};
+ byte[] subjectId = {6, 7, 8, 9, 10};
+ boolean testResult = true;
+
+ // Subject and Issuer
+ X500Name subject = new X500Name("test", "Oracle", "Santa Clara",
+ "US");
+ X500Name issuer = subject;
+
+ // Generate keys and sign
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm);
+ keyGen.initialize(keyLength);
+ KeyPair pair = keyGen.generateKeyPair();
+ PublicKey publicKey = pair.getPublic();
+ PrivateKey privateKey = pair.getPrivate();
+ MessageDigest md = MessageDigest.getInstance("SHA");
+ byte[] keyId = md.digest(publicKey.getEncoded());
+
+ Signature signature = Signature.getInstance(sigAlg);
+ signature.initSign(privateKey);
+
+ // Validity interval
+ Date firstDate = new Date();
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("PST"));
+ cal.set(2014, 03, 10, 12, 30, 30);
+ Date lastDate = cal.getTime();
+ CertificateValidity interval = new CertificateValidity(firstDate,
+ lastDate);
+
+ // Certificate Info
+ X509CertInfo cert = new X509CertInfo();
+
+ cert.set(X509CertInfo.VERSION,
+ new CertificateVersion(CertificateVersion.V3));
+ cert.set(X509CertInfo.SERIAL_NUMBER,
+ new CertificateSerialNumber((int) (firstDate.getTime() / 1000)));
+ cert.set(X509CertInfo.ALGORITHM_ID,
+ new CertificateAlgorithmId(AlgorithmId.get(sigAlg)));
+ cert.set(X509CertInfo.SUBJECT, subject);
+ cert.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
+ cert.set(X509CertInfo.VALIDITY, interval);
+ cert.set(X509CertInfo.ISSUER, issuer);
+
+ cert.set(X509CertInfo.ISSUER_ID,
+ new UniqueIdentity(
+ new BitArray(issuerId.length * 8 - 2, issuerId)));
+ cert.set(X509CertInfo.SUBJECT_ID, new UniqueIdentity(subjectId));
+
+ // Create Extensions
+ CertificateExtensions exts = new CertificateExtensions();
+
+ GeneralNameInterface mailInf = new RFC822Name("test@Oracle.com");
+ GeneralName mail = new GeneralName(mailInf);
+ GeneralNameInterface dnsInf = new DNSName("Oracle.com");
+ GeneralName dns = new GeneralName(dnsInf);
+ GeneralNameInterface uriInf = new URIName("http://www.Oracle.com");
+ GeneralName uri = new GeneralName(uriInf);
+
+ // localhost
+ byte[] address = new byte[]{127, 0, 0, 1};
+
+ GeneralNameInterface ipInf = new IPAddressName(address);
+ GeneralName ip = new GeneralName(ipInf);
+ int[] oidData = new int[]{1, 2, 3, 4};
+
+ GeneralNameInterface oidInf = new OIDName(new ObjectIdentifier(oidData));
+ GeneralName oid = new GeneralName(oidInf);
+
+ SubjectAlternativeNameExtension subjectName
+ = new SubjectAlternativeNameExtension();
+ IssuerAlternativeNameExtension issuerName
+ = new IssuerAlternativeNameExtension();
+
+ GeneralNames subjectNames
+ = (GeneralNames) subjectName.
+ get(SubjectAlternativeNameExtension.SUBJECT_NAME);
+
+ GeneralNames issuerNames
+ = (GeneralNames) issuerName.
+ get(IssuerAlternativeNameExtension.ISSUER_NAME);
+
+ subjectNames.add(mail);
+ subjectNames.add(dns);
+ subjectNames.add(uri);
+
+ issuerNames.add(ip);
+ issuerNames.add(oid);
+
+ cal.set(2000, 11, 15, 12, 30, 30);
+ lastDate = cal.getTime();
+ PrivateKeyUsageExtension pkusage
+ = new PrivateKeyUsageExtension(firstDate, lastDate);
+
+ KeyUsageExtension usage = new KeyUsageExtension();
+ usage.set(KeyUsageExtension.CRL_SIGN, true);
+ usage.set(KeyUsageExtension.DIGITAL_SIGNATURE, true);
+ usage.set(KeyUsageExtension.NON_REPUDIATION, true);
+
+ KeyIdentifier kid = new KeyIdentifier(keyId);
+ SerialNumber sn = new SerialNumber(42);
+ AuthorityKeyIdentifierExtension aki
+ = new AuthorityKeyIdentifierExtension(kid, subjectNames, sn);
+
+ SubjectKeyIdentifierExtension ski
+ = new SubjectKeyIdentifierExtension(keyId);
+
+ BasicConstraintsExtension cons
+ = new BasicConstraintsExtension(true, 10);
+
+ PolicyConstraintsExtension pce = new PolicyConstraintsExtension(2, 4);
+
+ exts.set(SubjectAlternativeNameExtension.NAME, subjectName);
+ exts.set(IssuerAlternativeNameExtension.NAME, issuerName);
+ exts.set(PrivateKeyUsageExtension.NAME, pkusage);
+ exts.set(KeyUsageExtension.NAME, usage);
+ exts.set(AuthorityKeyIdentifierExtension.NAME, aki);
+ exts.set(SubjectKeyIdentifierExtension.NAME, ski);
+ exts.set(BasicConstraintsExtension.NAME, cons);
+ exts.set(PolicyConstraintsExtension.NAME, pce);
+ cert.set(X509CertInfo.EXTENSIONS, exts);
+
+ // Generate and sign X509CertImpl
+ X509CertImpl crt = new X509CertImpl(cert);
+ crt.sign(privateKey, sigAlg);
+ crt.verify(publicKey);
+
+ try (FileOutputStream fos = new FileOutputStream(new File(V3_FILE));
+ FileOutputStream fos_b64
+ = new FileOutputStream(new File(V3_B64_FILE));
+ PrintWriter pw = new PrintWriter(fos_b64)) {
+ crt.encode((OutputStream) fos);
+ fos.flush();
+
+ // Certificate boundaries/
+ pw.println("-----BEGIN CERTIFICATE-----");
+ pw.flush();
+ new BASE64Encoder().encodeBuffer(crt.getEncoded(), fos_b64);
+ fos_b64.flush();
+ pw.println("-----END CERTIFICATE-----");
+ }
+
+ out.println("*** Certificate ***");
+ out.println(crt);
+ out.println("*** End Certificate ***");
+
+ X509Certificate x2 = generateCertificate(V3_FILE);
+ if (!x2.equals(crt)) {
+ out.println("*** Certificate mismatch ***");
+ testResult = false;
+ }
+
+ X509Certificate x3 = generateCertificate(V3_B64_FILE);
+ if (!x3.equals(crt)) {
+ out.println("*** Certificate mismatch ***");
+ testResult = false;
+ }
+
+ return testResult;
+ }
+
+ static X509Certificate generateCertificate(String certFile) {
+ try (InputStream inStrm = new FileInputStream(certFile)) {
+ CertificateFactory cf = CertificateFactory.getInstance("X509");
+ X509Certificate x2
+ = (X509Certificate) cf.generateCertificate(inStrm);
+ return x2;
+ } catch (CertificateException | IOException e) {
+ throw new RuntimeException("Exception while "
+ + "genrating certificate for " + certFile, e);
+ }
+ }
+}
--- a/jdk/test/sun/tools/jps/JpsBase.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/tools/jps/JpsBase.java Tue Sep 08 14:40:44 2015 -0700
@@ -138,6 +138,8 @@
String tmp = str.replace("\\", "\\\\");
tmp = tmp.replace("+", "\\+");
tmp = tmp.replace(".", "\\.");
+ tmp = tmp.replace("\n", "\\\\n");
+ tmp = tmp.replace("\r", "\\\\r");
return tmp;
}
--- a/jdk/test/sun/tools/jps/JpsHelper.java Tue Sep 08 16:01:29 2015 +0400
+++ b/jdk/test/sun/tools/jps/JpsHelper.java Tue Sep 08 14:40:44 2015 -0700
@@ -97,7 +97,10 @@
* VM arguments to start test application with.
* -XX:+UsePerfData is required for running the tests on embedded platforms.
*/
- public static final String[] VM_ARGS = {"-XX:+UsePerfData", "-Xmx512m", "-XX:+PrintGCDetails"};
+ public static final String[] VM_ARGS = {
+ "-XX:+UsePerfData", "-Xmx512m", "-XX:+PrintGCDetails",
+ "-Dmultiline.prop=value1\nvalue2\r\nvalue3"
+ };
/**
* VM flag to start test application with
*/
--- a/langtools/.hgtags Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/.hgtags Tue Sep 08 14:40:44 2015 -0700
@@ -322,3 +322,4 @@
6ec3d5cb1bfcfba135c8d18866e567f1b1ada861 jdk9-b77
7fd155b7041c8aba7084f03e2fd1d6f74cceda75 jdk9-b78
eaab8a16dcfb807acacdb6d133f3ecd502667a8c jdk9-b79
+c5671e662392df372b2005b75afa6cfdc0eebce7 jdk9-b80
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Tue Sep 08 14:40:44 2015 -0700
@@ -76,7 +76,7 @@
private final AtomicBoolean used = new AtomicBoolean();
private Iterable<? extends Processor> processors;
- JavacTaskImpl(Context context) {
+ protected JavacTaskImpl(Context context) {
super(context, true);
args = Arguments.instance(context);
fileManager = context.get(JavaFileManager.class);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/MultiTaskListener.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/MultiTaskListener.java Tue Sep 08 14:40:44 2015 -0700
@@ -47,6 +47,9 @@
/** The context key for the MultiTaskListener. */
public static final Context.Key<MultiTaskListener> taskListenerKey = new Context.Key<>();
+ /** Empty array of task listeners */
+ private static final TaskListener[] EMPTY_LISTENERS = new TaskListener[0];
+
/** Get the MultiTaskListener instance for this context. */
public static MultiTaskListener instance(Context context) {
MultiTaskListener instance = context.get(taskListenerKey);
@@ -64,7 +67,7 @@
* The current set of registered listeners.
* This is a mutable reference to an immutable array.
*/
- TaskListener[] listeners = { };
+ TaskListener[] listeners = EMPTY_LISTENERS;
ClientCodeWrapper ccw;
@@ -73,7 +76,7 @@
}
public boolean isEmpty() {
- return (listeners.length == 0);
+ return listeners == EMPTY_LISTENERS;
}
public void add(TaskListener listener) {
@@ -88,10 +91,14 @@
public void remove(TaskListener listener) {
for (int i = 0; i < listeners.length; i++) {
if (ccw.unwrap(listeners[i]) == listener) {
- TaskListener[] newListeners = new TaskListener[listeners.length - 1];
- System.arraycopy(listeners, 0, newListeners, 0, i);
- System.arraycopy(listeners, i + 1, newListeners, i, newListeners.length - i);
- listeners = newListeners;
+ if (listeners.length == 1) {
+ listeners = EMPTY_LISTENERS;
+ } else {
+ TaskListener[] newListeners = new TaskListener[listeners.length - 1];
+ System.arraycopy(listeners, 0, newListeners, 0, i);
+ System.arraycopy(listeners, i + 1, newListeners, i, newListeners.length - i);
+ listeners = newListeners;
+ }
break;
}
}
@@ -117,4 +124,8 @@
public String toString() {
return Arrays.toString(listeners);
}
+
+ public void clear() {
+ listeners = EMPTY_LISTENERS;
+ }
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Scope.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Scope.java Tue Sep 08 14:40:44 2015 -0700
@@ -26,6 +26,7 @@
package com.sun.tools.javac.code;
import com.sun.tools.javac.code.Kinds.Kind;
+import java.lang.ref.WeakReference;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.stream.Stream;
@@ -162,15 +163,49 @@
/** A list of scopes to be notified if items are to be removed from this scope.
*/
- List<ScopeListener> listeners = List.nil();
+ ScopeListenerList listeners = new ScopeListenerList();
- public void addScopeListener(ScopeListener sl) {
- listeners = listeners.prepend(sl);
+ public interface ScopeListener {
+ void symbolAdded(Symbol sym, Scope s);
+ void symbolRemoved(Symbol sym, Scope s);
}
- public interface ScopeListener {
- public void symbolAdded(Symbol sym, Scope s);
- public void symbolRemoved(Symbol sym, Scope s);
+ /**
+ * A list of scope listeners; listeners are stored in weak references, to avoid memory leaks.
+ * When the listener list is scanned (upon notification), elements corresponding to GC-ed
+ * listeners are removed so that the listener list size is kept in check.
+ */
+ public static class ScopeListenerList {
+
+ List<WeakReference<ScopeListener>> listeners = List.nil();
+
+ void add(ScopeListener sl) {
+ listeners = listeners.prepend(new WeakReference<>(sl));
+ }
+
+ void symbolAdded(Symbol sym, Scope scope) {
+ walkReferences(sym, scope, false);
+ }
+
+ void symbolRemoved(Symbol sym, Scope scope) {
+ walkReferences(sym, scope, true);
+ }
+
+ private void walkReferences(Symbol sym, Scope scope, boolean isRemove) {
+ ListBuffer<WeakReference<ScopeListener>> newListeners = new ListBuffer<>();
+ for (WeakReference<ScopeListener> wsl : listeners) {
+ ScopeListener sl = wsl.get();
+ if (sl != null) {
+ if (isRemove) {
+ sl.symbolRemoved(sym, scope);
+ } else {
+ sl.symbolAdded(sym, scope);
+ }
+ newListeners.add(wsl);
+ }
+ }
+ listeners = newListeners.toList();
+ }
}
public enum LookupKind {
@@ -404,9 +439,7 @@
elems = e;
//notify listeners
- for (List<ScopeListener> l = listeners; l.nonEmpty(); l = l.tail) {
- l.head.symbolAdded(sym, this);
- }
+ listeners.symbolAdded(sym, this);
}
/** Remove symbol from this scope.
@@ -442,9 +475,7 @@
}
//notify listeners
- for (List<ScopeListener> l = listeners; l.nonEmpty(); l = l.tail) {
- l.head.symbolRemoved(sym, this);
- }
+ listeners.symbolRemoved(sym, this);
}
/** Enter symbol sym in this scope if not already there.
@@ -698,11 +729,12 @@
finalized.enter(sym);
}
- finalized.addScopeListener(new ScopeListener() {
+ finalized.listeners.add(new ScopeListener() {
@Override
public void symbolAdded(Symbol sym, Scope s) {
Assert.error("The scope is sealed.");
}
+
@Override
public void symbolRemoved(Symbol sym, Scope s) {
Assert.error("The scope is sealed.");
@@ -929,26 +961,20 @@
public void prependSubScope(Scope that) {
if (that != null) {
subScopes = subScopes.prepend(that);
- that.addScopeListener(this);
+ that.listeners.add(this);
mark++;
- for (ScopeListener sl : listeners) {
- sl.symbolAdded(null, this); //propagate upwards in case of nested CompoundScopes
- }
+ listeners.symbolAdded(null, this);
}
}
public void symbolAdded(Symbol sym, Scope s) {
mark++;
- for (ScopeListener sl : listeners) {
- sl.symbolAdded(sym, s);
- }
+ listeners.symbolAdded(sym, s);
}
public void symbolRemoved(Symbol sym, Scope s) {
mark++;
- for (ScopeListener sl : listeners) {
- sl.symbolRemoved(sym, s);
- }
+ listeners.symbolRemoved(sym, s);
}
public int getMark() {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java Tue Sep 08 14:40:44 2015 -0700
@@ -68,7 +68,7 @@
/**
* The context key for the arguments.
*/
- protected static final Context.Key<Arguments> argsKey = new Context.Key<>();
+ public static final Context.Key<Arguments> argsKey = new Context.Key<>();
private String ownName;
private Set<String> classNames;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Tue Sep 08 14:40:44 2015 -0700
@@ -87,7 +87,7 @@
*/
public class JavaCompiler {
/** The context key for the compiler. */
- protected static final Context.Key<JavaCompiler> compilerKey = new Context.Key<>();
+ public static final Context.Key<JavaCompiler> compilerKey = new Context.Key<>();
/** Get the JavaCompiler instance for this context. */
public static JavaCompiler instance(Context context) {
@@ -821,7 +821,7 @@
// as a JavaCompiler can only be used once, throw an exception if
// it has been used before.
if (hasBeenUsed)
- throw new AssertionError("attempt to reuse JavaCompiler");
+ checkReusable();
hasBeenUsed = true;
// forcibly set the equivalent of -Xlint:-options, so that no further
@@ -898,6 +898,10 @@
}
}
+ protected void checkReusable() {
+ throw new AssertionError("attempt to reuse JavaCompiler");
+ }
+
/**
* Set needRootClasses to true, in JavaCompiler subclass constructor
* that want to collect public apis of classes supplied on the command line.
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Tue Sep 08 14:40:44 2015 -0700
@@ -26,6 +26,7 @@
package com.sun.tools.javac.parser;
import java.util.*;
+import java.util.stream.Collectors;
import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
@@ -510,7 +511,7 @@
if (mods != 0) {
long lowestMod = mods & -mods;
error(token.pos, "mod.not.allowed.here",
- Flags.asFlagSet(lowestMod));
+ Flags.asFlagSet(lowestMod));
}
}
@@ -946,10 +947,7 @@
t = odStack[0];
if (t.hasTag(JCTree.Tag.PLUS)) {
- StringBuilder buf = foldStrings(t);
- if (buf != null) {
- t = toP(F.at(startPos).Literal(TypeTag.CLASS, buf.toString()));
- }
+ t = foldStrings(t);
}
odStackSupply.add(odStack);
@@ -973,37 +971,76 @@
/** If tree is a concatenation of string literals, replace it
* by a single literal representing the concatenated string.
*/
- protected StringBuilder foldStrings(JCTree tree) {
+ protected JCExpression foldStrings(JCExpression tree) {
if (!allowStringFolding)
return null;
- List<String> buf = List.nil();
+ ListBuffer<JCExpression> opStack = new ListBuffer<>();
+ ListBuffer<JCLiteral> litBuf = new ListBuffer<>();
+ boolean needsFolding = false;
+ JCExpression curr = tree;
while (true) {
- if (tree.hasTag(LITERAL)) {
- JCLiteral lit = (JCLiteral) tree;
- if (lit.typetag == TypeTag.CLASS) {
- StringBuilder sbuf =
- new StringBuilder((String)lit.value);
- while (buf.nonEmpty()) {
- sbuf.append(buf.head);
- buf = buf.tail;
- }
- return sbuf;
- }
- } else if (tree.hasTag(JCTree.Tag.PLUS)) {
- JCBinary op = (JCBinary)tree;
- if (op.rhs.hasTag(LITERAL)) {
- JCLiteral lit = (JCLiteral) op.rhs;
- if (lit.typetag == TypeTag.CLASS) {
- buf = buf.prepend((String) lit.value);
- tree = op.lhs;
- continue;
- }
- }
+ if (curr.hasTag(JCTree.Tag.PLUS)) {
+ JCBinary op = (JCBinary)curr;
+ needsFolding |= foldIfNeeded(op.rhs, litBuf, opStack, false);
+ curr = op.lhs;
+ } else {
+ needsFolding |= foldIfNeeded(curr, litBuf, opStack, true);
+ break; //last one!
}
- return null;
+ }
+ if (needsFolding) {
+ List<JCExpression> ops = opStack.toList();
+ JCExpression res = ops.head;
+ for (JCExpression op : ops.tail) {
+ res = F.at(op.getStartPosition()).Binary(optag(TokenKind.PLUS), res, op);
+ storeEnd(res, getEndPos(op));
+ }
+ return res;
+ } else {
+ return tree;
}
}
+ private boolean foldIfNeeded(JCExpression tree, ListBuffer<JCLiteral> litBuf,
+ ListBuffer<JCExpression> opStack, boolean last) {
+ JCLiteral str = stringLiteral(tree);
+ if (str != null) {
+ litBuf.prepend(str);
+ return last && merge(litBuf, opStack);
+ } else {
+ boolean res = merge(litBuf, opStack);
+ litBuf.clear();
+ opStack.prepend(tree);
+ return res;
+ }
+ }
+
+ boolean merge(ListBuffer<JCLiteral> litBuf, ListBuffer<JCExpression> opStack) {
+ if (litBuf.isEmpty()) {
+ return false;
+ } else if (litBuf.size() == 1) {
+ opStack.prepend(litBuf.first());
+ return false;
+ } else {
+ JCExpression t = F.at(litBuf.first().getStartPosition()).Literal(TypeTag.CLASS,
+ litBuf.stream().map(lit -> (String)lit.getValue()).collect(Collectors.joining()));
+ storeEnd(t, litBuf.last().getEndPosition(endPosTable));
+ opStack.prepend(t);
+ return true;
+ }
+ }
+
+ private JCLiteral stringLiteral(JCTree tree) {
+ if (tree.hasTag(LITERAL)) {
+ JCLiteral lit = (JCLiteral)tree;
+ if (lit.typetag == TypeTag.CLASS) {
+ return lit;
+ }
+ }
+ return null;
+ }
+
+
/** optimization: To save allocating a new operand/operator stack
* for every binary operation, we use supplys.
*/
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Context.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Context.java Tue Sep 08 14:40:44 2015 -0700
@@ -119,7 +119,7 @@
* or
* {@literal Key<T> -> Factory<T> }
*/
- private final Map<Key<?>,Object> ht = new HashMap<>();
+ protected final Map<Key<?>,Object> ht = new HashMap<>();
/** Set the factory for the key in this context. */
public <T> void put(Key<T> key, Factory<T> fac) {
@@ -173,7 +173,7 @@
*/
private final Map<Class<?>, Key<?>> kt = new HashMap<>();
- private <T> Key<T> key(Class<T> clss) {
+ protected <T> Key<T> key(Class<T> clss) {
checkState(kt);
Key<T> k = uncheckedCast(kt.get(clss));
if (k == null) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java Tue Sep 08 14:40:44 2015 -0700
@@ -334,7 +334,7 @@
* error message more than once. For each error, a pair consisting of the
* source file name and source code position of the error is added to the set.
*/
- private Set<Pair<JavaFileObject, Integer>> recorded = new HashSet<>();
+ protected Set<Pair<JavaFileObject, Integer>> recorded = new HashSet<>();
public boolean hasDiagnosticListener() {
return diagListener != null;
--- a/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java Tue Sep 08 14:40:44 2015 -0700
@@ -25,26 +25,19 @@
* @test
* @bug 6769027 8006694
* @summary Source line should be displayed immediately after the first diagnostic line
- * temporarily workaround combo tests are causing time out in several platforms
- * @author Maurizio Cimadamore
- * @library ../../lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
* @run main/othervm T6769027
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+// use /othervm to avoid locale issues
import java.net.URI;
import java.util.regex.Matcher;
import javax.tools.*;
import com.sun.tools.javac.util.*;
-public class T6769027
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
+public class T6769027 {
enum OutputKind {
RAW("rawDiagnostics","rawDiagnostics"),
@@ -324,11 +317,6 @@
}
@Override
- protected java.io.PrintWriter getWriterForDiagnosticType(JCDiagnostic.DiagnosticType dt) {
- return outWriter;
- }
-
- @Override
protected boolean shouldReport(JavaFileObject jfo, int pos) {
return true;
}
@@ -368,7 +356,6 @@
this.subdiagsIndent = subdiagsIndent;
}
- @Override
public void run() {
Context ctx = new Context();
Options options = Options.instance(ctx);
@@ -419,7 +406,7 @@
for (IndentKind detailsIndent : IndentKind.values()) {
for (IndentKind sourceIndent : IndentKind.values()) {
for (IndentKind subdiagsIndent : IndentKind.values()) {
- pool.execute(new T6769027(outputKind,
+ new T6769027(outputKind,
errKind,
multiKind,
multiPolicy,
@@ -431,7 +418,7 @@
summaryIndent,
detailsIndent,
sourceIndent,
- subdiagsIndent));
+ subdiagsIndent).run();
}
}
}
@@ -445,8 +432,6 @@
}
}
}
-
- checkAfterExec(false);
}
void printInfo(String msg, String errorLine) {
@@ -457,11 +442,11 @@
" caret=" + caretKind + " sourcePosition=" + sourceLineKind +
" summaryIndent=" + summaryIndent + " detailsIndent=" + detailsIndent +
" sourceIndent=" + sourceIndent + " subdiagsIndent=" + subdiagsIndent;
- errWriter.println(sep);
- errWriter.println(desc);
- errWriter.println(sep);
- errWriter.println(msg);
- errWriter.println("Diagnostic formatting problem - expected diagnostic...\n" + errorLine);
+ System.err.println(sep);
+ System.err.println(desc);
+ System.err.println(sep);
+ System.err.println(msg);
+ System.err.println("Diagnostic formatting problem - expected diagnostic...\n" + errorLine);
}
void checkOutput(String msg) {
@@ -494,8 +479,8 @@
}
if (!msg.equals(errorLine)) {
-// printInfo(msg, errorLine);
- errCount.incrementAndGet();
+ printInfo(msg, errorLine);
+ throw new AssertionError("errors were found");
}
}
--- a/langtools/test/tools/javac/T7093325.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/T7093325.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,38 +23,41 @@
/*
* @test
- * @bug 7093325 8006694
+ * @bug 7093325 8006694 8129962
* @summary Redundant entry in bytecode exception table
* temporarily workaround combo tests are causing time out in several platforms
- * @library lib
+ * @library /tools/javac/lib
* @modules jdk.jdeps/com.sun.tools.classfile
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm T7093325
+ * jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main T7093325
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
+import java.io.InputStream;
-import java.io.File;
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.JavaCompiler;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.ToolProvider;
-
-import com.sun.source.util.JavacTask;
import com.sun.tools.classfile.Attribute;
import com.sun.tools.classfile.ClassFile;
import com.sun.tools.classfile.Code_attribute;
-import com.sun.tools.classfile.ConstantPool.*;
+import com.sun.tools.classfile.ConstantPoolException;
import com.sun.tools.classfile.Method;
-public class T7093325
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
+import javax.tools.JavaFileObject;
- enum StatementKind {
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
+
+public class T7093325 extends ComboInstance<T7093325> {
+
+ enum StatementKind implements ComboParameter {
+ NONE(null, false, false),
THROW("throw new RuntimeException();", false, false),
RETURN_NONEMPTY("System.out.println(); return;", true, false),
RETURN_EMPTY("return;", true, true),
@@ -64,107 +67,79 @@
boolean canInline;
boolean empty;
- private StatementKind(String stmt, boolean canInline, boolean empty) {
+ StatementKind(String stmt, boolean canInline, boolean empty) {
this.stmt = stmt;
this.canInline = canInline;
this.empty = empty;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return stmt;
+ }
}
- enum CatchArity {
+ enum CatchArity implements ComboParameter {
NONE(""),
- ONE("catch (A a) { #S1 }"),
- TWO("catch (B b) { #S2 }"),
- THREE("catch (C c) { #S3 }"),
- FOUR("catch (D d) { #S4 }");
+ ONE("catch (A a) { #{STMT[1]} }"),
+ TWO("catch (B b) { #{STMT[2]} }"),
+ THREE("catch (C c) { #{STMT[3]} }"),
+ FOUR("catch (D d) { #{STMT[4]} }");
String catchStr;
- private CatchArity(String catchStr) {
+ CatchArity(String catchStr) {
this.catchStr = catchStr;
}
- String catchers() {
+ @Override
+ public String expand(String optParameter) {
if (this.ordinal() == 0) {
return catchStr;
} else {
- return CatchArity.values()[this.ordinal() - 1].catchers() +
+ return CatchArity.values()[this.ordinal() - 1].expand(optParameter) +
catchStr;
}
}
}
public static void main(String... args) throws Exception {
- for (CatchArity ca : CatchArity.values()) {
- for (StatementKind stmt0 : StatementKind.values()) {
- if (ca.ordinal() == 0) {
- pool.execute(new T7093325(ca, stmt0));
- continue;
- }
- for (StatementKind stmt1 : StatementKind.values()) {
- if (ca.ordinal() == 1) {
- pool.execute(new T7093325(ca, stmt0, stmt1));
- continue;
- }
- for (StatementKind stmt2 : StatementKind.values()) {
- if (ca.ordinal() == 2) {
- pool.execute(new T7093325(ca, stmt0, stmt1, stmt2));
- continue;
- }
- for (StatementKind stmt3 : StatementKind.values()) {
- if (ca.ordinal() == 3) {
- pool.execute(
- new T7093325(ca, stmt0, stmt1, stmt2, stmt3));
- continue;
- }
- for (StatementKind stmt4 : StatementKind.values()) {
- if (ca.ordinal() == 4) {
- pool.execute(
- new T7093325(ca, stmt0, stmt1,
- stmt2, stmt3, stmt4));
- continue;
- }
- for (StatementKind stmt5 : StatementKind.values()) {
- pool.execute(
- new T7093325(ca, stmt0, stmt1, stmt2,
- stmt3, stmt4, stmt5));
- }
- }
- }
- }
- }
- }
- }
-
- checkAfterExec();
+ new ComboTestHelper<T7093325>()
+ .withFilter(T7093325::testFilter)
+ .withDimension("CATCH", (x, ca) -> x.ca = ca, CatchArity.values())
+ .withArrayDimension("STMT", (x, stmt, idx) -> x.stmts[idx] = stmt, 5, StatementKind.values())
+ .run(T7093325::new);
}
/** instance decls **/
CatchArity ca;
- StatementKind[] stmts;
+ StatementKind[] stmts = new StatementKind[5];
- public T7093325(CatchArity ca, StatementKind... stmts) {
- this.ca = ca;
- this.stmts = stmts;
+ boolean testFilter() {
+ int lastPos = ca.ordinal() + 1;
+ for (int i = 0; i < stmts.length ; i++) {
+ boolean shouldBeSet = i < lastPos;
+ boolean isSet = stmts[i] != StatementKind.NONE;
+ if (shouldBeSet != isSet) {
+ return false;
+ }
+ }
+ return true;
}
@Override
- public void run() {
- int id = checkCount.incrementAndGet();
- final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
- JavaSource source = new JavaSource(id);
- JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), null,
- null, null, Arrays.asList(source));
- ct.call();
- verifyBytecode(source, id);
+ public void doWork() throws IOException {
+ verifyBytecode(newCompilationTask()
+ .withSourceFromTemplate(source_template)
+ .generate());
}
- void verifyBytecode(JavaSource source, int id) {
+ void verifyBytecode(Result<Iterable<? extends JavaFileObject>> result) {
boolean lastInlined = false;
boolean hasCode = false;
int gapsCount = 0;
- for (int i = 0; i < stmts.length ; i++) {
+ for (int i = 0; i < ca.ordinal() + 1 ; i++) {
lastInlined = stmts[i].canInline;
hasCode = hasCode || !stmts[i].empty;
if (lastInlined && hasCode) {
@@ -176,12 +151,11 @@
gapsCount++;
}
- File compiledTest = new File(String.format("Test%s.class", id));
- try {
- ClassFile cf = ClassFile.read(compiledTest);
+ try (InputStream is = result.get().iterator().next().openInputStream()) {
+ ClassFile cf = ClassFile.read(is);
if (cf == null) {
- throw new Error("Classfile not found: " +
- compiledTest.getName());
+ fail("Classfile not found: " + result.compilationInfo());
+ return;
}
Method test_method = null;
@@ -193,7 +167,8 @@
}
if (test_method == null) {
- throw new Error("Method test() not found in class Test");
+ fail("Method test() not found in class Test" + result.compilationInfo());
+ return;
}
Code_attribute code = null;
@@ -205,7 +180,8 @@
}
if (code == null) {
- throw new Error("Code attribute not found in method test()");
+ fail("Code attribute not found in method test()");
+ return;
}
int actualGapsCount = 0;
@@ -217,54 +193,28 @@
}
if (actualGapsCount != gapsCount) {
- throw new Error("Bad exception table for test()\n" +
+ fail("Bad exception table for test()\n" +
"expected gaps: " + gapsCount + "\n" +
"found gaps: " + actualGapsCount + "\n" +
- source);
+ result.compilationInfo());
+ return;
}
- } catch (Exception e) {
+ } catch (IOException | ConstantPoolException e) {
e.printStackTrace();
- throw new Error("error reading " + compiledTest +": " + e);
+ fail("error reading classfile: " + e);
}
}
- class JavaSource extends SimpleJavaFileObject {
-
- static final String source_template =
+ static final String source_template =
+ "class Test {\n" +
+ " void test() {\n" +
+ " try { #{STMT[0]} } #{CATCH} finally { System.out.println(); }\n" +
+ " }\n" +
+ "}\n" +
"class A extends RuntimeException {} \n" +
"class B extends RuntimeException {} \n" +
"class C extends RuntimeException {} \n" +
"class D extends RuntimeException {} \n" +
- "class E extends RuntimeException {} \n" +
- "class Test#ID {\n" +
- " void test() {\n" +
- " try { #S0 } #C finally { System.out.println(); }\n" +
- " }\n" +
- "}";
-
- String source;
-
- public JavaSource(int id) {
- super(URI.create(String.format("myfo:/Test%s.java", id)),
- JavaFileObject.Kind.SOURCE);
- source = source_template.replace("#C", ca.catchers());
- source = source.replace("#S0", stmts[0].stmt);
- source = source.replace("#ID", String.valueOf(id));
- for (int i = 1; i < ca.ordinal() + 1; i++) {
- source = source.replace("#S" + i, stmts[i].stmt);
- }
- }
-
- @Override
- public String toString() {
- return source;
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
- }
- }
-
+ "class E extends RuntimeException {}";
}
--- a/langtools/test/tools/javac/TestBootstrapMethodsCount.java Tue Sep 08 16:01:29 2015 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,236 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
- * 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 8129547
- * @summary Excess entries in BootstrapMethods with the same (bsm, bsmKind, bsmStaticArgs), but different dynamicArgs
- * @library lib
- * @modules jdk.jdeps/com.sun.tools.classfile
- * jdk.compiler/com.sun.tools.javac.api
- * jdk.compiler/com.sun.tools.javac.code
- * jdk.compiler/com.sun.tools.javac.jvm
- * jdk.compiler/com.sun.tools.javac.tree
- * jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm TestBootstrapMethodsCount
- */
-
-import java.io.File;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Locale;
-
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-
-import com.sun.source.tree.MethodInvocationTree;
-import com.sun.source.tree.MethodTree;
-import com.sun.source.util.TaskEvent;
-import com.sun.source.util.TaskListener;
-import com.sun.source.util.TreeScanner;
-
-import com.sun.tools.classfile.Attribute;
-import com.sun.tools.classfile.BootstrapMethods_attribute;
-import com.sun.tools.classfile.ClassFile;
-
-import com.sun.tools.javac.api.JavacTaskImpl;
-import com.sun.tools.javac.code.Symbol;
-import com.sun.tools.javac.code.Symbol.MethodSymbol;
-import com.sun.tools.javac.code.Symtab;
-import com.sun.tools.javac.code.Types;
-import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
-import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
-import com.sun.tools.javac.tree.JCTree.JCIdent;
-import com.sun.tools.javac.util.Context;
-import com.sun.tools.javac.util.Names;
-
-import static com.sun.tools.javac.jvm.ClassFile.*;
-
-public class TestBootstrapMethodsCount
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
-
-
- public static void main(String... args) throws Exception {
- pool.execute(new TestBootstrapMethodsCount());
- checkAfterExec();
- }
-
- DiagChecker dc;
-
- TestBootstrapMethodsCount() {
- dc = new DiagChecker();
- }
-
- public void run() {
- int id = checkCount.incrementAndGet();
- JavaSource source = new JavaSource(id);
- JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, fm.get(), dc,
- Arrays.asList("-g"), null, Arrays.asList(source));
- Context context = ct.getContext();
- Symtab syms = Symtab.instance(context);
- Names names = Names.instance(context);
- Types types = Types.instance(context);
- ct.addTaskListener(new Indifier(syms, names, types));
- try {
- ct.generate();
- } catch (Throwable t) {
- t.printStackTrace();
- throw new AssertionError(
- String.format("Error thrown when compiling following code\n%s",
- source.source));
- }
- if (dc.diagFound) {
- throw new AssertionError(
- String.format("Diags found when compiling following code\n%s\n\n%s",
- source.source, dc.printDiags()));
- }
- verifyBytecode(id);
- }
-
- void verifyBytecode(int id) {
- File compiledTest = new File(String.format("Test%d.class", id));
- try {
- ClassFile cf = ClassFile.read(compiledTest);
- BootstrapMethods_attribute bsm_attr =
- (BootstrapMethods_attribute)cf
- .getAttribute(Attribute.BootstrapMethods);
- int length = bsm_attr.bootstrap_method_specifiers.length;
- if (length != 1) {
- throw new Error("Bad number of method specifiers " +
- "in BootstrapMethods attribute: " + length);
- }
- } catch (Exception e) {
- e.printStackTrace();
- throw new Error("error reading " + compiledTest +": " + e);
- }
- }
-
- class JavaSource extends SimpleJavaFileObject {
-
- static final String source_template = "import java.lang.invoke.*;\n" +
- "class Bootstrap {\n" +
- " public static CallSite bsm(MethodHandles.Lookup lookup, " +
- "String name, MethodType methodType) {\n" +
- " return null;\n" +
- " }\n" +
- "}\n" +
- "class Test#ID {\n" +
- " void m1() { }\n" +
- " void m2(Object arg1) { }\n" +
- " void test1() {\n" +
- " Object o = this; // marker statement \n" +
- " m1();\n" +
- " }\n" +
- " void test2(Object arg1) {\n" +
- " Object o = this; // marker statement \n" +
- " m2(arg1);\n" +
- " }\n" +
- "}";
-
- String source;
-
- JavaSource(int id) {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
- source = source_template.replace("#ID", String.valueOf(id));
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
- }
- }
-
- class Indifier extends TreeScanner<Void, Void> implements TaskListener {
-
- MethodSymbol bsm;
- Symtab syms;
- Names names;
- Types types;
-
- Indifier(Symtab syms, Names names, Types types) {
- this.syms = syms;
- this.names = names;
- this.types = types;
- }
-
- @Override
- public void started(TaskEvent e) {
- //do nothing
- }
-
- @Override
- public void finished(TaskEvent e) {
- if (e.getKind() == TaskEvent.Kind.ANALYZE) {
- scan(e.getCompilationUnit(), null);
- }
- }
-
- @Override
- public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
- super.visitMethodInvocation(node, p);
- JCMethodInvocation apply = (JCMethodInvocation)node;
- JCIdent ident = (JCIdent)apply.meth;
- Symbol oldSym = ident.sym;
- if (!oldSym.isConstructor()) {
- ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name,
- oldSym.owner, REF_invokeStatic, bsm, oldSym.type, new Object[0]);
- }
- return null;
- }
-
- @Override
- public Void visitMethod(MethodTree node, Void p) {
- super.visitMethod(node, p);
- if (node.getName().toString().equals("bsm")) {
- bsm = ((JCMethodDecl)node).sym;
- }
- return null;
- }
- }
-
- static class DiagChecker
- implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- boolean diagFound;
- ArrayList<String> diags = new ArrayList<>();
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- diags.add(diagnostic.getMessage(Locale.getDefault()));
- diagFound = true;
- }
-
- String printDiags() {
- StringBuilder buf = new StringBuilder();
- for (String s : diags) {
- buf.append(s);
- buf.append("\n");
- }
- return buf.toString();
- }
- }
-
-}
--- a/langtools/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,53 +23,47 @@
/*
* @test
- * @bug 8002099 8006694
+ * @bug 8002099 8006694 8129962
* @summary Add support for intersection types in cast expression
* temporarily workaround combo tests are causing time out in several platforms
- * @library ../../lib
- * @modules jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm/timeout=360 IntersectionTypeCastTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+
+ * @run main IntersectionTypeCastTest
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import com.sun.tools.javac.util.List;
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaCompiler;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.ToolProvider;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
-import com.sun.source.util.JavacTask;
-import com.sun.tools.javac.util.List;
-import com.sun.tools.javac.util.ListBuffer;
+import java.io.IOException;
-public class IntersectionTypeCastTest
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
+public class IntersectionTypeCastTest extends ComboInstance<IntersectionTypeCastTest> {
- interface Type {
+ interface Type extends ComboParameter {
boolean subtypeOf(Type that);
- String asString();
boolean isClass();
boolean isInterface();
}
enum InterfaceKind implements Type {
- A("interface A { }\n", "A", null),
- B("interface B { }\n", "B", null),
- C("interface C extends A { }\n", "C", A);
+ A("A", null),
+ B("B", null),
+ C("C", A);
- String declStr;
String typeStr;
InterfaceKind superInterface;
- InterfaceKind(String declStr, String typeStr,
- InterfaceKind superInterface) {
- this.declStr = declStr;
+ InterfaceKind(String typeStr, InterfaceKind superInterface) {
this.typeStr = typeStr;
this.superInterface = superInterface;
}
@@ -81,11 +75,6 @@
}
@Override
- public String asString() {
- return typeStr;
- }
-
- @Override
public boolean isClass() {
return false;
}
@@ -94,42 +83,31 @@
public boolean isInterface() {
return true;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return typeStr;
+ }
}
enum ClassKind implements Type {
- OBJECT(null, "Object"),
- CA("#M class CA implements A { }\n", "CA",
- InterfaceKind.A),
- CB("#M class CB implements B { }\n", "CB",
- InterfaceKind.B),
- CAB("#M class CAB implements A, B { }\n", "CAB",
- InterfaceKind.A, InterfaceKind.B),
- CC("#M class CC implements C { }\n", "CC",
- InterfaceKind.C, InterfaceKind.A),
- CCA("#M class CCA implements C, A { }\n", "CCA",
- InterfaceKind.C, InterfaceKind.A),
- CCB("#M class CCB implements C, B { }\n", "CCB",
- InterfaceKind.C, InterfaceKind.A, InterfaceKind.B),
- CCAB("#M class CCAB implements C, A, B { }\n", "CCAB",
- InterfaceKind.C, InterfaceKind.A, InterfaceKind.B);
+ OBJECT("Object"),
+ CA("CA", InterfaceKind.A),
+ CB("CB", InterfaceKind.B),
+ CAB("CAB", InterfaceKind.A, InterfaceKind.B),
+ CC("CC", InterfaceKind.C, InterfaceKind.A),
+ CCA("CCA", InterfaceKind.C, InterfaceKind.A),
+ CCB("CCB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B),
+ CCAB("CCAB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B);
- String declTemplate;
String typeStr;
List<InterfaceKind> superInterfaces;
- ClassKind(String declTemplate, String typeStr,
- InterfaceKind... superInterfaces) {
- this.declTemplate = declTemplate;
+ ClassKind(String typeStr, InterfaceKind... superInterfaces) {
this.typeStr = typeStr;
this.superInterfaces = List.from(superInterfaces);
}
- String getDecl(ModifierKind mod) {
- return declTemplate != null ?
- declTemplate.replaceAll("#M", mod.modStr) :
- "";
- }
-
@Override
public boolean subtypeOf(Type that) {
return this == that || superInterfaces.contains(that) ||
@@ -137,11 +115,6 @@
}
@Override
- public String asString() {
- return typeStr;
- }
-
- @Override
public boolean isClass() {
return true;
}
@@ -150,9 +123,14 @@
public boolean isInterface() {
return false;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return typeStr;
+ }
}
- enum ModifierKind {
+ enum ModifierKind implements ComboParameter {
NONE(""),
FINAL("final");
@@ -161,14 +139,18 @@
ModifierKind(String modStr) {
this.modStr = modStr;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return modStr;
+ }
}
- enum CastKind {
- CLASS("(#C)", 0),
- INTERFACE("(#I0)", 1),
- INTERSECTION2("(#C & #I0)", 1),
- INTERSECTION3("(#C & #I0 & #I1)", 2);
- //INTERSECTION4("(#C & #I0 & #I1 & #I2)", 3);
+ enum CastKind implements ComboParameter {
+ CLASS("(#{CLAZZ#IDX})", 0),
+ INTERFACE("(#{INTF1#IDX})", 1),
+ INTERSECTION2("(#{CLAZZ#IDX} & #{INTF1#IDX})", 1),
+ INTERSECTION3("(#{CLAZZ#IDX} & #{INTF1#IDX} & #{INTF2#IDX})", 2);
String castTemplate;
int interfaceBounds;
@@ -177,6 +159,11 @@
this.castTemplate = castTemplate;
this.interfaceBounds = interfaceBounds;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return castTemplate.replaceAll("#IDX", optParameter);
+ }
}
static class CastInfo {
@@ -188,19 +175,9 @@
this.types = types;
}
- String getCast() {
- String temp = kind.castTemplate.replaceAll("#C",
- types[0].asString());
- for (int i = 0; i < kind.interfaceBounds ; i++) {
- temp = temp.replace(String.format("#I%d", i),
- types[i + 1].asString());
- }
- return temp;
- }
-
boolean hasDuplicateTypes() {
- for (int i = 0 ; i < types.length ; i++) {
- for (int j = 0 ; j < types.length ; j++) {
+ for (int i = 0 ; i < arity() ; i++) {
+ for (int j = 0 ; j < arity() ; j++) {
if (i != j && types[i] == types[j]) {
return true;
}
@@ -210,8 +187,10 @@
}
boolean compatibleWith(ModifierKind mod, CastInfo that) {
- for (Type t1 : types) {
- for (Type t2 : that.types) {
+ for (int i = 0 ; i < arity() ; i++) {
+ Type t1 = types[i];
+ for (int j = 0 ; j < that.arity() ; j++) {
+ Type t2 = that.types[j];
boolean compat =
t1.subtypeOf(t2) ||
t2.subtypeOf(t1) ||
@@ -223,138 +202,92 @@
}
return true;
}
+
+ private int arity() {
+ return kind.interfaceBounds + 1;
+ }
}
public static void main(String... args) throws Exception {
- for (ModifierKind mod : ModifierKind.values()) {
- for (CastInfo cast1 : allCastInfo()) {
- for (CastInfo cast2 : allCastInfo()) {
- pool.execute(
- new IntersectionTypeCastTest(mod, cast1, cast2));
+ new ComboTestHelper<IntersectionTypeCastTest>()
+ .withFilter(IntersectionTypeCastTest::isRedundantCast)
+ .withFilter(IntersectionTypeCastTest::arityFilter)
+ .withArrayDimension("CAST", (x, ck, idx) -> x.castKinds[idx] = ck, 2, CastKind.values())
+ .withDimension("CLAZZ1", (x, ty) -> x.types1[0] = ty, ClassKind.values())
+ .withDimension("INTF11", (x, ty) -> x.types1[1] = ty, InterfaceKind.values())
+ .withDimension("INTF21", (x, ty) -> x.types1[2] = ty, InterfaceKind.values())
+ .withDimension("CLAZZ2", (x, ty) -> x.types2[0] = ty, ClassKind.values())
+ .withDimension("INTF12", (x, ty) -> x.types2[1] = ty, InterfaceKind.values())
+ .withDimension("INTF22", (x, ty) -> x.types2[2] = ty, InterfaceKind.values())
+ .withDimension("MOD", (x, mod) -> x.mod = mod, ModifierKind.values())
+ .run(IntersectionTypeCastTest::new);
+ }
+
+ boolean isRedundantCast() {
+ for (int i = 0 ; i < 2 ; i++) {
+ Type[] types = i == 0 ? types1 : types2;
+ if (castKinds[i] == CastKind.INTERFACE && types[0] != ClassKind.OBJECT) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ boolean arityFilter() {
+ for (int i = 0 ; i < 2 ; i++) {
+ int lastPos = castKinds[i].interfaceBounds + 1;
+ Type[] types = i == 0 ? types1 : types2;
+ for (int j = 1; j < types.length; j++) {
+ boolean shouldBeSet = j < lastPos;
+ if (!shouldBeSet && (types[j] != InterfaceKind.A)) {
+ return false;
}
}
}
- checkAfterExec();
- }
-
- static List<CastInfo> allCastInfo() {
- ListBuffer<CastInfo> buf = new ListBuffer<>();
- for (CastKind kind : CastKind.values()) {
- for (ClassKind clazz : ClassKind.values()) {
- if (kind == CastKind.INTERFACE && clazz != ClassKind.OBJECT) {
- continue;
- } else if (kind.interfaceBounds == 0) {
- buf.append(new CastInfo(kind, clazz));
- continue;
- } else {
- for (InterfaceKind intf1 : InterfaceKind.values()) {
- if (kind.interfaceBounds == 1) {
- buf.append(new CastInfo(kind, clazz, intf1));
- continue;
- } else {
- for (InterfaceKind intf2 : InterfaceKind.values()) {
- if (kind.interfaceBounds == 2) {
- buf.append(
- new CastInfo(kind, clazz, intf1, intf2));
- continue;
- } else {
- for (InterfaceKind intf3 : InterfaceKind.values()) {
- buf.append(
- new CastInfo(kind, clazz, intf1,
- intf2, intf3));
- continue;
- }
- }
- }
- }
- }
- }
- }
- }
- return buf.toList();
+ return true;
}
ModifierKind mod;
- CastInfo cast1, cast2;
- JavaSource source;
- DiagnosticChecker diagChecker;
-
- IntersectionTypeCastTest(ModifierKind mod, CastInfo cast1, CastInfo cast2) {
- this.mod = mod;
- this.cast1 = cast1;
- this.cast2 = cast2;
- this.source = new JavaSource();
- this.diagChecker = new DiagnosticChecker();
- }
+ CastKind[] castKinds = new CastKind[2];
+ Type[] types1 = new Type[3];
+ Type[] types2 = new Type[3];
@Override
- public void run() {
- final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
-
- JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker,
- null, null, Arrays.asList(source));
- try {
- ct.analyze();
- } catch (Throwable ex) {
- throw new AssertionError("Error thrown when compiling the following code:\n" +
- source.getCharContent(true));
- }
- check();
+ public void doWork() throws IOException {
+ check(newCompilationTask()
+ .withSourceFromTemplate(bodyTemplate)
+ .analyze());
}
- class JavaSource extends SimpleJavaFileObject {
-
- String bodyTemplate = "class Test {\n" +
- " void test() {\n" +
- " Object o = #C1#C2null;\n" +
- " } }";
-
- String source = "";
+ String bodyTemplate = "class Test {\n" +
+ " void test() {\n" +
+ " Object o = #{CAST[0].1}#{CAST[1].2}null;\n" +
+ " } }\n" +
+ "interface A { }\n" +
+ "interface B { }\n" +
+ "interface C extends A { }\n" +
+ "#{MOD} class CA implements A { }\n" +
+ "#{MOD} class CB implements B { }\n" +
+ "#{MOD} class CAB implements A, B { }\n" +
+ "#{MOD} class CC implements C { }\n" +
+ "#{MOD} class CCA implements C, A { }\n" +
+ "#{MOD} class CCB implements C, B { }\n" +
+ "#{MOD} class CCAB implements C, A, B { }";
- public JavaSource() {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
- for (ClassKind ck : ClassKind.values()) {
- source += ck.getDecl(mod);
- }
- for (InterfaceKind ik : InterfaceKind.values()) {
- source += ik.declStr;
- }
- source += bodyTemplate.replaceAll("#C1", cast1.getCast()).
- replaceAll("#C2", cast2.getCast());
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
- }
- }
-
- void check() {
- checkCount.incrementAndGet();
-
+ void check(Result<?> res) {
+ CastInfo cast1 = new CastInfo(castKinds[0], types1);
+ CastInfo cast2 = new CastInfo(castKinds[1], types2);
boolean errorExpected = cast1.hasDuplicateTypes() ||
cast2.hasDuplicateTypes();
errorExpected |= !cast2.compatibleWith(mod, cast1);
- if (errorExpected != diagChecker.errorFound) {
- throw new Error("invalid diagnostics for source:\n" +
- source.getCharContent(true) +
- "\nFound error: " + diagChecker.errorFound +
+ boolean errorsFound = res.hasErrors();
+ if (errorExpected != errorsFound) {
+ fail("invalid diagnostics for source:\n" +
+ res.compilationInfo() +
+ "\nFound error: " + errorsFound +
"\nExpected error: " + errorExpected);
}
}
-
- static class DiagnosticChecker
- implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- boolean errorFound;
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
- errorFound = true;
- }
- }
- }
-
}
--- a/langtools/test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,40 +23,41 @@
/*
* @test
- * @bug 8005166
+ * @bug 8005166 8129962
* @summary Add support for static interface methods
* Smoke test for static interface method hiding
- * @modules jdk.compiler
- * @run main/timeout=600 InterfaceMethodHidingTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main InterfaceMethodHidingTest
*/
-import com.sun.source.util.JavacTask;
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaCompiler;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.StandardJavaFileManager;
-import javax.tools.ToolProvider;
+import java.io.IOException;
+
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
-
-public class InterfaceMethodHidingTest {
-
- static int checkCount = 0;
+public class InterfaceMethodHidingTest extends ComboInstance<InterfaceMethodHidingTest> {
- enum SignatureKind {
- VOID_INTEGER("void m(Integer s)", "return;"),
- STRING_INTEGER("String m(Integer s)", "return null;"),
- VOID_STRING("void m(String s)", "return;"),
- STRING_STRING("String m(String s)", "return null;");
+ enum SignatureKind implements ComboParameter {
+ VOID_INTEGER("void m(Integer s)", false),
+ STRING_INTEGER("String m(Integer s)", true),
+ VOID_STRING("void m(String s)", false),
+ STRING_STRING("String m(String s)", true);
String sigStr;
- String retStr;
+ boolean needsReturn;
- SignatureKind(String sigStr, String retStr) {
+ SignatureKind(String sigStr, boolean needsReturn) {
this.sigStr = sigStr;
- this.retStr = retStr;
+ this.needsReturn = needsReturn;
}
boolean overrideEquivalentWith(SignatureKind s2) {
@@ -71,18 +72,21 @@
throw new AssertionError("bad signature kind");
}
}
+
+ @Override
+ public String expand(String optParameter) {
+ return sigStr;
+ }
}
- enum MethodKind {
- VIRTUAL("", "#M #S;"),
- STATIC("static", "#M #S { #BE; #R }"),
- DEFAULT("default", "#M #S { #BE; #R }");
+ enum MethodKind implements ComboParameter {
+ VIRTUAL("#{SIG[#IDX]};"),
+ STATIC("static #{SIG[#IDX]} { #{BODY[#IDX]}; #{RET.#IDX} }"),
+ DEFAULT("default #{SIG[#IDX]} { #{BODY[#IDX]}; #{RET.#IDX} }");
- String modStr;
String methTemplate;
- MethodKind(String modStr, String methTemplate) {
- this.modStr = modStr;
+ MethodKind(String methTemplate) {
this.methTemplate = methTemplate;
}
@@ -96,15 +100,13 @@
mk1 != STATIC;
}
- String getBody(BodyExpr be, SignatureKind sk) {
- return methTemplate.replaceAll("#BE", be.bodyExprStr)
- .replaceAll("#R", sk.retStr)
- .replaceAll("#M", modStr)
- .replaceAll("#S", sk.sigStr);
+ @Override
+ public String expand(String optParameter) {
+ return methTemplate.replaceAll("#IDX", optParameter);
}
}
- enum BodyExpr {
+ enum BodyExpr implements ComboParameter {
NONE(""),
THIS("Object o = this");
@@ -118,129 +120,78 @@
return this == NONE ||
mk != MethodKind.STATIC;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return bodyExprStr;
+ }
}
public static void main(String... args) throws Exception {
-
- //create default shared JavaCompiler - reused across multiple compilations
- JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
- try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) {
-
- for (MethodKind mk1 : MethodKind.values()) {
- for (SignatureKind sk1 : SignatureKind.values()) {
- for (BodyExpr be1 : BodyExpr.values()) {
- for (MethodKind mk2 : MethodKind.values()) {
- for (SignatureKind sk2 : SignatureKind.values()) {
- for (BodyExpr be2 : BodyExpr.values()) {
- for (MethodKind mk3 : MethodKind.values()) {
- for (SignatureKind sk3 : SignatureKind.values()) {
- for (BodyExpr be3 : BodyExpr.values()) {
- new InterfaceMethodHidingTest(mk1, mk2, mk3, sk1, sk2, sk3, be1, be2, be3).run(comp, fm);
- }
- }
- }
- }
- }
- }
- }
- }
- }
- System.out.println("Total check executed: " + checkCount);
- }
+ new ComboTestHelper<InterfaceMethodHidingTest>()
+ .withArrayDimension("SIG", (x, sig, idx) -> x.signatureKinds[idx] = sig, 3, SignatureKind.values())
+ .withArrayDimension("BODY", (x, body, idx) -> x.bodyExprs[idx] = body, 3, BodyExpr.values())
+ .withArrayDimension("MET", (x, meth, idx) -> x.methodKinds[idx] = meth, 3, MethodKind.values())
+ .run(InterfaceMethodHidingTest::new);
}
- MethodKind mk1, mk2, mk3;
- SignatureKind sk1, sk2, sk3;
- BodyExpr be1, be2, be3;
- JavaSource source;
- DiagnosticChecker diagChecker;
+ MethodKind[] methodKinds = new MethodKind[3];
+ SignatureKind[] signatureKinds = new SignatureKind[3];
+ BodyExpr[] bodyExprs = new BodyExpr[3];
- InterfaceMethodHidingTest(MethodKind mk1, MethodKind mk2, MethodKind mk3,
- SignatureKind sk1, SignatureKind sk2, SignatureKind sk3, BodyExpr be1, BodyExpr be2, BodyExpr be3) {
- this.mk1 = mk1;
- this.mk2 = mk2;
- this.mk3 = mk3;
- this.sk1 = sk1;
- this.sk2 = sk2;
- this.sk3 = sk3;
- this.be1 = be1;
- this.be2 = be2;
- this.be3 = be3;
- this.source = new JavaSource();
- this.diagChecker = new DiagnosticChecker();
- }
-
- class JavaSource extends SimpleJavaFileObject {
-
- String template = "interface Sup {\n" +
+ String template = "interface Sup {\n" +
" default void sup() { }\n" +
"}\n" +
"interface A extends Sup {\n" +
- " #M1\n" +
+ " #{MET[0].0}\n" +
"}\n" +
"interface B extends A, Sup {\n" +
- " #M2\n" +
+ " #{MET[1].1}\n" +
"}\n" +
"interface C extends B, Sup {\n" +
- " #M3\n" +
+ " #{MET[2].2}\n" +
"}\n";
- String source;
+ @Override
+ public void doWork() throws IOException {
+ check(newCompilationTask()
+ .withOption("-XDallowStaticInterfaceMethods")
+ .withSourceFromTemplate(template, this::returnExpr)
+ .analyze());
+ }
- public JavaSource() {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
- source = template.replaceAll("#M1", mk1.getBody(be1, sk1))
- .replaceAll("#M2", mk2.getBody(be2, sk2))
- .replaceAll("#M3", mk3.getBody(be3, sk3));
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
+ ComboParameter returnExpr(String name) {
+ switch (name) {
+ case "RET":
+ return optParameter -> {
+ int idx = new Integer(optParameter);
+ return signatureKinds[idx].needsReturn ? "return null;" : "return;";
+ };
+ default:
+ return null;
}
}
- void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
- JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
- Arrays.asList("-XDallowStaticInterfaceMethods"), null, Arrays.asList(source));
- try {
- ct.analyze();
- } catch (Throwable ex) {
- throw new AssertionError("Error thrown when analyzing the following source:\n" + source.getCharContent(true));
- }
- check();
- }
+ void check(Result<?> res) {
+ boolean errorExpected = !bodyExprs[0].allowed(methodKinds[0]) ||
+ !bodyExprs[1].allowed(methodKinds[1]) ||
+ !bodyExprs[2].allowed(methodKinds[2]);
- void check() {
- boolean errorExpected =
- !be1.allowed(mk1) || !be2.allowed(mk2) || !be3.allowed(mk3);
-
- if (mk1.inherithed()) {
- errorExpected |=
- sk2.overrideEquivalentWith(sk1) && !MethodKind.overrides(mk2, sk2, mk1, sk1) ||
- sk3.overrideEquivalentWith(sk1) && !MethodKind.overrides(mk3, sk3, mk1, sk1);
+ if (methodKinds[0].inherithed()) {
+ errorExpected |= signatureKinds[1].overrideEquivalentWith(signatureKinds[0]) &&
+ !MethodKind.overrides(methodKinds[1], signatureKinds[1], methodKinds[0], signatureKinds[0]) ||
+ signatureKinds[2].overrideEquivalentWith(signatureKinds[0]) &&
+ !MethodKind.overrides(methodKinds[2], signatureKinds[2], methodKinds[0], signatureKinds[0]);
}
- if (mk2.inherithed()) {
- errorExpected |=
- sk3.overrideEquivalentWith(sk2) && !MethodKind.overrides(mk3, sk3, mk2, sk2);
+ if (methodKinds[1].inherithed()) {
+ errorExpected |= signatureKinds[2].overrideEquivalentWith(signatureKinds[1]) &&
+ !MethodKind.overrides(methodKinds[2], signatureKinds[2], methodKinds[1], signatureKinds[1]);
}
- checkCount++;
- if (diagChecker.errorFound != errorExpected) {
- throw new AssertionError("Problem when compiling source:\n" + source.getCharContent(true) +
- "\nfound error: " + diagChecker.errorFound);
- }
- }
-
- static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- boolean errorFound;
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
- errorFound = true;
- }
+ if (res.hasErrors() != errorExpected) {
+ fail("Problem when compiling source:\n" + res.compilationInfo() +
+ "\nfound error: " + res.hasErrors());
}
}
}
--- a/langtools/test/tools/javac/defaultMethods/super/TestDefaultSuperCall.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/defaultMethods/super/TestDefaultSuperCall.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,33 +23,32 @@
/*
* @test
- * @bug 7192246 8006694
+ * @bug 7192246 8006694 8129962
* @summary Automatic test for checking correctness of default super/this resolution
* temporarily workaround combo tests are causing time out in several platforms
- * @library ../../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm TestDefaultSuperCall
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main TestDefaultSuperCall
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
-import java.net.URI;
-import java.util.Arrays;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-
-import com.sun.source.util.JavacTask;
-public class TestDefaultSuperCall
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
- enum InterfaceKind {
+public class TestDefaultSuperCall extends ComboInstance<TestDefaultSuperCall> {
+
+ enum InterfaceKind implements ComboParameter {
DEFAULT("interface A extends B { default void m() { } }"),
ABSTRACT("interface A extends B { void m(); }"),
NONE("interface A extends B { }");
@@ -63,9 +62,14 @@
boolean methodDefined() {
return this == DEFAULT;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return interfaceStr;
+ }
}
- enum PruneKind {
+ enum PruneKind implements ComboParameter {
NO_PRUNE("interface C { }"),
PRUNE("interface C extends A { }");
@@ -79,15 +83,20 @@
PruneKind(String interfaceStr) {
this.interfaceStr = interfaceStr;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return interfaceStr;
+ }
}
- enum QualifierKind {
+ enum QualifierKind implements ComboParameter {
DIRECT_1("C"),
DIRECT_2("A"),
INDIRECT("B"),
UNRELATED("E"),
- ENCLOSING_1(null),
- ENCLOSING_2(null);
+ ENCLOSING_1("name0"),
+ ENCLOSING_2("name1");
String qualifierStr;
@@ -95,15 +104,6 @@
this.qualifierStr = qualifierStr;
}
- String getQualifier(Shape sh) {
- switch (this) {
- case ENCLOSING_1: return sh.enclosingAt(0);
- case ENCLOSING_2: return sh.enclosingAt(1);
- default:
- return qualifierStr;
- }
- }
-
boolean isEnclosing() {
return this == ENCLOSING_1 ||
this == ENCLOSING_2;
@@ -119,9 +119,14 @@
return false;
}
}
+
+ @Override
+ public String expand(String optParameter) {
+ return qualifierStr;
+ }
}
- enum ExprKind {
+ enum ExprKind implements ComboParameter {
THIS("this"),
SUPER("super");
@@ -130,19 +135,24 @@
ExprKind(String exprStr) {
this.exprStr = exprStr;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return exprStr;
+ }
}
- enum ElementKind {
- INTERFACE("interface #N { #B }", true),
- INTERFACE_EXTENDS("interface #N extends A, C { #B }", true),
- CLASS("class #N { #B }", false),
- CLASS_EXTENDS("abstract class #N implements A, C { #B }", false),
- STATIC_CLASS("static class #N { #B }", true),
- STATIC_CLASS_EXTENDS("abstract static class #N implements A, C { #B }", true),
- ANON_CLASS("new Object() { #B };", false),
- METHOD("void test() { #B }", false),
- STATIC_METHOD("static void test() { #B }", true),
- DEFAULT_METHOD("default void test() { #B }", false);
+ enum ElementKind implements ComboParameter {
+ INTERFACE("interface name#CURR { #BODY }", true),
+ INTERFACE_EXTENDS("interface name#CURR extends A, C { #BODY }", true),
+ CLASS("class name#CURR { #BODY }", false),
+ CLASS_EXTENDS("abstract class name#CURR implements A, C { #BODY }", false),
+ STATIC_CLASS("static class name#CURR { #BODY }", true),
+ STATIC_CLASS_EXTENDS("abstract static class name#CURR implements A, C { #BODY }", true),
+ ANON_CLASS("new Object() { #BODY };", false),
+ METHOD("void test() { #BODY }", false),
+ STATIC_METHOD("static void test() { #BODY }", true),
+ DEFAULT_METHOD("default void test() { #BODY }", false);
String templateDecl;
boolean isStatic;
@@ -207,11 +217,21 @@
this == STATIC_CLASS_EXTENDS ||
this == CLASS_EXTENDS;
}
+
+ @Override
+ public String expand(String optParameter) {
+ int nextDepth = new Integer(optParameter) + 1;
+ String replStr = (nextDepth <= 4) ?
+ String.format("#{ELEM[%d].%d}", nextDepth, nextDepth) :
+ "#{QUAL}.#{EXPR}.#{METH}();";
+ return templateDecl
+ .replaceAll("#CURR", optParameter)
+ .replaceAll("#BODY", replStr);
+ }
}
static class Shape {
- String shapeStr;
List<ElementKind> enclosingElements;
List<String> enclosingNames;
List<String> elementsWithMethod;
@@ -234,114 +254,73 @@
} else {
elementsWithMethod.add(prevName);
}
- String element = ek.templateDecl.replaceAll("#N", name);
- shapeStr = shapeStr ==
- null ? element : shapeStr.replaceAll("#B", element);
prevName = name;
}
}
-
- String getShape(QualifierKind qk, ExprKind ek) {
- String methName = ek == ExprKind.THIS ? "test" : "m";
- String call = qk.getQualifier(this) + "." +
- ek.exprStr + "." + methName + "();";
- return shapeStr.replaceAll("#B", call);
- }
-
- String enclosingAt(int index) {
- return index < enclosingNames.size() ?
- enclosingNames.get(index) : "BAD";
- }
}
public static void main(String... args) throws Exception {
- for (InterfaceKind ik : InterfaceKind.values()) {
- for (PruneKind pk : PruneKind.values()) {
- for (ElementKind ek1 : ElementKind.values()) {
- if (!ek1.isAllowedTop()) continue;
- for (ElementKind ek2 : ElementKind.values()) {
- if (!ek2.isAllowedEnclosing(ek1, true)) continue;
- for (ElementKind ek3 : ElementKind.values()) {
- if (!ek3.isAllowedEnclosing(ek2, false)) continue;
- for (ElementKind ek4 : ElementKind.values()) {
- if (!ek4.isAllowedEnclosing(ek3, false)) continue;
- for (ElementKind ek5 : ElementKind.values()) {
- if (!ek5.isAllowedEnclosing(ek4, false) ||
- ek5.isClassDecl()) continue;
- for (QualifierKind qk : QualifierKind.values()) {
- for (ExprKind ek : ExprKind.values()) {
- pool.execute(
- new TestDefaultSuperCall(ik, pk,
- new Shape(ek1, ek2, ek3,
- ek4, ek5), qk, ek));
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- checkAfterExec();
+ new ComboTestHelper<TestDefaultSuperCall>()
+ .withFilter(TestDefaultSuperCall::filterBadTopElement)
+ .withFilter(TestDefaultSuperCall::filterBadIntermediateElement)
+ .withFilter(TestDefaultSuperCall::filterBadTerminalElement)
+ .withDimension("INTF1", (x, ik) -> x.ik = ik, InterfaceKind.values())
+ .withDimension("INTF2", (x, pk) -> x.pk = pk, PruneKind.values())
+ .withArrayDimension("ELEM", (x, elem, idx) -> x.elements[idx] = elem, 5, ElementKind.values())
+ .withDimension("QUAL", (x, qk) -> x.qk = qk, QualifierKind.values())
+ .withDimension("EXPR", (x, ek) -> x.ek = ek, ExprKind.values())
+ .run(TestDefaultSuperCall::new);
}
InterfaceKind ik;
PruneKind pk;
- Shape sh;
+ ElementKind[] elements = new ElementKind[5];
QualifierKind qk;
ExprKind ek;
- JavaSource source;
- DiagnosticChecker diagChecker;
+
+ boolean filterBadTopElement() {
+ return elements[0].isAllowedTop();
+ }
- TestDefaultSuperCall(InterfaceKind ik, PruneKind pk, Shape sh,
- QualifierKind qk, ExprKind ek) {
- this.ik = ik;
- this.pk = pk;
- this.sh = sh;
- this.qk = qk;
- this.ek = ek;
- this.source = new JavaSource();
- this.diagChecker = new DiagnosticChecker();
+ boolean filterBadIntermediateElement() {
+ for (int i = 1 ; i < 4 ; i++) {
+ if (!elements[i].isAllowedEnclosing(elements[i - 1], i == 1)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ boolean filterBadTerminalElement() {
+ return elements[4].isAllowedEnclosing(elements[3], false) && !elements[4].isClassDecl();
}
- class JavaSource extends SimpleJavaFileObject {
-
- String template = "interface E {}\n" +
- "interface B { }\n" +
- "#I\n" +
- "#P\n" +
- "#C";
-
- String source;
+ String template = "interface E {}\n" +
+ "interface B { }\n" +
+ "#{INTF1}\n" +
+ "#{INTF2}\n" +
+ "#{ELEM[0].0}";
- public JavaSource() {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
- source = template.replaceAll("#I", ik.interfaceStr)
- .replaceAll("#P", pk.interfaceStr)
- .replaceAll("#C", sh.getShape(qk, ek));
- }
+ @Override
+ public void doWork() throws IOException {
+ check(newCompilationTask()
+ .withSourceFromTemplate(template, this::methodName)
+ .analyze());
+ }
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
+ ComboParameter methodName(String parameterName) {
+ switch (parameterName) {
+ case "METH":
+ String methodName = ek == ExprKind.THIS ? "test" : "m";
+ return new ComboParameter.Constant<String>(methodName);
+ default:
+ return null;
}
}
- public void run() {
- JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
- null, null, Arrays.asList(source));
- try {
- ct.analyze();
- } catch (Throwable ex) {
- processException(ex);
- return;
- }
- check();
- }
+ void check(Result<?> res) {
+ Shape sh = new Shape(elements);
- void check() {
boolean errorExpected = false;
boolean badEnclosing = false;
@@ -364,7 +343,7 @@
boolean found = false;
for (int i = 0; i < sh.enclosingElements.size(); i++) {
if (sh.enclosingElements.get(i) == ElementKind.ANON_CLASS) continue;
- if (sh.enclosingNames.get(i).equals(qk.getQualifier(sh))) {
+ if (sh.enclosingNames.get(i).equals(qk.qualifierStr)) {
found = sh.elementsWithMethod.contains(sh.enclosingNames.get(i));
break;
}
@@ -388,10 +367,9 @@
}
}
- checkCount.incrementAndGet();
- if (diagChecker.errorFound != errorExpected) {
- throw new AssertionError("Problem when compiling source:\n" +
- source.getCharContent(true) +
+ if (res.hasErrors() != errorExpected) {
+ fail("Problem when compiling source:\n" +
+ res.compilationInfo() +
"\nenclosingElems: " + sh.enclosingElements +
"\nenclosingNames: " + sh.enclosingNames +
"\nelementsWithMethod: " + sh.elementsWithMethod +
@@ -399,20 +377,7 @@
"\nbad this: " + badThis +
"\nbad super: " + badSuper +
"\nqual kind: " + qk +
- "\nfound error: " + diagChecker.errorFound);
+ "\nfound error: " + res.hasErrors());
}
}
-
- static class DiagnosticChecker
- implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- boolean errorFound;
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
- errorFound = true;
- }
- }
- }
-
}
--- a/langtools/test/tools/javac/failover/CheckAttributedTree.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/failover/CheckAttributedTree.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6970584 8006694 8062373
+ * @bug 6970584 8006694 8062373 8129962
* @summary assorted position errors in compiler syntax trees
* temporarily workaround combo tests are causing time out in several platforms
* @library ../lib
@@ -31,13 +31,10 @@
* jdk.compiler/com.sun.tools.javac.code
* jdk.compiler/com.sun.tools.javac.tree
* jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm CheckAttributedTree -q -r -et ERRONEOUS .
+ * @build combo.ComboTestHelper
+ * @run main CheckAttributedTree -q -r -et ERRONEOUS .
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
@@ -56,6 +53,11 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -79,18 +81,14 @@
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;
-import javax.tools.Diagnostic;
-import javax.tools.DiagnosticListener;
import javax.tools.JavaFileObject;
import com.sun.source.tree.CompilationUnitTree;
-import com.sun.source.util.JavacTask;
import com.sun.source.util.TaskEvent;
+import com.sun.source.util.TaskEvent.Kind;
import com.sun.source.util.TaskListener;
-import com.sun.tools.javac.api.JavacTaskImpl;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
-import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.tree.EndPosTable;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
@@ -101,6 +99,10 @@
import static com.sun.tools.javac.tree.JCTree.Tag.*;
+import combo.ComboTestHelper;
+import combo.ComboInstance;
+import combo.ComboTestHelper.IgnoreMode;
+
/**
* Utility and test program to check validity of tree positions for tree nodes.
* The program can be run standalone, or as a jtreg test. In standalone mode,
@@ -113,7 +115,7 @@
* covering any new language features that may be tested in this test suite.
*/
-public class CheckAttributedTree extends JavacTestingAbstractThreadedTest {
+public class CheckAttributedTree {
/**
* Main entry point.
* If test.src is set, program runs in jtreg mode, and will throw an Error
@@ -125,7 +127,6 @@
public static void main(String... args) throws Exception {
String testSrc = System.getProperty("test.src");
File baseDir = (testSrc == null) ? null : new File(testSrc);
- throwAssertionOnError = false;
boolean ok = new CheckAttributedTree().run(baseDir, args);
if (!ok) {
if (testSrc != null) // jtreg mode
@@ -160,7 +161,6 @@
quiet = true;
else if (arg.equals("-v")) {
verbose = true;
- printAll = true;
}
else if (arg.equals("-t") && i + 1 < args.length)
tags.add(args[++i]);
@@ -187,18 +187,37 @@
}
}
- for (File file: files) {
- if (file.exists())
- test(file);
- else
- error("File not found: " + file);
- }
+ ComboTestHelper<FileChecker> cth = new ComboTestHelper<>();
+ cth.withIgnoreMode(IgnoreMode.IGNORE_ALL)
+ .withFilter(FileChecker::checkFile)
+ .withDimension("FILE", (x, file) -> x.file = file, getAllFiles(files))
+ .run(FileChecker::new);
if (fileCount.get() != 1)
errWriter.println(fileCount + " files read");
- checkAfterExec(false);
+
+ if (verbose) {
+ System.out.println(errSWriter.toString());
+ }
+
+ return (gui || !cth.info().hasFailures());
+ }
- return (gui || errCount.get() == 0);
+ File[] getAllFiles(List<File> roots) throws IOException {
+ long now = System.currentTimeMillis();
+ ArrayList<File> buf = new ArrayList<>();
+ for (File file : roots) {
+ Files.walkFileTree(file.toPath(), new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ buf.add(file.toFile());
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+ long delta = System.currentTimeMillis() - now;
+ System.err.println("All files = " + buf.size() + " " + delta);
+ return buf.toArray(new File[buf.size()]);
}
/**
@@ -224,116 +243,217 @@
out.println("");
}
- /**
- * Test a file. If the file is a directory, it will be recursively scanned
- * for java files.
- * @param file the file or directory to test
- */
- void test(final File file) {
- if (excludeFiles.contains(file)) {
- if (!quiet)
- error("File " + file + " excluded");
- return;
+ class FileChecker extends ComboInstance<FileChecker> {
+
+ File file;
+
+ boolean checkFile() {
+ if (!file.exists()) {
+ error("File not found: " + file);
+ return false;
+ }
+ if (excludeFiles.contains(file)) {
+ if (!quiet)
+ error("File " + file + " excluded");
+ return false;
+ }
+ if (!file.getName().endsWith(".java")) {
+ if (!quiet)
+ error("File " + file + " ignored");
+ return false;
+ }
+
+ return true;
}
- if (file.isDirectory()) {
- for (File f: file.listFiles()) {
- test(f);
+ public void doWork() {
+ if (!file.exists()) {
+ error("File not found: " + file);
+ }
+ if (excludeFiles.contains(file)) {
+ if (!quiet)
+ error("File " + file + " excluded");
+ return;
+ }
+ if (!file.getName().endsWith(".java")) {
+ if (!quiet)
+ error("File " + file + " ignored");
+ }
+ try {
+ if (verbose)
+ errWriter.println(file);
+ fileCount.incrementAndGet();
+ NPETester p = new NPETester();
+ p.test(read(file));
+ } catch (AttributionException e) {
+ if (!quiet) {
+ error("Error attributing " + file + "\n" + e.getMessage());
+ }
+ } catch (IOException e) {
+ error("Error reading " + file + ": " + e);
}
- return;
+ }
+
+ /**
+ * Read a file.
+ * @param file the file to be read
+ * @return the tree for the content of the file
+ * @throws IOException if any IO errors occur
+ * @throws AttributionException if any errors occur while analyzing the file
+ */
+ List<Pair<JCCompilationUnit, JCTree>> read(File file) throws IOException, AttributionException {
+ try {
+ Iterable<? extends JavaFileObject> files = fileManager().getJavaFileObjects(file);
+ final List<Element> analyzedElems = new ArrayList<>();
+ final List<CompilationUnitTree> trees = new ArrayList<>();
+ Iterable<? extends Element> elems = newCompilationTask()
+ .withWriter(pw)
+ .withOption("-XDshouldStopPolicy=ATTR")
+ .withOption("-XDverboseCompilePolicy")
+ .withSource(files.iterator().next())
+ .withListener(new TaskListener() {
+ public void started(TaskEvent e) {
+ if (e.getKind() == TaskEvent.Kind.ANALYZE)
+ analyzedElems.add(e.getTypeElement());
+ }
+
+ public void finished(TaskEvent e) {
+ if (e.getKind() == Kind.PARSE)
+ trees.add(e.getCompilationUnit());
+ }
+ }).analyze().get();
+ if (!elems.iterator().hasNext())
+ throw new AttributionException("No results from analyze");
+ List<Pair<JCCompilationUnit, JCTree>> res = new ArrayList<>();
+ for (CompilationUnitTree t : trees) {
+ JCCompilationUnit cu = (JCCompilationUnit)t;
+ for (JCTree def : cu.defs) {
+ if (def.hasTag(CLASSDEF) &&
+ analyzedElems.contains(((JCTree.JCClassDecl)def).sym)) {
+ res.add(new Pair<>(cu, def));
+ }
+ }
+ }
+ return res;
+ }
+ catch (Throwable t) {
+ throw new AttributionException("Exception while attributing file: " + file);
+ }
}
- if (file.isFile() && file.getName().endsWith(".java")) {
- pool.execute(new Runnable() {
- @Override
- public void run() {
+ /**
+ * Report an error. When the program is complete, the program will either
+ * exit or throw an Error if any errors have been reported.
+ * @param msg the error message
+ */
+ void error(String msg) {
+ System.err.println();
+ System.err.println(msg);
+ System.err.println();
+ fail(msg);
+ }
+
+ /**
+ * Main class for testing assertions concerning types/symbol
+ * left uninitialized after attribution
+ */
+ private class NPETester extends TreeScanner {
+ void test(List<Pair<JCCompilationUnit, JCTree>> trees) {
+ for (Pair<JCCompilationUnit, JCTree> p : trees) {
+ sourcefile = p.fst.sourcefile;
+ endPosTable = p.fst.endPositions;
+ encl = new Info(p.snd, endPosTable);
+ p.snd.accept(this);
+ }
+ }
+
+ @Override
+ public void scan(JCTree tree) {
+ if (tree == null ||
+ excludeTags.contains(treeUtil.nameFromTag(tree.getTag()))) {
+ return;
+ }
+
+ Info self = new Info(tree, endPosTable);
+ if (mandatoryType(tree)) {
+ check(tree.type != null,
+ "'null' field 'type' found in tree ", self);
+ if (tree.type==null)
+ Thread.dumpStack();
+ }
+
+ Field errField = checkFields(tree);
+ if (errField!=null) {
+ check(false,
+ "'null' field '" + errField.getName() + "' found in tree ", self);
+ }
+
+ Info prevEncl = encl;
+ encl = self;
+ tree.accept(this);
+ encl = prevEncl;
+ }
+
+ private boolean mandatoryType(JCTree that) {
+ return that instanceof JCTree.JCExpression ||
+ that.hasTag(VARDEF) ||
+ that.hasTag(METHODDEF) ||
+ that.hasTag(CLASSDEF);
+ }
+
+ private final List<String> excludedFields = Arrays.asList("varargsElement", "targetType");
+
+ void check(boolean ok, String label, Info self) {
+ if (!ok) {
+ if (gui) {
+ if (viewer == null)
+ viewer = new Viewer();
+ viewer.addEntry(sourcefile, label, encl, self);
+ }
+ error(label + self.toString() + " encl: " + encl.toString() +
+ " in file: " + sourcefile + " " + self.tree);
+ }
+ }
+
+ Field checkFields(JCTree t) {
+ List<Field> fieldsToCheck = treeUtil.getFieldsOfType(t,
+ excludedFields,
+ Symbol.class,
+ Type.class);
+ for (Field f : fieldsToCheck) {
try {
- if (verbose)
- errWriter.println(file);
- fileCount.incrementAndGet();
- NPETester p = new NPETester();
- p.test(read(file));
- } catch (AttributionException e) {
- if (!quiet) {
- error("Error attributing " + file + "\n" + e.getMessage());
+ if (f.get(t) == null) {
+ return f;
}
- } catch (IOException e) {
- error("Error reading " + file + ": " + e);
+ }
+ catch (IllegalAccessException e) {
+ System.err.println("Cannot read field: " + f);
+ //swallow it
}
}
- });
- return;
+ return null;
+ }
+
+ @Override
+ public void visitImport(JCImport tree) { }
+
+ @Override
+ public void visitTopLevel(JCCompilationUnit tree) {
+ scan(tree.defs);
+ }
+
+ JavaFileObject sourcefile;
+ EndPosTable endPosTable;
+ Info encl;
}
-
- if (!quiet)
- error("File " + file + " ignored");
}
// See CR: 6982992 Tests CheckAttributedTree.java, JavacTreeScannerTest.java, and SourceTreeeScannerTest.java timeout
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
- Reporter r = new Reporter(pw);
- /**
- * Read a file.
- * @param file the file to be read
- * @return the tree for the content of the file
- * @throws IOException if any IO errors occur
- * @throws AttributionException if any errors occur while analyzing the file
- */
- List<Pair<JCCompilationUnit, JCTree>> read(File file) throws IOException, AttributionException {
- r.errors = 0;
- Iterable<? extends JavaFileObject> files = fm.get().getJavaFileObjects(file);
- String[] opts = { "-XDshouldStopPolicy=ATTR", "-XDverboseCompilePolicy" };
- JavacTask task = (JavacTask)comp.getTask(pw, fm.get(), r, Arrays.asList(opts), null, files);
- final List<Element> analyzedElems = new ArrayList<>();
- task.setTaskListener(new TaskListener() {
- public void started(TaskEvent e) {
- if (e.getKind() == TaskEvent.Kind.ANALYZE)
- analyzedElems.add(e.getTypeElement());
- }
- public void finished(TaskEvent e) { }
- });
- int i = 0;
- try {
- Iterable<? extends CompilationUnitTree> trees = task.parse();
-// JavaCompiler c = JavaCompiler.instance(((JavacTaskImpl) task).getContext());
-// System.err.println("verboseCompilePolicy: " + c.verboseCompilePolicy);
-// System.err.println("shouldStopIfError: " + c.shouldStopPolicyIfError);
-// System.err.println("shouldStopIfNoError: " + c.shouldStopPolicyIfNoError);
- Iterable<? extends Element> elems = task.analyze();
- if (!elems.iterator().hasNext())
- throw new AttributionException("No results from analyze");
- List<Pair<JCCompilationUnit, JCTree>> res = new ArrayList<>();
- //System.err.println("Try to add pairs. Elems are " + analyzedElems);
- for (CompilationUnitTree t : trees) {
- JCCompilationUnit cu = (JCCompilationUnit)t;
- for (JCTree def : cu.defs) {
- if (def.hasTag(CLASSDEF) &&
- analyzedElems.contains(((JCTree.JCClassDecl)def).sym)) {
- //System.err.println("Adding pair..." + cu.sourcefile + " " + ((JCTree.JCClassDecl) def).name);
- res.add((i++ % 2) == 0 ? new Pair<>(cu, def) {} : new Pair<>(cu, def));
- }
- }
- }
- return res;
- }
- catch (Throwable t) {
- throw new AttributionException("Exception while attributing file: " + file);
- }
- }
-
- /**
- * Report an error. When the program is complete, the program will either
- * exit or throw an Error if any errors have been reported.
- * @param msg the error message
- */
- void error(String msg) {
- System.err.println();
- System.err.println(msg);
- System.err.println();
- errCount.incrementAndGet();
- }
+ StringWriter errSWriter = new StringWriter();
+ PrintWriter errWriter = new PrintWriter(errSWriter);
/** Flag: don't report irrelevant files. */
boolean quiet;
@@ -356,101 +476,6 @@
TreeUtil treeUtil = new TreeUtil();
/**
- * Main class for testing assertions concerning types/symbol
- * left uninitialized after attribution
- */
- private class NPETester extends TreeScanner {
- void test(List<Pair<JCCompilationUnit, JCTree>> trees) {
- for (Pair<JCCompilationUnit, JCTree> p : trees) {
-// System.err.println("checking " + p.fst.sourcefile);
- sourcefile = p.fst.sourcefile;
- endPosTable = p.fst.endPositions;
- encl = new Info(p.snd, endPosTable);
- p.snd.accept(this);
- }
- }
-
- @Override
- public void scan(JCTree tree) {
- if (tree == null ||
- excludeTags.contains(treeUtil.nameFromTag(tree.getTag()))) {
- return;
- }
-
- Info self = new Info(tree, endPosTable);
- if (mandatoryType(tree)) {
- check(tree.type != null,
- "'null' field 'type' found in tree ", self);
- if (tree.type==null)
- Thread.dumpStack();
- }
-
- Field errField = checkFields(tree);
- if (errField!=null) {
- check(false,
- "'null' field '" + errField.getName() + "' found in tree ", self);
- }
-
- Info prevEncl = encl;
- encl = self;
- tree.accept(this);
- encl = prevEncl;
- }
-
- private boolean mandatoryType(JCTree that) {
- return that instanceof JCTree.JCExpression ||
- that.hasTag(VARDEF) ||
- that.hasTag(METHODDEF) ||
- that.hasTag(CLASSDEF);
- }
-
- private final List<String> excludedFields = Arrays.asList("varargsElement", "targetType");
-
- void check(boolean ok, String label, Info self) {
- if (!ok) {
- if (gui) {
- if (viewer == null)
- viewer = new Viewer();
- viewer.addEntry(sourcefile, label, encl, self);
- }
- error(label + self.toString() + " encl: " + encl.toString() +
- " in file: " + sourcefile + " " + self.tree);
- }
- }
-
- Field checkFields(JCTree t) {
- List<Field> fieldsToCheck = treeUtil.getFieldsOfType(t,
- excludedFields,
- Symbol.class,
- Type.class);
- for (Field f : fieldsToCheck) {
- try {
- if (f.get(t) == null) {
- return f;
- }
- }
- catch (IllegalAccessException e) {
- System.err.println("Cannot read field: " + f);
- //swallow it
- }
- }
- return null;
- }
-
- @Override
- public void visitImport(JCImport tree) { }
-
- @Override
- public void visitTopLevel(JCCompilationUnit tree) {
- scan(tree.defs);
- }
-
- JavaFileObject sourcefile;
- EndPosTable endPosTable;
- Info encl;
- }
-
- /**
* Utility class providing easy access to position and other info for a tree node.
*/
private class Info {
@@ -524,25 +549,6 @@
}
/**
- * DiagnosticListener to report diagnostics and count any errors that occur.
- */
- private static class Reporter implements DiagnosticListener<JavaFileObject> {
- Reporter(PrintWriter out) {
- this.out = out;
- }
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- //out.println(diagnostic);
- switch (diagnostic.getKind()) {
- case ERROR:
- errors++;
- }
- }
- int errors;
- PrintWriter out;
- }
-
- /**
* GUI viewer for issues found by TreePosTester. The viewer provides a drop
* down list for selecting error conditions, a header area providing details
* about an error, and a text area with the ranges of text highlighted as
--- a/langtools/test/tools/javac/generics/diamond/7046778/DiamondAndInnerClassTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/generics/diamond/7046778/DiamondAndInnerClassTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,30 +23,32 @@
/*
* @test
- * @bug 7046778 8006694
+ * @bug 7046778 8006694 8129962
* @summary Project Coin: problem with diamond and member inner classes
* temporarily workaround combo tests are causing time out in several platforms
- * @library ../../../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm DiamondAndInnerClassTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @compile -Xlint:all DiamondAndInnerClassTest.java
+ * @run main DiamondAndInnerClassTest
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
-import com.sun.source.util.JavacTask;
-import java.net.URI;
+import java.io.IOException;
import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-public class DiamondAndInnerClassTest
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
+import combo.ComboTestHelper;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
- enum TypeArgumentKind {
+public class DiamondAndInnerClassTest extends ComboInstance<DiamondAndInnerClassTest> {
+
+ enum TypeArgumentKind implements ComboParameter {
NONE(""),
STRING("<String>"),
INTEGER("<Integer>"),
@@ -54,7 +56,7 @@
String typeargStr;
- private TypeArgumentKind(String typeargStr) {
+ TypeArgumentKind(String typeargStr) {
this.typeargStr = typeargStr;
}
@@ -75,252 +77,173 @@
default: throw new AssertionError("Unexpected decl kind: " + this);
}
}
+
+ @Override
+ public String expand(String optParameter) {
+ return typeargStr;
+ }
}
- enum ArgumentKind {
+ enum ArgumentKind implements ComboParameter {
OBJECT("(Object)null"),
STRING("(String)null"),
INTEGER("(Integer)null");
String argStr;
- private ArgumentKind(String argStr) {
+ ArgumentKind(String argStr) {
this.argStr = argStr;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return argStr;
+ }
}
- enum TypeQualifierArity {
- ONE(1, "A1#TA1"),
- TWO(2, "A1#TA1.A2#TA2"),
- THREE(3, "A1#TA1.A2#TA2.A3#TA3");
+ enum TypeQualifierArity implements ComboParameter {
+ ONE(1, "A1#{TA#IDX[0]}"),
+ TWO(2, "A1#{TA#IDX[0]}.A2#{TA#IDX[1]}"),
+ THREE(3, "A1#{TA#IDX[0]}.A2#{TA#IDX[1]}.A3#{TA#IDX[2]}");
int n;
String qualifierStr;
- private TypeQualifierArity(int n, String qualifierStr) {
+ TypeQualifierArity(int n, String qualifierStr) {
this.n = n;
this.qualifierStr = qualifierStr;
}
- String getType(TypeArgumentKind... typeArgumentKinds) {
- String res = qualifierStr;
- for (int i = 1 ; i <= typeArgumentKinds.length ; i++) {
- res = res.replace("#TA" + i, typeArgumentKinds[i-1].typeargStr);
- }
- return res;
- }
-
- boolean matches(InnerClassDeclArity innerClassDeclArity) {
- return n ==innerClassDeclArity.n;
+ @Override
+ public String expand(String optParameter) {
+ return qualifierStr.replaceAll("#IDX", optParameter);
}
}
- enum InnerClassDeclArity {
- ONE(1, "class A1<X> { A1(X x1) { } #B }"),
- TWO(2, "class A1<X1> { class A2<X2> { A2(X1 x1, X2 x2) { } #B } }"),
- THREE(3, "class A1<X1> { class A2<X2> { class A3<X3> { A3(X1 x1, X2 x2, X3 x3) { } #B } } }");
+ enum InnerClassDeclArity implements ComboParameter {
+ ONE(1, "class A1<X> { A1(X x1) { } #{BODY} }"),
+ TWO(2, "class A1<X1> { class A2<X2> { A2(X1 x1, X2 x2) { } #{BODY} } }"),
+ THREE(3, "class A1<X1> { class A2<X2> { class A3<X3> { A3(X1 x1, X2 x2, X3 x3) { } #{BODY} } } }");
int n;
String classDeclStr;
- private InnerClassDeclArity(int n, String classDeclStr) {
+ InnerClassDeclArity(int n, String classDeclStr) {
this.n = n;
this.classDeclStr = classDeclStr;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return classDeclStr;
+ }
}
- enum ArgumentListArity {
- ONE(1, "(#A1)"),
- TWO(2, "(#A1,#A2)"),
- THREE(3, "(#A1,#A2,#A3)");
+ enum ArgumentListArity implements ComboParameter {
+ ONE(1, "(#{A[0]})"),
+ TWO(2, "(#{A[0]},#{A[1]})"),
+ THREE(3, "(#{A[0]},#{A[1]},#{A[2]})");
int n;
String argListStr;
- private ArgumentListArity(int n, String argListStr) {
+ ArgumentListArity(int n, String argListStr) {
this.n = n;
this.argListStr = argListStr;
}
- String getArgs(ArgumentKind... argumentKinds) {
- String res = argListStr;
- for (int i = 1 ; i <= argumentKinds.length ; i++) {
- res = res.replace("#A" + i, argumentKinds[i-1].argStr);
- }
- return res;
- }
-
- boolean matches(InnerClassDeclArity innerClassDeclArity) {
- return n ==innerClassDeclArity.n;
+ @Override
+ public String expand(String optParameter) {
+ return argListStr.replaceAll("#IDX", optParameter);
}
}
public static void main(String... args) throws Exception {
- for (InnerClassDeclArity innerClassDeclArity : InnerClassDeclArity.values()) {
- for (TypeQualifierArity declType : TypeQualifierArity.values()) {
- if (!declType.matches(innerClassDeclArity)) continue;
- for (TypeQualifierArity newClassType : TypeQualifierArity.values()) {
- if (!newClassType.matches(innerClassDeclArity)) continue;
- for (ArgumentListArity argList : ArgumentListArity.values()) {
- if (!argList.matches(innerClassDeclArity)) continue;
- for (TypeArgumentKind taDecl1 : TypeArgumentKind.values()) {
- boolean isDeclRaw = taDecl1 == TypeArgumentKind.NONE;
- //no diamond on decl site
- if (taDecl1 == TypeArgumentKind.DIAMOND) continue;
- for (TypeArgumentKind taSite1 : TypeArgumentKind.values()) {
- boolean isSiteRaw =
- taSite1 == TypeArgumentKind.NONE;
- //diamond only allowed on the last type qualifier
- if (taSite1 == TypeArgumentKind.DIAMOND &&
- innerClassDeclArity !=
- InnerClassDeclArity.ONE)
- continue;
- for (ArgumentKind arg1 : ArgumentKind.values()) {
- if (innerClassDeclArity == innerClassDeclArity.ONE) {
- pool.execute(
- new DiamondAndInnerClassTest(
- innerClassDeclArity, declType,
- newClassType, argList,
- new TypeArgumentKind[] {taDecl1},
- new TypeArgumentKind[] {taSite1},
- new ArgumentKind[] {arg1}));
- continue;
- }
- for (TypeArgumentKind taDecl2 : TypeArgumentKind.values()) {
- //no rare types
- if (isDeclRaw != (taDecl2 == TypeArgumentKind.NONE))
- continue;
- //no diamond on decl site
- if (taDecl2 == TypeArgumentKind.DIAMOND)
- continue;
- for (TypeArgumentKind taSite2 : TypeArgumentKind.values()) {
- //no rare types
- if (isSiteRaw != (taSite2 == TypeArgumentKind.NONE))
- continue;
- //diamond only allowed on the last type qualifier
- if (taSite2 == TypeArgumentKind.DIAMOND &&
- innerClassDeclArity != InnerClassDeclArity.TWO)
- continue;
- for (ArgumentKind arg2 : ArgumentKind.values()) {
- if (innerClassDeclArity == innerClassDeclArity.TWO) {
- pool.execute(
- new DiamondAndInnerClassTest(
- innerClassDeclArity,
- declType,
- newClassType,
- argList,
- new TypeArgumentKind[] {taDecl1, taDecl2},
- new TypeArgumentKind[] {taSite1, taSite2},
- new ArgumentKind[] {arg1, arg2}));
- continue;
- }
- for (TypeArgumentKind taDecl3 : TypeArgumentKind.values()) {
- //no rare types
- if (isDeclRaw != (taDecl3 == TypeArgumentKind.NONE))
- continue;
- //no diamond on decl site
- if (taDecl3 == TypeArgumentKind.DIAMOND)
- continue;
- for (TypeArgumentKind taSite3 : TypeArgumentKind.values()) {
- //no rare types
- if (isSiteRaw != (taSite3 == TypeArgumentKind.NONE))
- continue;
- //diamond only allowed on the last type qualifier
- if (taSite3 == TypeArgumentKind.DIAMOND &&
- innerClassDeclArity != InnerClassDeclArity.THREE)
- continue;
- for (ArgumentKind arg3 : ArgumentKind.values()) {
- if (innerClassDeclArity ==
- innerClassDeclArity.THREE) {
- pool.execute(
- new DiamondAndInnerClassTest(
- innerClassDeclArity,
- declType,
- newClassType,
- argList,
- new TypeArgumentKind[] {taDecl1, taDecl2, taDecl3},
- new TypeArgumentKind[] {taSite1, taSite2, taSite3},
- new ArgumentKind[] {arg1, arg2, arg3}));
- continue;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
+ new ComboTestHelper<DiamondAndInnerClassTest>()
+ .withFilter(DiamondAndInnerClassTest::rareTypesFilter)
+ .withFilter(DiamondAndInnerClassTest::noDiamondOnDecl)
+ .withFilter(DiamondAndInnerClassTest::noDiamondOnIntermediateTypes)
+ .withFilter(DiamondAndInnerClassTest::arityMismatch)
+ .withFilter(DiamondAndInnerClassTest::redundantFilter)
+ .withDimension("BODY", new ComboParameter.Constant<>("#{D.1} res = new #{S.2}#{AL};"))
+ .withDimension("DECL", (x, arity) -> x.innerClassDeclArity = arity, InnerClassDeclArity.values())
+ .withDimension("D", (x, arity) -> x.declArity = arity, TypeQualifierArity.values())
+ .withDimension("S", (x, arity) -> x.siteArity = arity, TypeQualifierArity.values())
+ .withDimension("AL", (x, alist) -> x.argumentListArity = alist, ArgumentListArity.values())
+ .withArrayDimension("TA1", (x, targs, idx) -> x.declTypeArgumentKinds[idx] = targs, 3, TypeArgumentKind.values())
+ .withArrayDimension("TA2", (x, targs, idx) -> x.siteTypeArgumentKinds[idx] = targs, 3, TypeArgumentKind.values())
+ .withArrayDimension("A", (x, argsk, idx) -> x.argumentKinds[idx] = argsk, 3, ArgumentKind.values())
+ .run(DiamondAndInnerClassTest::new);
+ }
+
+ InnerClassDeclArity innerClassDeclArity;
+ TypeQualifierArity declArity;
+ TypeQualifierArity siteArity;
+ TypeArgumentKind[] declTypeArgumentKinds = new TypeArgumentKind[3];
+ TypeArgumentKind[] siteTypeArgumentKinds = new TypeArgumentKind[3];
+ ArgumentKind[] argumentKinds = new ArgumentKind[3];
+ ArgumentListArity argumentListArity;
+
+ boolean rareTypesFilter() {
+ for (TypeArgumentKind[] types : Arrays.asList(declTypeArgumentKinds, siteTypeArgumentKinds)) {
+ boolean isRaw = types[0] == TypeArgumentKind.NONE;
+ for (int i = 1; i < innerClassDeclArity.n; i++) {
+ if (isRaw != (types[i] == TypeArgumentKind.NONE)) {
+ return false;
}
}
}
+ return true;
+ }
- checkAfterExec();
+ boolean noDiamondOnDecl() {
+ for (int i = 0; i < innerClassDeclArity.n; i++) {
+ if (declTypeArgumentKinds[i] == TypeArgumentKind.DIAMOND) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ boolean noDiamondOnIntermediateTypes() {
+ for (int i = 0; i < (innerClassDeclArity.n - 1); i++) {
+ if (siteTypeArgumentKinds[i] == TypeArgumentKind.DIAMOND) {
+ return false;
+ }
+ }
+ return true;
}
- InnerClassDeclArity innerClassDeclArity;
- TypeQualifierArity declType;
- TypeQualifierArity siteType;
- ArgumentListArity argList;
- TypeArgumentKind[] declTypeArgumentKinds;
- TypeArgumentKind[] siteTypeArgumentKinds;
- ArgumentKind[] argumentKinds;
- JavaSource source;
- DiagnosticChecker diagChecker;
-
- DiamondAndInnerClassTest(InnerClassDeclArity innerClassDeclArity,
- TypeQualifierArity declType, TypeQualifierArity siteType,
- ArgumentListArity argList, TypeArgumentKind[] declTypeArgumentKinds,
- TypeArgumentKind[] siteTypeArgumentKinds, ArgumentKind[] argumentKinds) {
- this.innerClassDeclArity = innerClassDeclArity;
- this.declType = declType;
- this.siteType = siteType;
- this.argList = argList;
- this.declTypeArgumentKinds = declTypeArgumentKinds;
- this.siteTypeArgumentKinds = siteTypeArgumentKinds;
- this.argumentKinds = argumentKinds;
- this.source = new JavaSource();
- this.diagChecker = new DiagnosticChecker();
+ boolean redundantFilter() {
+ for (TypeArgumentKind[] types : Arrays.asList(declTypeArgumentKinds, siteTypeArgumentKinds)) {
+ for (int i = innerClassDeclArity.n; i < types.length; i++) {
+ if (types[i].ordinal() != 0) {
+ return false;
+ }
+ }
+ }
+ for (int i = innerClassDeclArity.n; i < argumentKinds.length; i++) {
+ if (argumentKinds[i].ordinal() != 0) {
+ return false;
+ }
+ }
+ return true;
}
- class JavaSource extends SimpleJavaFileObject {
-
- String bodyTemplate = "#D res = new #S#AL;";
-
- String source;
-
- public JavaSource() {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
- source = innerClassDeclArity.classDeclStr.replace("#B", bodyTemplate)
- .replace("#D", declType.getType(declTypeArgumentKinds))
- .replace("#S", siteType.getType(siteTypeArgumentKinds))
- .replace("#AL", argList.getArgs(argumentKinds));
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
- }
+ boolean arityMismatch() {
+ return argumentListArity.n == innerClassDeclArity.n &&
+ siteArity.n == innerClassDeclArity.n &&
+ declArity.n == innerClassDeclArity.n;
}
@Override
- public void run() {
- JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
- null, null, Arrays.asList(source));
- try {
- ct.analyze();
- } catch (Throwable ex) {
- throw new AssertionError("Error thrown when compiling the following code:\n" +
- source.getCharContent(true));
- }
- check();
+ public void doWork() throws IOException {
+ check(newCompilationTask()
+ .withSourceFromTemplate("#{DECL}")
+ .analyze());
}
- void check() {
- checkCount.incrementAndGet();
-
+ void check(Result<?> res) {
boolean errorExpected = false;
TypeArgumentKind[] expectedArgKinds =
@@ -345,24 +268,11 @@
}
}
- if (errorExpected != diagChecker.errorFound) {
- throw new Error("invalid diagnostics for source:\n" +
- source.getCharContent(true) +
- "\nFound error: " + diagChecker.errorFound +
+ if (errorExpected != res.hasErrors()) {
+ fail("invalid diagnostics for source:\n" +
+ res.compilationInfo() +
+ "\nFound error: " + res.hasErrors() +
"\nExpected error: " + errorExpected);
}
}
-
- static class DiagnosticChecker
- implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- boolean errorFound;
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
- errorFound = true;
- }
- }
- }
-
}
--- a/langtools/test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,29 +23,29 @@
/*
* @test
- * @bug 7062745 8006694
+ * @bug 7062745 8006694 8129962
* @summary Regression: difference in overload resolution when two methods
* are maximally specific
* temporarily workaround combo tests are causing time out in several platforms
- * @library ../../../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm GenericOverrideTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main GenericOverrideTest
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import com.sun.source.util.JavacTask;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
-public class GenericOverrideTest
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
+public class GenericOverrideTest extends ComboInstance<GenericOverrideTest> {
enum SourceLevel {
SOURCE_7("-source", "7"),
@@ -58,24 +58,29 @@
}
}
- enum SignatureKind {
+ enum SignatureKind implements ComboParameter {
NON_GENERIC(""),
GENERIC("<X>");
String paramStr;
- private SignatureKind(String paramStr) {
+ SignatureKind(String paramStr) {
this.paramStr = paramStr;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return paramStr;
+ }
}
- enum ReturnTypeKind {
+ enum ReturnTypeKind implements ComboParameter {
LIST("List"),
ARRAYLIST("ArrayList");
String retStr;
- private ReturnTypeKind(String retStr) {
+ ReturnTypeKind(String retStr) {
this.retStr = retStr;
}
@@ -88,9 +93,14 @@
default: throw new AssertionError("Unexpected ret kind: " + this);
}
}
+
+ @Override
+ public String expand(String optParameter) {
+ return retStr;
+ }
}
- enum TypeArgumentKind {
+ enum TypeArgumentKind implements ComboParameter {
NONE(""),
UNBOUND("<?>"),
INTEGER("<Number>"),
@@ -99,7 +109,7 @@
String typeargStr;
- private TypeArgumentKind(String typeargStr) {
+ TypeArgumentKind(String typeargStr) {
this.typeargStr = typeargStr;
}
@@ -141,136 +151,79 @@
default: throw new AssertionError("Unexpected typearg kind: " + this);
}
}
+
+ @Override
+ public String expand(String optParameter) {
+ return typeargStr;
+ }
}
public static void main(String... args) throws Exception {
- for (SignatureKind sig1 : SignatureKind.values()) {
- for (ReturnTypeKind rt1 : ReturnTypeKind.values()) {
- for (TypeArgumentKind ta1 : TypeArgumentKind.values()) {
- if (!ta1.compatibleWith(sig1)) continue;
- for (SignatureKind sig2 : SignatureKind.values()) {
- for (ReturnTypeKind rt2 : ReturnTypeKind.values()) {
- for (TypeArgumentKind ta2 : TypeArgumentKind.values()) {
- if (!ta2.compatibleWith(sig2)) continue;
- for (ReturnTypeKind rt3 : ReturnTypeKind.values()) {
- for (TypeArgumentKind ta3 : TypeArgumentKind.values()) {
- if (!ta3.compatibleWith(SignatureKind.NON_GENERIC))
- continue;
- for (SourceLevel level : SourceLevel.values()) {
- pool.execute(
- new GenericOverrideTest(sig1,
- rt1, ta1, sig2, rt2,
- ta2, rt3, ta3, level));
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- checkAfterExec();
+ new ComboTestHelper<GenericOverrideTest>()
+ .withFilter(GenericOverrideTest::argMismatchFilter)
+ .withDimension("SOURCE", (x, level) -> x.level = level, SourceLevel.values())
+ .withArrayDimension("SIG", (x, sig, idx) -> x.sigs[idx] = sig, 2, SignatureKind.values())
+ .withArrayDimension("TARG", (x, targ, idx) -> x.targs[idx] = targ, 3, TypeArgumentKind.values())
+ .withArrayDimension("RET", (x, ret, idx) -> x.rets[idx] = ret, 3, ReturnTypeKind.values())
+ .run(GenericOverrideTest::new);
}
- SignatureKind sig1, sig2;
- ReturnTypeKind rt1, rt2, rt3;
- TypeArgumentKind ta1, ta2, ta3;
+ SignatureKind[] sigs = new SignatureKind[2];
+ ReturnTypeKind[] rets = new ReturnTypeKind[3];
+ TypeArgumentKind[] targs = new TypeArgumentKind[3];
SourceLevel level;
- JavaSource source;
- DiagnosticChecker diagChecker;
- GenericOverrideTest(SignatureKind sig1, ReturnTypeKind rt1, TypeArgumentKind ta1,
- SignatureKind sig2, ReturnTypeKind rt2, TypeArgumentKind ta2,
- ReturnTypeKind rt3, TypeArgumentKind ta3, SourceLevel level) {
- this.sig1 = sig1;
- this.sig2 = sig2;
- this.rt1 = rt1;
- this.rt2 = rt2;
- this.rt3 = rt3;
- this.ta1 = ta1;
- this.ta2 = ta2;
- this.ta3 = ta3;
- this.level = level;
- this.source = new JavaSource();
- this.diagChecker = new DiagnosticChecker();
+ boolean argMismatchFilter() {
+ return targs[0].compatibleWith(sigs[0]) &&
+ targs[1].compatibleWith(sigs[1]) &&
+ targs[2].compatibleWith(SignatureKind.NON_GENERIC);
}
- class JavaSource extends SimpleJavaFileObject {
-
- String template = "import java.util.*;\n" +
- "interface A { #S1 #R1#TA1 m(); }\n" +
- "interface B { #S2 #R2#TA2 m(); }\n" +
- "interface AB extends A, B {}\n" +
- "class Test {\n" +
- " void test(AB ab) { #R3#TA3 n = ab.m(); }\n" +
- "}";
-
- String source;
+ String template = "import java.util.*;\n" +
+ "interface A { #{SIG[0]} #{RET[0]}#{TARG[0]} m(); }\n" +
+ "interface B { #{SIG[1]} #{RET[1]}#{TARG[1]} m(); }\n" +
+ "interface AB extends A, B {}\n" +
+ "class Test {\n" +
+ " void test(AB ab) { #{RET[2]}#{TARG[2]} n = ab.m(); }\n" +
+ "}";
- public JavaSource() {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
- source = template.replace("#S1", sig1.paramStr).
- replace("#S2", sig2.paramStr).
- replace("#R1", rt1.retStr).
- replace("#R2", rt2.retStr).
- replace("#R3", rt3.retStr).
- replace("#TA1", ta1.typeargStr).
- replace("#TA2", ta2.typeargStr).
- replace("#TA3", ta3.typeargStr);
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
- }
+ @Override
+ public void doWork() throws IOException {
+ check(newCompilationTask()
+ .withOption("-XDuseUnsharedTable") //this test relies on predictable name indexes!
+ .withOptions(level.opts)
+ .withSourceFromTemplate(template)
+ .analyze());
}
- @Override
- public void run() {
- JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
- level.opts != null ? Arrays.asList(level.opts) : null,
- null, Arrays.asList(source));
- try {
- ct.analyze();
- } catch (Throwable ex) {
- throw new AssertionError("Error thrown when compiling the following code:\n" +
- source.getCharContent(true));
- }
- check();
- }
-
- void check() {
- checkCount.incrementAndGet();
-
+ void check(Result<?> res) {
boolean errorExpected = false;
int mostSpecific = 0;
//first check that either |R1| <: |R2| or |R2| <: |R1|
- if (rt1 != rt2) {
- if (!rt1.moreSpecificThan(rt2) &&
- !rt2.moreSpecificThan(rt1)) {
+ if (rets[0] != rets[1]) {
+ if (!rets[0].moreSpecificThan(rets[1]) &&
+ !rets[1].moreSpecificThan(rets[0])) {
errorExpected = true;
} else {
- mostSpecific = rt1.moreSpecificThan(rt2) ? 1 : 2;
+ mostSpecific = rets[0].moreSpecificThan(rets[1]) ? 1 : 2;
}
}
//check that either TA1 <= TA2 or TA2 <= TA1 (unless most specific return found above is raw)
if (!errorExpected) {
- if (ta1 != ta2) {
- boolean useStrictCheck = ta1.moreSpecificThan(ta2, true) ||
- ta2.moreSpecificThan(ta1, true);
- if (!ta1.moreSpecificThan(ta2, useStrictCheck) &&
- !ta2.moreSpecificThan(ta1, useStrictCheck)) {
+ if (targs[0] != targs[1]) {
+ boolean useStrictCheck = targs[0].moreSpecificThan(targs[1], true) ||
+ targs[1].moreSpecificThan(targs[0], true);
+ if (!targs[0].moreSpecificThan(targs[1], useStrictCheck) &&
+ !targs[1].moreSpecificThan(targs[0], useStrictCheck)) {
errorExpected = true;
} else {
- int mostSpecific2 = ta1.moreSpecificThan(ta2, useStrictCheck) ? 1 : 2;
+ int mostSpecific2 = targs[0].moreSpecificThan(targs[1], useStrictCheck) ? 1 : 2;
if (mostSpecific != 0 && mostSpecific2 != mostSpecific) {
errorExpected = mostSpecific == 1 ?
- ta1 != TypeArgumentKind.NONE :
- ta2 != TypeArgumentKind.NONE;
+ targs[0] != TypeArgumentKind.NONE :
+ targs[1] != TypeArgumentKind.NONE;
} else {
mostSpecific = mostSpecific2;
}
@@ -284,34 +237,21 @@
//finally, check that most specific return type is compatible with expected type
if (!errorExpected) {
- ReturnTypeKind msrt = mostSpecific == 1 ? rt1 : rt2;
- TypeArgumentKind msta = mostSpecific == 1 ? ta1 : ta2;
- SignatureKind mssig = mostSpecific == 1 ? sig1 : sig2;
+ ReturnTypeKind msrt = mostSpecific == 1 ? rets[0] : rets[1];
+ TypeArgumentKind msta = mostSpecific == 1 ? targs[0] : targs[1];
+ SignatureKind mssig = mostSpecific == 1 ? sigs[0] : sigs[1];
- if (!msrt.moreSpecificThan(rt3) ||
- !msta.assignableTo(ta3, mssig, level)) {
+ if (!msrt.moreSpecificThan(rets[2]) ||
+ !msta.assignableTo(targs[2], mssig, level)) {
errorExpected = true;
}
}
- if (errorExpected != diagChecker.errorFound) {
- throw new Error("invalid diagnostics for source:\n" +
- source.getCharContent(true) +
- "\nFound error: " + diagChecker.errorFound +
+ if (errorExpected != res.hasErrors()) {
+ fail("invalid diagnostics for source:\n" +
+ res.compilationInfo() +
+ "\nFound error: " + res.hasErrors() +
"\nExpected error: " + errorExpected);
}
}
-
- static class DiagnosticChecker
- implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- boolean errorFound;
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
- errorFound = true;
- }
- }
- }
-
}
--- a/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,35 +23,32 @@
/**
* @test
- * @bug 8003280 8004102 8006694
+ * @bug 8003280 8004102 8006694 8129962
* @summary Add lambda tests
* perform several automated checks in lambda conversion, esp. around accessibility
* temporarily workaround combo tests are causing time out in several platforms
- * @author Maurizio Cimadamore
- * @library ../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/timeout=600/othervm FunctionalInterfaceConversionTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main FunctionalInterfaceConversionTest
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
import java.io.IOException;
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaCompiler;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.ToolProvider;
-import com.sun.source.util.JavacTask;
-public class FunctionalInterfaceConversionTest
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
- enum PackageKind {
+
+public class FunctionalInterfaceConversionTest extends ComboInstance<FunctionalInterfaceConversionTest> {
+
+ enum PackageKind implements ComboParameter {
NO_PKG(""),
PKG_A("a");
@@ -61,7 +58,8 @@
this.pkg = pkg;
}
- String getPkgDecl() {
+ @Override
+ public String expand(String optParameter) {
return this == NO_PKG ?
"" :
"package " + pkg + ";";
@@ -74,12 +72,12 @@
}
}
- enum SamKind {
+ enum SamKind implements ComboParameter {
CLASS("public class Sam { }"),
ABSTACT_CLASS("public abstract class Sam { }"),
ANNOTATION("public @interface Sam { }"),
ENUM("public enum Sam { }"),
- INTERFACE("public interface Sam { \n #METH; \n }");
+ INTERFACE("public interface Sam { \n #{METH1}; \n }");
String sam_str;
@@ -87,12 +85,13 @@
this.sam_str = sam_str;
}
- String getSam(String methStr) {
- return sam_str.replaceAll("#METH", methStr);
+ @Override
+ public String expand(String optParameter) {
+ return sam_str;
}
}
- enum ModifierKind {
+ enum ModifierKind implements ComboParameter {
PUBLIC("public"),
PACKAGE("");
@@ -102,77 +101,73 @@
this.modifier_str = modifier_str;
}
- boolean stricterThan(ModifierKind that) {
- return this.ordinal() > that.ordinal();
+ @Override
+ public String expand(String optParameter) {
+ return modifier_str;
}
}
- enum TypeKind {
+ enum TypeKind implements ComboParameter {
EXCEPTION("Exception"),
PKG_CLASS("PackageClass");
String typeStr;
- private TypeKind(String typeStr) {
+ TypeKind(String typeStr) {
this.typeStr = typeStr;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return typeStr;
+ }
}
- enum ExprKind {
+ enum ExprKind implements ComboParameter {
LAMBDA("x -> null"),
MREF("this::m");
String exprStr;
- private ExprKind(String exprStr) {
+ ExprKind(String exprStr) {
this.exprStr = exprStr;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return exprStr;
+ }
}
- enum MethodKind {
+ enum MethodKind implements ComboParameter {
NONE(""),
- NON_GENERIC("public abstract #R m(#ARG s) throws #T;"),
- GENERIC("public abstract <X> #R m(#ARG s) throws #T;");
+ NON_GENERIC("public abstract #{RET} m(#{ARG} s) throws #{THROWN};"),
+ GENERIC("public abstract <X> #{RET} m(#{ARG} s) throws #{THROWN};");
String methodTemplate;
- private MethodKind(String methodTemplate) {
+ MethodKind(String methodTemplate) {
this.methodTemplate = methodTemplate;
}
- String getMethod(TypeKind retType, TypeKind argType, TypeKind thrownType) {
- return methodTemplate.replaceAll("#R", retType.typeStr).
- replaceAll("#ARG", argType.typeStr).
- replaceAll("#T", thrownType.typeStr);
+ @Override
+ public String expand(String optParameter) {
+ return methodTemplate;
}
}
public static void main(String[] args) throws Exception {
- for (PackageKind samPkg : PackageKind.values()) {
- for (ModifierKind modKind : ModifierKind.values()) {
- for (SamKind samKind : SamKind.values()) {
- for (MethodKind samMeth : MethodKind.values()) {
- for (MethodKind clientMeth : MethodKind.values()) {
- for (TypeKind retType : TypeKind.values()) {
- for (TypeKind argType : TypeKind.values()) {
- for (TypeKind thrownType : TypeKind.values()) {
- for (ExprKind exprKind : ExprKind.values()) {
- pool.execute(
- new FunctionalInterfaceConversionTest(
- samPkg, modKind, samKind,
- samMeth, clientMeth, retType,
- argType, thrownType, exprKind));
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- checkAfterExec(false);
+ new ComboTestHelper<FunctionalInterfaceConversionTest>()
+ .withDimension("PKG", (x, pkg) -> x.samPkg = pkg, PackageKind.values())
+ .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values())
+ .withDimension("CLAZZ", (x, sam) -> x.samKind = sam, SamKind.values())
+ .withDimension("METH1", (x, meth) -> x.samMeth = meth, MethodKind.values())
+ .withDimension("METH2", (x, meth) -> x.clientMeth = meth, MethodKind.values())
+ .withDimension("RET", (x, ret) -> x.retType = ret, TypeKind.values())
+ .withDimension("ARG", (x, arg) -> x.argType = arg, TypeKind.values())
+ .withDimension("THROWN", (x, thrown) -> x.thrownType = thrown, TypeKind.values())
+ .withDimension("EXPR", (x, expr) -> x.exprKind = expr, ExprKind.values())
+ .run(FunctionalInterfaceConversionTest::new);
}
PackageKind samPkg;
@@ -184,70 +179,32 @@
TypeKind argType;
TypeKind thrownType;
ExprKind exprKind;
- DiagnosticChecker dc;
- SourceFile samSourceFile = new SourceFile("Sam.java", "#P \n #C") {
- @Override
- public String toString() {
- return template.replaceAll("#P", samPkg.getPkgDecl()).
- replaceAll("#C", samKind.getSam(
- samMeth.getMethod(retType, argType, thrownType)));
- }
- };
-
- SourceFile pkgClassSourceFile =
- new SourceFile("PackageClass.java",
- "#P\n #M class PackageClass extends Exception { }") {
- @Override
- public String toString() {
- return template.replaceAll("#P", samPkg.getPkgDecl()).
- replaceAll("#M", modKind.modifier_str);
- }
- };
+ String samSource = "#{PKG} \n #{CLAZZ}";
+ String pkgClassSource = "#{PKG}\n #{MOD} class PackageClass extends Exception { }";
+ String clientSource = "#{IMP}\n abstract class Client { \n" +
+ " Sam s = #{EXPR};\n" +
+ " #{METH2} \n }";
- SourceFile clientSourceFile =
- new SourceFile("Client.java",
- "#I\n abstract class Client { \n" +
- " Sam s = #E;\n" +
- " #M \n }") {
- @Override
- public String toString() {
- return template.replaceAll("#I", samPkg.getImportStat())
- .replaceAll("#E", exprKind.exprStr)
- .replaceAll("#M", clientMeth.getMethod(retType, argType, thrownType));
- }
- };
-
- FunctionalInterfaceConversionTest(PackageKind samPkg, ModifierKind modKind,
- SamKind samKind, MethodKind samMeth, MethodKind clientMeth,
- TypeKind retType, TypeKind argType, TypeKind thrownType,
- ExprKind exprKind) {
- this.samPkg = samPkg;
- this.modKind = modKind;
- this.samKind = samKind;
- this.samMeth = samMeth;
- this.clientMeth = clientMeth;
- this.retType = retType;
- this.argType = argType;
- this.thrownType = thrownType;
- this.exprKind = exprKind;
- this.dc = new DiagnosticChecker();
+ @Override
+ public void doWork() throws IOException {
+ check(newCompilationTask()
+ .withSourceFromTemplate("Sam", samSource)
+ .withSourceFromTemplate("PackageClass", pkgClassSource)
+ .withSourceFromTemplate("Client", clientSource, this::importStmt)
+ .analyze());
}
- @Override
- public void run() {
- final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+ ComboParameter importStmt(String name) {
+ switch (name) {
+ case "IMP": return new ComboParameter.Constant<>(samPkg.getImportStat());
+ default: return null;
+ }
+ }
- JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), dc, null, null,
- Arrays.asList(samSourceFile, pkgClassSourceFile, clientSourceFile));
- try {
- ct.analyze();
- } catch (IOException ex) {
- throw new AssertionError("Test failing with cause", ex.getCause());
- }
- if (dc.errorFound == checkSamConversion()) {
- throw new AssertionError(samSourceFile + "\n\n" +
- pkgClassSourceFile + "\n\n" + clientSourceFile);
+ void check(Result<?> res) {
+ if (res.hasErrors() == checkSamConversion()) {
+ fail("Unexpected compilation result; " + res.compilationInfo());
}
}
@@ -276,35 +233,4 @@
return true;
}
}
-
- abstract class SourceFile extends SimpleJavaFileObject {
-
- protected String template;
-
- public SourceFile(String filename, String template) {
- super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
- this.template = template;
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return toString();
- }
-
- @Override
- public abstract String toString();
- }
-
- static class DiagnosticChecker
- implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- boolean errorFound = false;
-
- @Override
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
- errorFound = true;
- }
- }
- }
}
--- a/langtools/test/tools/javac/lambda/LambdaParserTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/lambda/LambdaParserTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,39 +23,40 @@
/*
* @test
- * @bug 7115050 8003280 8005852 8006694
+ * @bug 7115050 8003280 8005852 8006694 8129962
* @summary Add lambda tests
* Add parser support for lambda expressions
* temporarily workaround combo tests are causing time out in several platforms
- * @library ../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm LambdaParserTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+
+ * @run main LambdaParserTest
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import com.sun.source.util.JavacTask;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
-public class LambdaParserTest
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
+public class LambdaParserTest extends ComboInstance<LambdaParserTest> {
- enum LambdaKind {
+ enum LambdaKind implements ComboParameter {
NILARY_EXPR("()->x"),
NILARY_STMT("()->{ return x; }"),
- ONEARY_SHORT_EXPR("#PN->x"),
- ONEARY_SHORT_STMT("#PN->{ return x; }"),
- ONEARY_EXPR("(#M1 #T1 #PN)->x"),
- ONEARY_STMT("(#M1 #T1 #PN)->{ return x; }"),
- TWOARY_EXPR("(#M1 #T1 #PN, #M2 #T2 y)->x"),
- TWOARY_STMT("(#M1 #T1 #PN, #M2 #T2 y)->{ return x; }");
+ ONEARY_SHORT_EXPR("#{NAME}->x"),
+ ONEARY_SHORT_STMT("#{NAME}->{ return x; }"),
+ ONEARY_EXPR("(#{MOD[0]} #{TYPE[0]} #{NAME})->x"),
+ ONEARY_STMT("(#{MOD[0]} #{TYPE[0]} #{NAME})->{ return x; }"),
+ TWOARY_EXPR("(#{MOD[0]} #{TYPE[0]} #{NAME}, #{MOD[1]} #{TYPE[1]} y)->x"),
+ TWOARY_STMT("(#{MOD[0]} #{TYPE[0]} #{NAME}, #{MOD[1]} #{TYPE[1]} y)->{ return x; }");
String lambdaTemplate;
@@ -63,13 +64,9 @@
this.lambdaTemplate = lambdaTemplate;
}
- String getLambdaString(LambdaParameterKind pk1, LambdaParameterKind pk2,
- ModifierKind mk1, ModifierKind mk2, LambdaParameterName pn) {
- return lambdaTemplate.replaceAll("#M1", mk1.modifier)
- .replaceAll("#M2", mk2.modifier)
- .replaceAll("#T1", pk1.parameterType)
- .replaceAll("#T2", pk2.parameterType)
- .replaceAll("#PN", pn.nameStr);
+ @Override
+ public String expand(String optParameter) {
+ return lambdaTemplate;
}
int arity() {
@@ -92,7 +89,7 @@
}
}
- enum LambdaParameterName {
+ enum LambdaParameterName implements ComboParameter {
IDENT("x"),
UNDERSCORE("_");
@@ -101,9 +98,14 @@
LambdaParameterName(String nameStr) {
this.nameStr = nameStr;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return nameStr;
+ }
}
- enum LambdaParameterKind {
+ enum LambdaParameterKind implements ComboParameter {
IMPLICIT(""),
EXPLIICT_SIMPLE("A"),
EXPLIICT_SIMPLE_ARR1("A[]"),
@@ -129,9 +131,14 @@
return this == EXPLICIT_VARARGS ||
this == EXPLICIT_GENERIC2_VARARGS;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return parameterType;
+ }
}
- enum ModifierKind {
+ enum ModifierKind implements ComboParameter {
NONE(""),
FINAL("final"),
PUBLIC("public");
@@ -150,15 +157,20 @@
default: throw new AssertionError("Invalid modifier kind " + this);
}
}
+
+ @Override
+ public String expand(String optParameter) {
+ return modifier;
+ }
}
- enum ExprKind {
- NONE("#L#S"),
- SINGLE_PAREN1("(#L#S)"),
- SINGLE_PAREN2("(#L)#S"),
- DOUBLE_PAREN1("((#L#S))"),
- DOUBLE_PAREN2("((#L)#S)"),
- DOUBLE_PAREN3("((#L))#S");
+ enum ExprKind implements ComboParameter {
+ NONE("#{LAMBDA}#{SUBEXPR}"),
+ SINGLE_PAREN1("(#{LAMBDA}#{SUBEXPR})"),
+ SINGLE_PAREN2("(#{LAMBDA})#{SUBEXPR}"),
+ DOUBLE_PAREN1("((#{LAMBDA}#{SUBEXPR}))"),
+ DOUBLE_PAREN2("((#{LAMBDA})#{SUBEXPR})"),
+ DOUBLE_PAREN3("((#{LAMBDA}))#{SUBEXPR}");
String expressionTemplate;
@@ -166,14 +178,13 @@
this.expressionTemplate = expressionTemplate;
}
- String expressionString(LambdaParameterKind pk1, LambdaParameterKind pk2,
- ModifierKind mk1, ModifierKind mk2, LambdaKind lk, LambdaParameterName pn, SubExprKind sk) {
- return expressionTemplate.replaceAll("#L", lk.getLambdaString(pk1, pk2, mk1, mk2, pn))
- .replaceAll("#S", sk.subExpression);
+ @Override
+ public String expand(String optParameter) {
+ return expressionTemplate;
}
}
- enum SubExprKind {
+ enum SubExprKind implements ComboParameter {
NONE(""),
SELECT_FIELD(".f"),
SELECT_METHOD(".f()"),
@@ -186,133 +197,78 @@
SubExprKind(String subExpression) {
this.subExpression = subExpression;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return subExpression;
+ }
}
public static void main(String... args) throws Exception {
- for (LambdaKind lk : LambdaKind.values()) {
- for (LambdaParameterName pn : LambdaParameterName.values()) {
- for (LambdaParameterKind pk1 : LambdaParameterKind.values()) {
- if (lk.arity() < 1 && pk1 != LambdaParameterKind.IMPLICIT)
- continue;
- for (LambdaParameterKind pk2 : LambdaParameterKind.values()) {
- if (lk.arity() < 2 && pk2 != LambdaParameterKind.IMPLICIT)
- continue;
- for (ModifierKind mk1 : ModifierKind.values()) {
- if (mk1 != ModifierKind.NONE && lk.isShort())
- continue;
- if (lk.arity() < 1 && mk1 != ModifierKind.NONE)
- continue;
- for (ModifierKind mk2 : ModifierKind.values()) {
- if (lk.arity() < 2 && mk2 != ModifierKind.NONE)
- continue;
- for (SubExprKind sk : SubExprKind.values()) {
- for (ExprKind ek : ExprKind.values()) {
- pool.execute(
- new LambdaParserTest(pk1, pk2, mk1,
- mk2, lk, sk, ek, pn));
- }
- }
- }
- }
- }
- }
- }
- }
-
- checkAfterExec();
+ new ComboTestHelper<LambdaParserTest>()
+ .withFilter(LambdaParserTest::redundantTestFilter)
+ .withFilter(LambdaParserTest::badImplicitFilter)
+ .withDimension("LAMBDA", (x, lk) -> x.lk = lk, LambdaKind.values())
+ .withDimension("NAME", (x, name) -> x.pn = name, LambdaParameterName.values())
+ .withArrayDimension("TYPE", (x, type, idx) -> x.pks[idx] = type, 2, LambdaParameterKind.values())
+ .withArrayDimension("MOD", (x, mod, idx) -> x.mks[idx] = mod, 2, ModifierKind.values())
+ .withDimension("EXPR", ExprKind.values())
+ .withDimension("SUBEXPR", SubExprKind.values())
+ .run(LambdaParserTest::new);
}
- LambdaParameterKind pk1;
- LambdaParameterKind pk2;
- ModifierKind mk1;
- ModifierKind mk2;
+ LambdaParameterKind[] pks = new LambdaParameterKind[2];
+ ModifierKind[] mks = new ModifierKind[2];
LambdaKind lk;
LambdaParameterName pn;
- SubExprKind sk;
- ExprKind ek;
- JavaSource source;
- DiagnosticChecker diagChecker;
+
+ boolean badImplicitFilter() {
+ return !(mks[0] != ModifierKind.NONE && lk.isShort());
+ }
- LambdaParserTest(LambdaParameterKind pk1, LambdaParameterKind pk2,
- ModifierKind mk1, ModifierKind mk2, LambdaKind lk,
- SubExprKind sk, ExprKind ek, LambdaParameterName pn) {
- this.pk1 = pk1;
- this.pk2 = pk2;
- this.mk1 = mk1;
- this.mk2 = mk2;
- this.lk = lk;
- this.pn = pn;
- this.sk = sk;
- this.ek = ek;
- this.source = new JavaSource();
- this.diagChecker = new DiagnosticChecker();
+ boolean redundantTestFilter() {
+ for (int i = lk.arity(); i < mks.length ; i++) {
+ if (mks[i].ordinal() != 0) {
+ return false;
+ }
+ }
+ for (int i = lk.arity(); i < pks.length ; i++) {
+ if (pks[i].ordinal() != 0) {
+ return false;
+ }
+ }
+ return true;
}
- class JavaSource extends SimpleJavaFileObject {
-
- String template = "class Test {\n" +
- " SAM s = #E;\n" +
- "}";
-
- String source;
+ String template = "class Test {\n" +
+ " SAM s = #{EXPR};\n" +
+ "}";
- public JavaSource() {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
- source = template.replaceAll("#E",
- ek.expressionString(pk1, pk2, mk1, mk2, lk, pn, sk));
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
- }
+ @Override
+ public void doWork() throws IOException {
+ check(newCompilationTask()
+ .withSourceFromTemplate(template)
+ .parse());
}
- public void run() {
- JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
- null, null, Arrays.asList(source));
- try {
- ct.parse();
- } catch (Throwable ex) {
- processException(ex);
- return;
- }
- check();
- }
-
- void check() {
- checkCount.incrementAndGet();
-
- boolean errorExpected = (lk.arity() > 0 && !mk1.compatibleWith(pk1)) ||
- (lk.arity() > 1 && !mk2.compatibleWith(pk2));
+ void check(Result<?> res) {
+ boolean errorExpected = (lk.arity() > 0 && !mks[0].compatibleWith(pks[0])) ||
+ (lk.arity() > 1 && !mks[1].compatibleWith(pks[1]));
if (lk.arity() == 2 &&
- (pk1.explicit() != pk2.explicit() ||
- pk1.isVarargs())) {
+ (pks[0].explicit() != pks[1].explicit() ||
+ pks[0].isVarargs())) {
errorExpected = true;
}
errorExpected |= pn == LambdaParameterName.UNDERSCORE &&
lk.arity() > 0;
- if (errorExpected != diagChecker.errorFound) {
- throw new Error("invalid diagnostics for source:\n" +
- source.getCharContent(true) +
- "\nFound error: " + diagChecker.errorFound +
+ if (errorExpected != res.hasErrors()) {
+ fail("invalid diagnostics for source:\n" +
+ res.compilationInfo() +
+ "\nFound error: " + res.hasErrors() +
"\nExpected error: " + errorExpected);
}
}
-
- static class DiagnosticChecker
- implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- boolean errorFound;
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
- errorFound = true;
- }
- }
- }
-
}
--- a/langtools/test/tools/javac/lambda/MethodReferenceParserTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/lambda/MethodReferenceParserTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,39 +23,39 @@
/*
* @test
- * @bug 7115052 8003280 8006694
+ * @bug 7115052 8003280 8006694 8129962
* @summary Add lambda tests
* Add parser support for method references
* temporarily workaround combo tests are causing time out in several platforms
- * @library ../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm MethodReferenceParserTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main MethodReferenceParserTest
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import com.sun.source.util.JavacTask;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
+
+public class MethodReferenceParserTest extends ComboInstance<MethodReferenceParserTest> {
-public class MethodReferenceParserTest
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
-
- enum ReferenceKind {
- METHOD_REF("#Q::#Gm"),
- CONSTRUCTOR_REF("#Q::#Gnew"),
+ enum ReferenceKind implements ComboParameter {
+ METHOD_REF("#{QUAL}::#{TARGS}m"),
+ CONSTRUCTOR_REF("#{QUAL}::#{TARGS}new"),
FALSE_REF("min < max"),
- ERR_SUPER("#Q::#Gsuper"),
- ERR_METH0("#Q::#Gm()"),
- ERR_METH1("#Q::#Gm(X)"),
- ERR_CONSTR0("#Q::#Gnew()"),
- ERR_CONSTR1("#Q::#Gnew(X)");
+ ERR_SUPER("#{QUAL}::#{TARGS}super"),
+ ERR_METH0("#{QUAL}::#{TARGS}m()"),
+ ERR_METH1("#{QUAL}::#{TARGS}m(X)"),
+ ERR_CONSTR0("#{QUAL}::#{TARGS}new()"),
+ ERR_CONSTR1("#{QUAL}::#{TARGS}new(X)");
String referenceTemplate;
@@ -63,12 +63,6 @@
this.referenceTemplate = referenceTemplate;
}
- String getReferenceString(QualifierKind qk, GenericKind gk) {
- return referenceTemplate
- .replaceAll("#Q", qk.qualifier)
- .replaceAll("#G", gk.typeParameters);
- }
-
boolean erroneous() {
switch (this) {
case ERR_SUPER:
@@ -80,11 +74,16 @@
default: return false;
}
}
+
+ @Override
+ public String expand(String optParameter) {
+ return referenceTemplate;
+ }
}
- enum ContextKind {
- ASSIGN("SAM s = #E;"),
- METHOD("m(#E, i);");
+ enum ContextKind implements ComboParameter {
+ ASSIGN("SAM s = #{EXPR};"),
+ METHOD("m(#{EXPR}, i);");
String contextTemplate;
@@ -92,13 +91,13 @@
this.contextTemplate = contextTemplate;
}
- String contextString(ExprKind ek, ReferenceKind rk, QualifierKind qk,
- GenericKind gk, SubExprKind sk) {
- return contextTemplate.replaceAll("#E", ek.expressionString(rk, qk, gk, sk));
+ @Override
+ public String expand(String optParameter) {
+ return contextTemplate;
}
}
- enum GenericKind {
+ enum GenericKind implements ComboParameter {
NONE(""),
ONE("<X>"),
TWO("<X,Y>");
@@ -108,9 +107,14 @@
GenericKind(String typeParameters) {
this.typeParameters = typeParameters;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return typeParameters;
+ }
}
- enum QualifierKind {
+ enum QualifierKind implements ComboParameter {
THIS("this"),
SUPER("super"),
NEW("new Foo()"),
@@ -131,15 +135,20 @@
QualifierKind(String qualifier) {
this.qualifier = qualifier;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return qualifier;
+ }
}
- enum ExprKind {
- NONE("#R::S"),
- SINGLE_PAREN1("(#R#S)"),
- SINGLE_PAREN2("(#R)#S"),
- DOUBLE_PAREN1("((#R#S))"),
- DOUBLE_PAREN2("((#R)#S)"),
- DOUBLE_PAREN3("((#R))#S");
+ enum ExprKind implements ComboParameter {
+ NONE("#{MREF}"),
+ SINGLE_PAREN1("(#{MREF}#{SUBEXPR})"),
+ SINGLE_PAREN2("(#{MREF})#{SUBEXPR}"),
+ DOUBLE_PAREN1("((#{MREF}#{SUBEXPR}))"),
+ DOUBLE_PAREN2("((#{MREF})#{SUBEXPR})"),
+ DOUBLE_PAREN3("((#{MREF}))#{SUBEXPR}");
String expressionTemplate;
@@ -147,14 +156,13 @@
this.expressionTemplate = expressionTemplate;
}
- String expressionString(ReferenceKind rk, QualifierKind qk, GenericKind gk, SubExprKind sk) {
- return expressionTemplate
- .replaceAll("#R", rk.getReferenceString(qk, gk))
- .replaceAll("#S", sk.subExpression);
+ @Override
+ public String expand(String optParameter) {
+ return expressionTemplate;
}
}
- enum SubExprKind {
+ enum SubExprKind implements ComboParameter {
NONE(""),
SELECT_FIELD(".f"),
SELECT_METHOD(".f()"),
@@ -167,100 +175,45 @@
SubExprKind(String subExpression) {
this.subExpression = subExpression;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return subExpression;
+ }
}
public static void main(String... args) throws Exception {
- for (ReferenceKind rk : ReferenceKind.values()) {
- for (QualifierKind qk : QualifierKind.values()) {
- for (GenericKind gk : GenericKind.values()) {
- for (SubExprKind sk : SubExprKind.values()) {
- for (ExprKind ek : ExprKind.values()) {
- for (ContextKind ck : ContextKind.values()) {
- pool.execute(new MethodReferenceParserTest(rk, qk, gk, sk, ek, ck));
- }
- }
- }
- }
- }
- }
-
- checkAfterExec();
+ new ComboTestHelper<MethodReferenceParserTest>()
+ .withDimension("MREF", (x, ref) -> x.rk = ref, ReferenceKind.values())
+ .withDimension("QUAL", QualifierKind.values())
+ .withDimension("TARGS", GenericKind.values())
+ .withDimension("EXPR", ExprKind.values())
+ .withDimension("SUBEXPR", SubExprKind.values())
+ .withDimension("CTX", ContextKind.values())
+ .run(MethodReferenceParserTest::new);
}
ReferenceKind rk;
- QualifierKind qk;
- GenericKind gk;
- SubExprKind sk;
- ExprKind ek;
- ContextKind ck;
- JavaSource source;
- DiagnosticChecker diagChecker;
- MethodReferenceParserTest(ReferenceKind rk, QualifierKind qk, GenericKind gk, SubExprKind sk, ExprKind ek, ContextKind ck) {
- this.rk = rk;
- this.qk = qk;
- this.gk = gk;
- this.sk = sk;
- this.ek = ek;
- this.ck = ck;
- this.source = new JavaSource();
- this.diagChecker = new DiagnosticChecker();
+ String template = "class Test {\n" +
+ " void test() {\n" +
+ " #{CTX}\n" +
+ " }" +
+ "}";
+
+ @Override
+ public void doWork() throws IOException {
+ check(newCompilationTask()
+ .withSourceFromTemplate(template)
+ .parse());
}
- class JavaSource extends SimpleJavaFileObject {
-
- String template = "class Test {\n" +
- " void test() {\n" +
- " #C\n" +
- " }" +
- "}";
-
- String source;
-
- public JavaSource() {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
- source = template.replaceAll("#C", ck.contextString(ek, rk, qk, gk, sk));
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
- }
- }
-
- @Override
- public void run() {
- JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
- null, null, Arrays.asList(source));
- try {
- ct.parse();
- } catch (Throwable ex) {
- processException(ex);
- return;
- }
- check();
- }
-
- void check() {
- checkCount.incrementAndGet();
-
- if (diagChecker.errorFound != rk.erroneous()) {
- throw new Error("invalid diagnostics for source:\n" +
- source.getCharContent(true) +
- "\nFound error: " + diagChecker.errorFound +
+ void check(Result<?> res) {
+ if (res.hasErrors() != rk.erroneous()) {
+ fail("invalid diagnostics for source:\n" +
+ res.compilationInfo() +
+ "\nFound error: " + res.hasErrors() +
"\nExpected error: " + rk.erroneous());
}
}
-
- static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- boolean errorFound;
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
- errorFound = true;
- }
- }
- }
-
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/TestBootstrapMethodsCount.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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 8129547
+ * @summary Excess entries in BootstrapMethods with the same (bsm, bsmKind, bsmStaticArgs), but different dynamicArgs
+ * @library /tools/javac/lib
+ * @modules jdk.jdeps/com.sun.tools.classfile
+ * jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.tree
+ * jdk.compiler/com.sun.tools.javac.util
+ */
+
+import java.io.File;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Locale;
+
+import javax.tools.Diagnostic;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+import com.sun.source.tree.MethodInvocationTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.util.TaskEvent;
+import com.sun.source.util.TaskListener;
+import com.sun.source.util.TreeScanner;
+
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.BootstrapMethods_attribute;
+import com.sun.tools.classfile.ClassFile;
+
+import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCIdent;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Names;
+
+import static com.sun.tools.javac.jvm.ClassFile.*;
+
+public class TestBootstrapMethodsCount {
+
+ public static void main(String... args) throws Exception {
+ JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+ new TestBootstrapMethodsCount().run(comp);
+ }
+
+ DiagChecker dc;
+
+ TestBootstrapMethodsCount() {
+ dc = new DiagChecker();
+ }
+
+ public void run(JavaCompiler comp) {
+ JavaSource source = new JavaSource();
+ JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, null, dc,
+ Arrays.asList("-g"), null, Arrays.asList(source));
+ Context context = ct.getContext();
+ Symtab syms = Symtab.instance(context);
+ Names names = Names.instance(context);
+ Types types = Types.instance(context);
+ ct.addTaskListener(new Indifier(syms, names, types));
+ try {
+ ct.generate();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw new AssertionError(
+ String.format("Error thrown when compiling following code\n%s",
+ source.source));
+ }
+ if (dc.diagFound) {
+ throw new AssertionError(
+ String.format("Diags found when compiling following code\n%s\n\n%s",
+ source.source, dc.printDiags()));
+ }
+ verifyBytecode();
+ }
+
+ void verifyBytecode() {
+ File compiledTest = new File("Test.class");
+ try {
+ ClassFile cf = ClassFile.read(compiledTest);
+ BootstrapMethods_attribute bsm_attr =
+ (BootstrapMethods_attribute)cf
+ .getAttribute(Attribute.BootstrapMethods);
+ int length = bsm_attr.bootstrap_method_specifiers.length;
+ if (length != 1) {
+ throw new Error("Bad number of method specifiers " +
+ "in BootstrapMethods attribute: " + length);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new Error("error reading " + compiledTest +": " + e);
+ }
+ }
+
+ class JavaSource extends SimpleJavaFileObject {
+
+ static final String source = "import java.lang.invoke.*;\n" +
+ "class Bootstrap {\n" +
+ " public static CallSite bsm(MethodHandles.Lookup lookup, " +
+ "String name, MethodType methodType) {\n" +
+ " return null;\n" +
+ " }\n" +
+ "}\n" +
+ "class Test {\n" +
+ " void m1() { }\n" +
+ " void m2(Object arg1) { }\n" +
+ " void test1() {\n" +
+ " Object o = this; // marker statement \n" +
+ " m1();\n" +
+ " }\n" +
+ " void test2(Object arg1) {\n" +
+ " Object o = this; // marker statement \n" +
+ " m2(arg1);\n" +
+ " }\n" +
+ "}";
+
+ JavaSource() {
+ super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return source;
+ }
+ }
+
+ class Indifier extends TreeScanner<Void, Void> implements TaskListener {
+
+ MethodSymbol bsm;
+ Symtab syms;
+ Names names;
+ Types types;
+
+ Indifier(Symtab syms, Names names, Types types) {
+ this.syms = syms;
+ this.names = names;
+ this.types = types;
+ }
+
+ @Override
+ public void started(TaskEvent e) {
+ //do nothing
+ }
+
+ @Override
+ public void finished(TaskEvent e) {
+ if (e.getKind() == TaskEvent.Kind.ANALYZE) {
+ scan(e.getCompilationUnit(), null);
+ }
+ }
+
+ @Override
+ public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
+ super.visitMethodInvocation(node, p);
+ JCMethodInvocation apply = (JCMethodInvocation)node;
+ JCIdent ident = (JCIdent)apply.meth;
+ Symbol oldSym = ident.sym;
+ if (!oldSym.isConstructor()) {
+ ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name,
+ oldSym.owner, REF_invokeStatic, bsm, oldSym.type, new Object[0]);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitMethod(MethodTree node, Void p) {
+ super.visitMethod(node, p);
+ if (node.getName().toString().equals("bsm")) {
+ bsm = ((JCMethodDecl)node).sym;
+ }
+ return null;
+ }
+ }
+
+ static class DiagChecker
+ implements javax.tools.DiagnosticListener<JavaFileObject> {
+
+ boolean diagFound;
+ ArrayList<String> diags = new ArrayList<>();
+
+ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ diags.add(diagnostic.getMessage(Locale.getDefault()));
+ diagFound = true;
+ }
+
+ String printDiags() {
+ StringBuilder buf = new StringBuilder();
+ for (String s : diags) {
+ buf.append(s);
+ buf.append("\n");
+ }
+ return buf.toString();
+ }
+ }
+
+}
--- a/langtools/test/tools/javac/lambda/TestInvokeDynamic.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/lambda/TestInvokeDynamic.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,33 +23,27 @@
/*
* @test
- * @bug 7194586 8003280 8006694 8010404
+ * @bug 7194586 8003280 8006694 8010404 8129962
* @summary Add lambda tests
* Add back-end support for invokedynamic
* temporarily workaround combo tests are causing time out in several platforms
- * @library ../lib
+ * @library /tools/javac/lib
* @modules jdk.jdeps/com.sun.tools.classfile
* jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.javac.jvm
* jdk.compiler/com.sun.tools.javac.tree
* jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm TestInvokeDynamic
+ * @build combo.ComboTestHelper
+ * @run main TestInvokeDynamic
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
+import java.io.InputStream;
-import java.io.File;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Locale;
-
-import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree;
@@ -78,13 +72,17 @@
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Names;
+import combo.ComboParameter;
+import combo.ComboTask;
+import combo.ComboTestHelper;
+import combo.ComboInstance;
+import combo.ComboTask.Result;
+
import static com.sun.tools.javac.jvm.ClassFile.*;
-public class TestInvokeDynamic
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
+public class TestInvokeDynamic extends ComboInstance<TestInvokeDynamic> {
- enum StaticArgumentKind {
+ enum StaticArgumentKind implements ComboParameter {
STRING("Hello!", "String", "Ljava/lang/String;") {
@Override
boolean check(CPInfo cpInfo) throws Exception {
@@ -189,88 +187,91 @@
throw new AssertionError();
}
}
+
+ @Override
+ public String expand(String optParameter) {
+ return sourceTypeStr;
+ }
}
- enum StaticArgumentsArity {
- ZERO(0),
- ONE(1),
- TWO(2),
- THREE(3);
+ enum StaticArgumentsArity implements ComboParameter {
+ ZERO(0, ""),
+ ONE(1, ",#{SARG[0]} s1"),
+ TWO(2, ",#{SARG[0]} s1, #{SARG[1]} s2"),
+ THREE(3, ",#{SARG[0]} s1, #{SARG[1]} s2, #{SARG[2]} s3");
int arity;
+ String argsTemplate;
- StaticArgumentsArity(int arity) {
+ StaticArgumentsArity(int arity, String argsTemplate) {
this.arity = arity;
+ this.argsTemplate = argsTemplate;
+ }
+
+ @Override
+ public String expand(String optParameter) {
+ return argsTemplate;
}
}
public static void main(String... args) throws Exception {
- for (StaticArgumentsArity arity : StaticArgumentsArity.values()) {
- if (arity.arity == 0) {
- pool.execute(new TestInvokeDynamic(arity));
- } else {
- for (StaticArgumentKind sak1 : StaticArgumentKind.values()) {
- if (arity.arity == 1) {
- pool.execute(new TestInvokeDynamic(arity, sak1));
- } else {
- for (StaticArgumentKind sak2 : StaticArgumentKind.values()) {
- if (arity.arity == 2) {
- pool.execute(new TestInvokeDynamic(arity, sak1, sak2));
- } else {
- for (StaticArgumentKind sak3 : StaticArgumentKind.values()) {
- pool.execute(
- new TestInvokeDynamic(arity, sak1, sak2, sak3));
- }
- }
- }
- }
- }
- }
- }
-
- checkAfterExec();
+ new ComboTestHelper<TestInvokeDynamic>()
+ .withFilter(TestInvokeDynamic::redundantTestFilter)
+ .withDimension("SARGS", (x, arity) -> x.arity = arity, StaticArgumentsArity.values())
+ .withArrayDimension("SARG", (x, arg, idx) -> x.saks[idx] = arg, 3, StaticArgumentKind.values())
+ .run(TestInvokeDynamic::new);
}
StaticArgumentsArity arity;
- StaticArgumentKind[] saks;
- DiagChecker dc;
+ StaticArgumentKind[] saks = new StaticArgumentKind[3];
- TestInvokeDynamic(StaticArgumentsArity arity, StaticArgumentKind... saks) {
- this.arity = arity;
- this.saks = saks;
- dc = new DiagChecker();
+ boolean redundantTestFilter() {
+ for (int i = arity.arity ; i < saks.length ; i++) {
+ if (saks[i].ordinal() != 0) {
+ return false;
+ }
+ }
+ return true;
}
- public void run() {
- int id = checkCount.incrementAndGet();
- JavaSource source = new JavaSource(id);
- JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, fm.get(), dc,
- Arrays.asList("-g"), null, Arrays.asList(source));
+ final String source_template =
+ "import java.lang.invoke.*;\n" +
+ "class Test {\n" +
+ " void m() { }\n" +
+ " void test() {\n" +
+ " Object o = this; // marker statement \n" +
+ " m();\n" +
+ " }\n" +
+ "}\n" +
+ "class Bootstrap {\n" +
+ " public static CallSite bsm(MethodHandles.Lookup lookup, " +
+ "String name, MethodType methodType #{SARGS}) {\n" +
+ " return null;\n" +
+ " }\n" +
+ "}";
+
+ @Override
+ public void doWork() throws IOException {
+ ComboTask comboTask = newCompilationTask()
+ .withOption("-g")
+ .withSourceFromTemplate(source_template);
+
+ JavacTaskImpl ct = (JavacTaskImpl)comboTask.getTask();
Context context = ct.getContext();
Symtab syms = Symtab.instance(context);
Names names = Names.instance(context);
Types types = Types.instance(context);
ct.addTaskListener(new Indifier(syms, names, types));
- try {
- ct.generate();
- } catch (Throwable t) {
- t.printStackTrace();
- throw new AssertionError(
- String.format("Error thrown when compiling following code\n%s",
- source.source));
- }
- if (dc.diagFound) {
- throw new AssertionError(
- String.format("Diags found when compiling following code\n%s\n\n%s",
- source.source, dc.printDiags()));
- }
- verifyBytecode(id);
+ verifyBytecode(comboTask.generate());
}
- void verifyBytecode(int id) {
- File compiledTest = new File(String.format("Test%d.class", id));
- try {
- ClassFile cf = ClassFile.read(compiledTest);
+ void verifyBytecode(Result<Iterable<? extends JavaFileObject>> res) {
+ if (res.hasErrors()) {
+ fail("Diags found when compiling instance: " + res.compilationInfo());
+ return;
+ }
+ try (InputStream is = res.get().iterator().next().openInputStream()){
+ ClassFile cf = ClassFile.read(is);
Method testMethod = null;
for (Method m : cf.methods) {
if (m.getName(cf.constant_pool).equals("test")) {
@@ -279,12 +280,14 @@
}
}
if (testMethod == null) {
- throw new Error("Test method not found");
+ fail("Test method not found");
+ return;
}
Code_attribute ea =
(Code_attribute)testMethod.attributes.get(Attribute.Code);
if (testMethod == null) {
- throw new Error("Code attribute for test() method not found");
+ fail("Code attribute for test() method not found");
+ return;
}
int bsmIdx = -1;
@@ -296,37 +299,39 @@
.constant_pool.get(i.getShort(1));
bsmIdx = indyInfo.bootstrap_method_attr_index;
if (!indyInfo.getNameAndTypeInfo().getType().equals("()V")) {
- throw new
- AssertionError("type mismatch for CONSTANT_InvokeDynamic_info");
+ fail("type mismatch for CONSTANT_InvokeDynamic_info");
+ return;
}
}
}
if (bsmIdx == -1) {
- throw new Error("Missing invokedynamic in generated code");
+ fail("Missing invokedynamic in generated code");
+ return;
}
BootstrapMethods_attribute bsm_attr =
(BootstrapMethods_attribute)cf
.getAttribute(Attribute.BootstrapMethods);
if (bsm_attr.bootstrap_method_specifiers.length != 1) {
- throw new Error("Bad number of method specifiers " +
+ fail("Bad number of method specifiers " +
"in BootstrapMethods attribute");
+ return;
}
BootstrapMethods_attribute.BootstrapMethodSpecifier bsm_spec =
bsm_attr.bootstrap_method_specifiers[0];
if (bsm_spec.bootstrap_arguments.length != arity.arity) {
- throw new Error("Bad number of static invokedynamic args " +
+ fail("Bad number of static invokedynamic args " +
"in BootstrapMethod attribute");
+ return;
}
- int count = 0;
- for (StaticArgumentKind sak : saks) {
- if (!sak.check(cf.constant_pool
- .get(bsm_spec.bootstrap_arguments[count]))) {
- throw new Error("Bad static argument value " + sak);
+ for (int i = 0 ; i < arity.arity ; i++) {
+ if (!saks[i].check(cf.constant_pool
+ .get(bsm_spec.bootstrap_arguments[i]))) {
+ fail("Bad static argument value " + saks[i]);
+ return;
}
- count++;
}
CONSTANT_MethodHandle_info bsm_handle =
@@ -334,7 +339,8 @@
.get(bsm_spec.bootstrap_method_ref);
if (bsm_handle.reference_kind != RefKind.REF_invokeStatic) {
- throw new Error("Bad kind on boostrap method handle");
+ fail("Bad kind on boostrap method handle");
+ return;
}
CONSTANT_Methodref_info bsm_ref =
@@ -342,88 +348,51 @@
.get(bsm_handle.reference_index);
if (!bsm_ref.getClassInfo().getName().equals("Bootstrap")) {
- throw new Error("Bad owner of boostrap method");
+ fail("Bad owner of boostrap method");
+ return;
}
if (!bsm_ref.getNameAndTypeInfo().getName().equals("bsm")) {
- throw new Error("Bad boostrap method name");
+ fail("Bad boostrap method name");
+ return;
}
if (!bsm_ref.getNameAndTypeInfo()
.getType().equals(asBSMSignatureString())) {
- throw new Error("Bad boostrap method type" +
+ fail("Bad boostrap method type" +
bsm_ref.getNameAndTypeInfo().getType() + " " +
asBSMSignatureString());
+ return;
}
LineNumberTable_attribute lnt =
(LineNumberTable_attribute)ea.attributes.get(Attribute.LineNumberTable);
if (lnt == null) {
- throw new Error("No LineNumberTable attribute");
+ fail("No LineNumberTable attribute");
+ return;
}
if (lnt.line_number_table_length != 3) {
- throw new Error("Wrong number of entries in LineNumberTable");
+ fail("Wrong number of entries in LineNumberTable");
+ return;
}
} catch (Exception e) {
e.printStackTrace();
- throw new Error("error reading " + compiledTest +": " + e);
+ fail("error reading classfile: " + res.compilationInfo());
+ return;
}
}
String asBSMSignatureString() {
StringBuilder buf = new StringBuilder();
buf.append("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;");
- for (StaticArgumentKind sak : saks) {
- buf.append(sak.bytecodeTypeStr);
+ for (int i = 0 ; i < arity.arity ; i++) {
+ buf.append(saks[i].bytecodeTypeStr);
}
buf.append(")Ljava/lang/invoke/CallSite;");
return buf.toString();
}
- class JavaSource extends SimpleJavaFileObject {
-
- static final String source_template = "import java.lang.invoke.*;\n" +
- "class Bootstrap {\n" +
- " public static CallSite bsm(MethodHandles.Lookup lookup, " +
- "String name, MethodType methodType #SARGS) {\n" +
- " return null;\n" +
- " }\n" +
- "}\n" +
- "class Test#ID {\n" +
- " void m() { }\n" +
- " void test() {\n" +
- " Object o = this; // marker statement \n" +
- " m();\n" +
- " }\n" +
- "}";
-
- String source;
-
- JavaSource(int id) {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
- source = source_template.replace("#SARGS", asSignatureString())
- .replace("#ID", String.valueOf(id));
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
- }
-
- String asSignatureString() {
- int count = 0;
- StringBuilder buf = new StringBuilder();
- for (StaticArgumentKind sak : saks) {
- buf.append(",");
- buf.append(sak.sourceTypeStr);
- buf.append(' ');
- buf.append(String.format("x%d", count++));
- }
- return buf.toString();
- }
- }
-
class Indifier extends TreeScanner<Void, Void> implements TaskListener {
MethodSymbol bsm;
@@ -475,26 +444,4 @@
return null;
}
}
-
- static class DiagChecker
- implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- boolean diagFound;
- ArrayList<String> diags = new ArrayList<>();
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- diags.add(diagnostic.getMessage(Locale.getDefault()));
- diagFound = true;
- }
-
- String printDiags() {
- StringBuilder buf = new StringBuilder();
- for (String s : diags) {
- buf.append(s);
- buf.append("\n");
- }
- return buf.toString();
- }
- }
-
}
--- a/langtools/test/tools/javac/lambda/TestLambdaToMethodStats.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/lambda/TestLambdaToMethodStats.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,34 +23,35 @@
/*
* @test
- * @bug 8013576
+ * @bug 8013576 8129962
* @summary Add stat support to LambdaToMethod
- * @library ../lib
+ * @library /tools/javac/lib
* @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
* jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm TestLambdaToMethodStats
+ * @build combo.ComboTestHelper
+ * @run main TestLambdaToMethodStats
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
-import java.net.URI;
-import java.util.Arrays;
+import java.io.IOException;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import com.sun.source.util.JavacTask;
import com.sun.tools.javac.api.ClientCodeWrapper;
-import com.sun.tools.javac.util.JCDiagnostic;
-public class TestLambdaToMethodStats
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
+import com.sun.tools.javac.util.List;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
- enum ExprKind {
+public class TestLambdaToMethodStats extends ComboInstance<TestLambdaToMethodStats> {
+
+ enum ExprKind implements ComboParameter {
LAMBDA("()->null"),
MREF1("this::g"),
MREF2("this::h");
@@ -60,9 +61,14 @@
ExprKind(String exprStr) {
this.exprStr = exprStr;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return exprStr;
+ }
}
- enum TargetKind {
+ enum TargetKind implements ComboParameter {
IMPLICIT(""),
SERIALIZABLE("(A & java.io.Serializable)");
@@ -71,124 +77,89 @@
TargetKind(String targetStr) {
this.targetStr = targetStr;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return targetStr;
+ }
+ }
+
+ enum DiagnosticKind {
+ LAMBDA_STAT("compiler.note.lambda.stat", true, false),
+ MREF_STAT("compiler.note.mref.stat", false, false),
+ MREF_STAT1("compiler.note.mref.stat.1", false, true);
+
+ String code;
+ boolean lambda;
+ boolean bridge;
+
+ DiagnosticKind(String code, boolean lambda, boolean bridge) {
+ this.code = code;
+ this.lambda = lambda;
+ this.bridge = bridge;
+ }
}
public static void main(String... args) throws Exception {
- for (ExprKind ek : ExprKind.values()) {
- for (TargetKind tk : TargetKind.values()) {
- pool.execute(new TestLambdaToMethodStats(ek, tk));
- }
- }
-
- checkAfterExec(true);
+ new ComboTestHelper<TestLambdaToMethodStats>()
+ .withDimension("EXPR", (x, expr) -> x.ek = expr, ExprKind.values())
+ .withDimension("CAST", (x, target) -> x.tk = target, TargetKind.values())
+ .run(TestLambdaToMethodStats::new);
}
ExprKind ek;
TargetKind tk;
- JavaSource source;
- DiagnosticChecker diagChecker;
-
- TestLambdaToMethodStats(ExprKind ek, TargetKind tk) {
- this.ek = ek;
- this.tk = tk;
- this.source = new JavaSource();
- this.diagChecker = new DiagnosticChecker();
+ String template = "interface A {\n" +
+ " Object o();\n" +
+ "}\n" +
+ "class Test {\n" +
+ " A a = #{CAST}#{EXPR};\n" +
+ " Object g() { return null; }\n" +
+ " Object h(Object... o) { return null; }\n" +
+ "}";
+
+ @Override
+ public void doWork() throws IOException {
+ check(newCompilationTask()
+ .withOption("-XDdumpLambdaToMethodStats")
+ .withSourceFromTemplate(template)
+ .generate());
}
- class JavaSource extends SimpleJavaFileObject {
-
- String template = "interface A {\n" +
- " Object o();\n" +
- "}\n" +
- "class Test {\n" +
- " A a = #C#E;\n" +
- " Object g() { return null; }\n" +
- " Object h(Object... o) { return null; }\n" +
- "}";
-
- String source;
-
- public JavaSource() {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
- source = template.replaceAll("#E", ek.exprStr)
- .replaceAll("#C", tk.targetStr);
+ void check(Result<?> res) {
+ DiagnosticKind diag = null;
+ boolean altMetafactory = false;
+ for (DiagnosticKind dk : DiagnosticKind.values()) {
+ List<Diagnostic<? extends JavaFileObject>> jcDiag = res.diagnosticsForKey(dk.code);
+ if (jcDiag.nonEmpty()) {
+ diag = dk;
+ ClientCodeWrapper.DiagnosticSourceUnwrapper dsu =
+ (ClientCodeWrapper.DiagnosticSourceUnwrapper)jcDiag.head;
+ altMetafactory = (Boolean)dsu.d.getArgs()[0];
+ break;
+ }
}
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
+ if (diag == null) {
+ fail("No diagnostic found; " + res.compilationInfo());
}
- }
- public void run() {
- JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
- Arrays.asList("-XDdumpLambdaToMethodStats"),
- null, Arrays.asList(source));
- try {
- ct.generate();
- } catch (Throwable ex) {
- throw new
- AssertionError("Error thron when analyzing the following source:\n" +
- source.getCharContent(true));
- }
- check();
- }
-
- void check() {
- checkCount.incrementAndGet();
-
- boolean error = diagChecker.lambda !=
+ boolean error = diag.lambda !=
(ek == ExprKind.LAMBDA);
- error |= diagChecker.bridge !=
+ error |= diag.bridge !=
(ek == ExprKind.MREF2);
- error |= diagChecker.altMetafactory !=
+ error |= altMetafactory !=
(tk == TargetKind.SERIALIZABLE);
if (error) {
- throw new AssertionError("Bad stat diagnostic found for source\n" +
- "lambda = " + diagChecker.lambda + "\n" +
- "bridge = " + diagChecker.bridge + "\n" +
- "altMF = " + diagChecker.altMetafactory + "\n" +
- source.source);
- }
- }
-
- static class DiagnosticChecker
- implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- boolean altMetafactory;
- boolean bridge;
- boolean lambda;
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- try {
- if (diagnostic.getKind() == Diagnostic.Kind.NOTE) {
- switch (diagnostic.getCode()) {
- case "compiler.note.lambda.stat":
- lambda = true;
- break;
- case "compiler.note.mref.stat":
- lambda = false;
- bridge = false;
- break;
- case "compiler.note.mref.stat.1":
- lambda = false;
- bridge = true;
- break;
- default:
- throw new AssertionError("unexpected note: " + diagnostic.getCode());
- }
- ClientCodeWrapper.DiagnosticSourceUnwrapper dsu =
- (ClientCodeWrapper.DiagnosticSourceUnwrapper)diagnostic;
- altMetafactory = (Boolean)dsu.d.getArgs()[0];
- }
- } catch (RuntimeException t) {
- t.printStackTrace();
- throw t;
- }
+ fail("Bad stat diagnostic found for source\n" +
+ "lambda = " + diag.lambda + "\n" +
+ "bridge = " + diag.bridge + "\n" +
+ "altMF = " + altMetafactory + "\n" +
+ res.compilationInfo());
}
}
}
--- a/langtools/test/tools/javac/lambda/bytecode/TestLambdaBytecode.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/lambda/bytecode/TestLambdaBytecode.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,18 +23,20 @@
/*
* @test
- * @bug 8009649
+ * @bug 8009649 8129962
* @summary Lambda back-end should generate invokespecial for method handles referring to private instance methods
- * @library ../../lib
+ * @library /tools/javac/lib
* @modules jdk.jdeps/com.sun.tools.classfile
* jdk.compiler/com.sun.tools.javac.api
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm TestLambdaBytecode
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main TestLambdaBytecode
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
import com.sun.tools.classfile.Attribute;
import com.sun.tools.classfile.BootstrapMethods_attribute;
import com.sun.tools.classfile.ClassFile;
@@ -43,26 +45,22 @@
import com.sun.tools.classfile.Instruction;
import com.sun.tools.classfile.Method;
-import com.sun.tools.javac.api.JavacTaskImpl;
-
+import java.io.IOException;
+import java.io.InputStream;
-import java.io.File;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Locale;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
-import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import static com.sun.tools.javac.jvm.ClassFile.*;
+public class TestLambdaBytecode extends ComboInstance<TestLambdaBytecode> {
-public class TestLambdaBytecode
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
+ static final int MF_ARITY = 3;
+ static final String MH_SIG = "()V";
- enum ClassKind {
+ enum ClassKind implements ComboParameter {
CLASS("class"),
INTERFACE("interface");
@@ -71,9 +69,14 @@
ClassKind(String classStr) {
this.classStr = classStr;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return classStr;
+ }
}
- enum AccessKind {
+ enum AccessKind implements ComboParameter {
PUBLIC("public"),
PRIVATE("private");
@@ -82,9 +85,14 @@
AccessKind(String accessStr) {
this.accessStr = accessStr;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return accessStr;
+ }
}
- enum StaticKind {
+ enum StaticKind implements ComboParameter {
STATIC("static"),
INSTANCE("");
@@ -93,9 +101,14 @@
StaticKind(String staticStr) {
this.staticStr = staticStr;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return staticStr;
+ }
}
- enum DefaultKind {
+ enum DefaultKind implements ComboParameter {
DEFAULT("default"),
NO_DEFAULT("");
@@ -104,15 +117,10 @@
DefaultKind(String defaultStr) {
this.defaultStr = defaultStr;
}
- }
- enum ExprKind {
- LAMBDA("Runnable r = ()->{ target(); };");
-
- String exprString;
-
- ExprKind(String exprString) {
- this.exprString = exprString;
+ @Override
+ public String expand(String optParameter) {
+ return defaultStr;
}
}
@@ -155,83 +163,53 @@
return true;
}
}
-
- String mods() {
- StringBuilder buf = new StringBuilder();
- buf.append(ak.accessStr);
- buf.append(' ');
- buf.append(sk.staticStr);
- buf.append(' ');
- buf.append(dk.defaultStr);
- return buf.toString();
- }
}
public static void main(String... args) throws Exception {
- for (ClassKind ck : ClassKind.values()) {
- for (AccessKind ak1 : AccessKind.values()) {
- for (StaticKind sk1 : StaticKind.values()) {
- for (DefaultKind dk1 : DefaultKind.values()) {
- for (AccessKind ak2 : AccessKind.values()) {
- for (StaticKind sk2 : StaticKind.values()) {
- for (DefaultKind dk2 : DefaultKind.values()) {
- for (ExprKind ek : ExprKind.values()) {
- pool.execute(new TestLambdaBytecode(ck, ak1, ak2, sk1, sk2, dk1, dk2, ek));
- }
- }
- }
- }
- }
- }
- }
- }
-
- checkAfterExec();
+ new ComboTestHelper<TestLambdaBytecode>()
+ .withDimension("CLASSKIND", (x, ck) -> x.ck = ck, ClassKind.values())
+ .withArrayDimension("ACCESS", (x, acc, idx) -> x.accessKinds[idx] = acc, 2, AccessKind.values())
+ .withArrayDimension("STATIC", (x, sk, idx) -> x.staticKinds[idx] = sk, 2, StaticKind.values())
+ .withArrayDimension("DEFAULT", (x, dk, idx) -> x.defaultKinds[idx] = dk, 2, DefaultKind.values())
+ .run(TestLambdaBytecode::new, TestLambdaBytecode::init);
}
+ ClassKind ck;
+ AccessKind[] accessKinds = new AccessKind[2];
+ StaticKind[] staticKinds = new StaticKind[2];
+ DefaultKind[] defaultKinds = new DefaultKind[2];
MethodKind mk1, mk2;
- ExprKind ek;
- DiagChecker dc;
- TestLambdaBytecode(ClassKind ck, AccessKind ak1, AccessKind ak2, StaticKind sk1,
- StaticKind sk2, DefaultKind dk1, DefaultKind dk2, ExprKind ek) {
- mk1 = new MethodKind(ck, ak1, sk1, dk1);
- mk2 = new MethodKind(ck, ak2, sk2, dk2);
- this.ek = ek;
- dc = new DiagChecker();
+ void init() {
+ mk1 = new MethodKind(ck, accessKinds[0], staticKinds[0], defaultKinds[0]);
+ mk2 = new MethodKind(ck, accessKinds[1], staticKinds[1], defaultKinds[1]);
}
- public void run() {
- int id = checkCount.incrementAndGet();
- JavaSource source = new JavaSource(id);
- JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, fm.get(), dc,
- null, null, Arrays.asList(source));
- try {
- ct.generate();
- } catch (Throwable t) {
- t.printStackTrace();
- throw new AssertionError(
- String.format("Error thrown when compiling following code\n%s",
- source.source));
- }
- if (dc.diagFound) {
+ String source_template =
+ "#{CLASSKIND} Test {\n" +
+ " #{ACCESS[0]} #{STATIC[0]} #{DEFAULT[0]} void test() { Runnable r = ()->{ target(); }; }\n" +
+ " #{ACCESS[1]} #{STATIC[1]} #{DEFAULT[1]} void target() { }\n" +
+ "}\n";
+
+ @Override
+ public void doWork() throws IOException {
+ verifyBytecode(newCompilationTask()
+ .withSourceFromTemplate(source_template)
+ .generate());
+ }
+
+ void verifyBytecode(Result<Iterable<? extends JavaFileObject>> res) {
+ if (res.hasErrors()) {
boolean errorExpected = !mk1.isOK() || !mk2.isOK();
errorExpected |= mk1.isStatic() && !mk2.isStatic();
if (!errorExpected) {
- throw new AssertionError(
- String.format("Diags found when compiling following code\n%s\n\n%s",
- source.source, dc.printDiags()));
+ fail("Diags found when compiling instance; " + res.compilationInfo());
}
return;
}
- verifyBytecode(id, source);
- }
-
- void verifyBytecode(int id, JavaSource source) {
- File compiledTest = new File(String.format("Test%d.class", id));
- try {
- ClassFile cf = ClassFile.read(compiledTest);
+ try (InputStream is = res.get().iterator().next().openInputStream()) {
+ ClassFile cf = ClassFile.read(is);
Method testMethod = null;
for (Method m : cf.methods) {
if (m.getName(cf.constant_pool).equals("test")) {
@@ -240,12 +218,14 @@
}
}
if (testMethod == null) {
- throw new Error("Test method not found");
+ fail("Test method not found");
+ return;
}
Code_attribute ea =
(Code_attribute)testMethod.attributes.get(Attribute.Code);
if (testMethod == null) {
- throw new Error("Code attribute for test() method not found");
+ fail("Code attribute for test() method not found");
+ return;
}
int bsmIdx = -1;
@@ -256,29 +236,34 @@
(CONSTANT_InvokeDynamic_info)cf
.constant_pool.get(i.getShort(1));
bsmIdx = indyInfo.bootstrap_method_attr_index;
- if (!indyInfo.getNameAndTypeInfo().getType().equals(makeIndyType(id))) {
- throw new
- AssertionError("type mismatch for CONSTANT_InvokeDynamic_info " + source.source + "\n" + indyInfo.getNameAndTypeInfo().getType() + "\n" + makeIndyType(id));
+ if (!indyInfo.getNameAndTypeInfo().getType().equals(makeIndyType())) {
+ fail("type mismatch for CONSTANT_InvokeDynamic_info " +
+ res.compilationInfo() + "\n" + indyInfo.getNameAndTypeInfo().getType() +
+ "\n" + makeIndyType());
+ return;
}
}
}
if (bsmIdx == -1) {
- throw new Error("Missing invokedynamic in generated code");
+ fail("Missing invokedynamic in generated code");
+ return;
}
BootstrapMethods_attribute bsm_attr =
(BootstrapMethods_attribute)cf
.getAttribute(Attribute.BootstrapMethods);
if (bsm_attr.bootstrap_method_specifiers.length != 1) {
- throw new Error("Bad number of method specifiers " +
+ fail("Bad number of method specifiers " +
"in BootstrapMethods attribute");
+ return;
}
BootstrapMethods_attribute.BootstrapMethodSpecifier bsm_spec =
bsm_attr.bootstrap_method_specifiers[0];
if (bsm_spec.bootstrap_arguments.length != MF_ARITY) {
- throw new Error("Bad number of static invokedynamic args " +
+ fail("Bad number of static invokedynamic args " +
"in BootstrapMethod attribute");
+ return;
}
CONSTANT_MethodHandle_info mh =
@@ -294,74 +279,27 @@
}
if (!kindOK) {
- throw new Error("Bad invoke kind in implementation method handle");
+ fail("Bad invoke kind in implementation method handle");
+ return;
}
if (!mh.getCPRefInfo().getNameAndTypeInfo().getType().toString().equals(MH_SIG)) {
- throw new Error("Type mismatch in implementation method handle");
+ fail("Type mismatch in implementation method handle");
+ return;
}
} catch (Exception e) {
e.printStackTrace();
- throw new Error("error reading " + compiledTest +": " + e);
+ fail("error reading " + res.compilationInfo() + ": " + e);
}
}
- String makeIndyType(int id) {
+
+ String makeIndyType() {
StringBuilder buf = new StringBuilder();
buf.append("(");
if (!mk2.isStatic()) {
- buf.append(String.format("LTest%d;", id));
+ buf.append("LTest;");
}
buf.append(")Ljava/lang/Runnable;");
return buf.toString();
}
-
- static final int MF_ARITY = 3;
- static final String MH_SIG = "()V";
-
- class JavaSource extends SimpleJavaFileObject {
-
- static final String source_template =
- "#CK Test#ID {\n" +
- " #MOD1 void test() { #EK }\n" +
- " #MOD2 void target() { }\n" +
- "}\n";
-
- String source;
-
- JavaSource(int id) {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
- source = source_template.replace("#CK", mk1.ck.classStr)
- .replace("#MOD1", mk1.mods())
- .replace("#MOD2", mk2.mods())
- .replace("#EK", ek.exprString)
- .replace("#ID", String.valueOf(id));
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
- }
- }
-
- static class DiagChecker
- implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- boolean diagFound;
- ArrayList<String> diags = new ArrayList<>();
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- diags.add(diagnostic.getMessage(Locale.getDefault()));
- diagFound = true;
- }
-
- String printDiags() {
- StringBuilder buf = new StringBuilder();
- for (String s : diags) {
- buf.append(s);
- buf.append("\n");
- }
- return buf.toString();
- }
- }
-
}
--- a/langtools/test/tools/javac/lambda/mostSpecific/StructuralMostSpecificTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/lambda/mostSpecific/StructuralMostSpecificTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,34 +23,36 @@
/*
* @test
- * @bug 8003280 8006694
+ * @bug 8003280 8006694 8129962
* @summary Add lambda tests
* Automatic test for checking correctness of structural most specific test routine
* temporarily workaround combo tests are causing time out in several platforms
- * @library ../../lib
+ * @library /tools/javac/lib
* @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
* jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm/timeout=600 StructuralMostSpecificTest
+ * @build combo.ComboTestHelper
+
+ * @run main StructuralMostSpecificTest
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
-import java.net.URI;
-import java.util.Arrays;
+import javax.lang.model.element.Element;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import com.sun.source.util.JavacTask;
import com.sun.tools.javac.api.ClientCodeWrapper;
import com.sun.tools.javac.util.JCDiagnostic;
+import com.sun.tools.javac.util.List;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
-public class StructuralMostSpecificTest
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
+public class StructuralMostSpecificTest extends ComboInstance<StructuralMostSpecificTest> {
- enum RetTypeKind {
+ enum RetTypeKind implements ComboParameter {
SHORT("short"),
INT("int"),
OBJECT("Object"),
@@ -76,9 +78,13 @@
/* INTEGER */ { false , false , true , true , false , false },
/* VOID */ { false , false , false , false , true , true },
/* J_L_VOID */{ false , false , true , false , false , true } };
+
+ public String expand(String optParameter) {
+ return retTypeStr;
+ }
}
- enum ArgTypeKind {
+ enum ArgTypeKind implements ComboParameter {
SHORT("short"),
INT("int"),
BOOLEAN("boolean"),
@@ -91,9 +97,13 @@
ArgTypeKind(String typeStr) {
this.argTypeStr = typeStr;
}
+
+ public String expand(String optParameter) {
+ return argTypeStr;
+ }
}
- enum ExceptionKind {
+ enum ExceptionKind implements ComboParameter {
NONE(""),
EXCEPTION("throws Exception"),
SQL_EXCEPTION("throws java.sql.SQLException"),
@@ -104,9 +114,13 @@
ExceptionKind(String exceptionStr) {
this.exceptionStr = exceptionStr;
}
+
+ public String expand(String optParameter) {
+ return exceptionStr;
+ }
}
- enum LambdaReturnKind {
+ enum LambdaReturnKind implements ComboParameter {
VOID("return;"),
SHORT("return (short)0;"),
INT("return 0;"),
@@ -144,118 +158,72 @@
/* INTEGER */ { false , false , true , false , false },
/* VOID */ { false , false , false , false , false },
/* J_L_VOID */{ true , false , false , false , false } };
- }
- public static void main(String... args) throws Exception {
- for (LambdaReturnKind lrk : LambdaReturnKind.values()) {
- for (RetTypeKind rk1 : RetTypeKind.values()) {
- for (RetTypeKind rk2 : RetTypeKind.values()) {
- for (ExceptionKind ek1 : ExceptionKind.values()) {
- for (ExceptionKind ek2 : ExceptionKind.values()) {
- for (ArgTypeKind ak11 : ArgTypeKind.values()) {
- for (ArgTypeKind ak12 : ArgTypeKind.values()) {
- pool.execute(
- new StructuralMostSpecificTest(lrk, rk1,
- rk2, ek1, ek2, ak11, ak12));
- }
- }
- }
- }
- }
- }
- }
-
- checkAfterExec();
- }
-
- LambdaReturnKind lrk;
- RetTypeKind rt1, rt2;
- ArgTypeKind ak1, ak2;
- ExceptionKind ek1, ek2;
- JavaSource source;
- DiagnosticChecker diagChecker;
-
- StructuralMostSpecificTest(LambdaReturnKind lrk, RetTypeKind rt1, RetTypeKind rt2,
- ExceptionKind ek1, ExceptionKind ek2, ArgTypeKind ak1, ArgTypeKind ak2) {
- this.lrk = lrk;
- this.rt1 = rt1;
- this.rt2 = rt2;
- this.ek1 = ek1;
- this.ek2 = ek2;
- this.ak1 = ak1;
- this.ak2 = ak2;
- this.source = new JavaSource();
- this.diagChecker = new DiagnosticChecker();
- }
-
- class JavaSource extends SimpleJavaFileObject {
-
- String template = "interface SAM1 {\n" +
- " #R1 m(#A1 a1) #E1;\n" +
- "}\n" +
- "interface SAM2 {\n" +
- " #R2 m(#A2 a1) #E2;\n" +
- "}\n" +
- "class Test {\n" +
- " void m(SAM1 s) { }\n" +
- " void m(SAM2 s) { }\n" +
- " { m((#A1 x)->{ #LR }); }\n" +
- "}\n";
-
- String source;
-
- public JavaSource() {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
- source = template.replaceAll("#LR", lrk.retStr)
- .replaceAll("#R1", rt1.retTypeStr)
- .replaceAll("#R2", rt2.retTypeStr)
- .replaceAll("#A1", ak1.argTypeStr)
- .replaceAll("#A2", ak2.argTypeStr)
- .replaceAll("#E1", ek1.exceptionStr)
- .replaceAll("#E2", ek2.exceptionStr);
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
+ public String expand(String optParameter) {
+ return retStr;
}
}
- public void run() {
- JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
- Arrays.asList("-XDverboseResolution=all,-predef,-internal,-object-init"),
- null, Arrays.asList(source));
- try {
- ct.analyze();
- } catch (Throwable ex) {
- throw new
- AssertionError("Error thron when analyzing the following source:\n" +
- source.getCharContent(true));
- }
- check();
+ static final String sourceTemplate =
+ "interface SAM1 {\n" +
+ " #{RET[0]} m(#{ARG[0]} a1) #{EX[0]};\n" +
+ "}\n" +
+ "interface SAM2 {\n" +
+ " #{RET[1]} m(#{ARG[1]} a1) #{EX[1]};\n" +
+ "}\n" +
+ "class Test {\n" +
+ " void m(SAM1 s) { }\n" +
+ " void m(SAM2 s) { }\n" +
+ " { m((#{ARG[0]} x)->{ #{EXPR} }); }\n" +
+ "}\n";
+
+ public static void main(String... args) throws Exception {
+ new ComboTestHelper<StructuralMostSpecificTest>()
+ .withFilter(StructuralMostSpecificTest::hasSameArguments)
+ .withFilter(StructuralMostSpecificTest::hasCompatibleReturns)
+ .withFilter(StructuralMostSpecificTest::hasSameOverloadPhase)
+ .withDimension("EXPR", (x, expr) -> x.lambdaReturnKind = expr, LambdaReturnKind.values())
+ .withArrayDimension("RET", (x, ret, idx) -> x.returnType[idx] = ret, 2, RetTypeKind.values())
+ .withArrayDimension("EX", 2, ExceptionKind.values())
+ .withArrayDimension("ARG", (x, arg, idx) -> x.argumentKind[idx] = arg, 2, ArgTypeKind.values())
+ .run(StructuralMostSpecificTest::new);
}
- void check() {
- checkCount.incrementAndGet();
+ LambdaReturnKind lambdaReturnKind;
+ RetTypeKind[] returnType = new RetTypeKind[2];
+ ArgTypeKind[] argumentKind = new ArgTypeKind[2];
- if (ak1 != ak2)
- return;
+ boolean hasSameArguments() {
+ return argumentKind[0] == argumentKind[1];
+ }
+
+ boolean hasCompatibleReturns() {
+ return lambdaReturnKind.compatibleWith(returnType[0]) &&
+ lambdaReturnKind.compatibleWith(returnType[1]);
+ }
- if (!lrk.compatibleWith(rt1) || !lrk.compatibleWith(rt2))
- return;
+ boolean hasSameOverloadPhase() {
+ return lambdaReturnKind.needsConversion(returnType[0]) == lambdaReturnKind.needsConversion(returnType[1]);
+ }
- if (lrk.needsConversion(rt1) != lrk.needsConversion(rt2))
- return;
+ @Override
+ public void doWork() throws Throwable {
+ check(newCompilationTask()
+ .withSourceFromTemplate(sourceTemplate)
+ .withOption("-XDverboseResolution=all,-predef,-internal,-object-init")
+ .analyze());
+ }
- boolean m1MoreSpecific = rt1.moreSpecificThan(rt2);
- boolean m2MoreSpecific = rt2.moreSpecificThan(rt1);
+ void check(Result<Iterable<? extends Element>> result) {
+ boolean m1MoreSpecific = returnType[0].moreSpecificThan(returnType[1]);
+ boolean m2MoreSpecific = returnType[1].moreSpecificThan(returnType[0]);
boolean ambiguous = (m1MoreSpecific == m2MoreSpecific);
- if (ambiguous != diagChecker.ambiguityFound) {
- throw new Error("invalid diagnostics for source:\n" +
- source.getCharContent(true) +
- "\nAmbiguity found: " + diagChecker.ambiguityFound +
+ if (ambiguous != ambiguityFound(result)) {
+ fail("invalid diagnostics for combo:\n" +
+ result.compilationInfo() + "\n" +
+ "\nAmbiguity found: " + ambiguityFound(result) +
"\nm1 more specific: " + m1MoreSpecific +
"\nm2 more specific: " + m2MoreSpecific +
"\nexpected ambiguity: " + ambiguous);
@@ -263,44 +231,32 @@
if (!ambiguous) {
String sigToCheck = m1MoreSpecific ? "m(SAM1)" : "m(SAM2)";
- if (!sigToCheck.equals(diagChecker.mostSpecificSig)) {
- throw new Error("invalid most specific method selected:\n" +
- source.getCharContent(true) +
- "\nMost specific found: " + diagChecker.mostSpecificSig +
- "\nm1 more specific: " + m1MoreSpecific +
- "\nm2 more specific: " + m2MoreSpecific);
+ if (!sigToCheck.equals(mostSpecificSignature(result))) {
+ fail("invalid most specific method selected:\n" +
+ result.compilationInfo() + "\n" +
+ "\nMost specific found: " + mostSpecificSignature(result) +
+ "\nm1 more specific: " + m1MoreSpecific +
+ "\nm2 more specific: " + m2MoreSpecific);
}
}
}
- static class DiagnosticChecker
- implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- boolean ambiguityFound;
- String mostSpecificSig;
+ boolean ambiguityFound(Result<Iterable<? extends Element>> result) {
+ return result.containsKey("compiler.err.ref.ambiguous");
+ }
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- try {
- if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
- diagnostic.getCode().equals("compiler.err.ref.ambiguous")) {
- ambiguityFound = true;
- } else if (diagnostic.getKind() == Diagnostic.Kind.NOTE &&
- diagnostic.getCode()
- .equals("compiler.note.verbose.resolve.multi")) {
- ClientCodeWrapper.DiagnosticSourceUnwrapper dsu =
- (ClientCodeWrapper.DiagnosticSourceUnwrapper)diagnostic;
- JCDiagnostic.MultilineDiagnostic mdiag =
- (JCDiagnostic.MultilineDiagnostic)dsu.d;
- int mostSpecificIndex = (Integer)mdiag.getArgs()[2];
- mostSpecificSig =
- ((JCDiagnostic)mdiag.getSubdiagnostics()
- .get(mostSpecificIndex)).getArgs()[1].toString();
- }
- } catch (RuntimeException t) {
- t.printStackTrace();
- throw t;
- }
+ String mostSpecificSignature(Result<Iterable<? extends Element>> result) {
+ List<Diagnostic<? extends JavaFileObject>> rsDiag =
+ result.diagnosticsForKey("compiler.note.verbose.resolve.multi");
+ if (rsDiag.nonEmpty()) {
+ ClientCodeWrapper.DiagnosticSourceUnwrapper dsu =
+ (ClientCodeWrapper.DiagnosticSourceUnwrapper)rsDiag.head;
+ JCDiagnostic.MultilineDiagnostic mdiag =
+ (JCDiagnostic.MultilineDiagnostic)dsu.d;
+ int mostSpecificIndex = (Integer)mdiag.getArgs()[2];
+ return mdiag.getSubdiagnostics().get(mostSpecificIndex).getArgs()[1].toString();
+ } else {
+ return null;
}
}
-
}
--- a/langtools/test/tools/javac/lambda/typeInference/combo/TypeInferenceComboTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/lambda/typeInference/combo/TypeInferenceComboTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,31 +23,31 @@
/**
* @test
- * @bug 8003280 8006694
+ * @bug 8003280 8006694 8129962
* @summary Add lambda tests
* perform automated checks in type inference in lambda expressions
* in different contexts
* temporarily workaround combo tests are causing time out in several platforms
- * @library ../../../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
* @compile TypeInferenceComboTest.java
- * @run main/othervm/timeout=360 TypeInferenceComboTest
+ * @run main TypeInferenceComboTest
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import com.sun.source.util.JavacTask;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
-public class TypeInferenceComboTest
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
+public class TypeInferenceComboTest extends ComboInstance<TypeInferenceComboTest> {
enum Context {
ASSIGNMENT("SAM#Type s = #LBody;"),
METHOD_CALL("#GenericDeclKind void method1(SAM#Type s) { }\n" +
@@ -221,82 +221,21 @@
}
}
- boolean checkTypeInference() {
- if (parameterType == TypeKind.VOID) {
- if (lambdaBodyType != LambdaBody.RETURN_VOID)
- return false;
- }
- else if (lambdaBodyType != LambdaBody.RETURN_ARG)
- return false;
-
- return true;
- }
-
- String templateStr = "#C\n" +
- "interface SAM2 {\n" +
- " SAM m();\n" +
- "}\n";
- SourceFile samSourceFile = new SourceFile("Sam.java", templateStr) {
- public String toString() {
- return template.replaceAll("#C",
- samKind.getSam(parameterType, returnType));
- }
- };
-
- SourceFile clientSourceFile = new SourceFile("Client.java",
- "class Client { \n" +
- " #Context\n" +
- "}") {
- public String toString() {
- return template.replaceAll("#Context",
- context.getContext(samKind, samTargetType, keyword,
- parameterType, returnType, lambdaKind, parameterKind,
- genericDeclKind, lambdaBodyType));
- }
- };
-
- public void run() {
- DiagnosticChecker dc = new DiagnosticChecker();
- JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), dc,
- null, null, Arrays.asList(samSourceFile, clientSourceFile));
- try {
- ct.analyze();
- } catch (Throwable t) {
- processException(t);
- }
- if (dc.errorFound == checkTypeInference()) {
- throw new AssertionError(samSourceFile + "\n\n" +
- clientSourceFile + "\n" + parameterType + " " + returnType);
- }
- }
-
- abstract class SourceFile extends SimpleJavaFileObject {
-
- protected String template;
-
- public SourceFile(String filename, String template) {
- super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
- this.template = template;
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return toString();
- }
-
- public abstract String toString();
- }
-
- static class DiagnosticChecker
- implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- boolean errorFound = false;
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
- errorFound = true;
- }
- }
+ public static void main(String[] args) {
+ new ComboTestHelper<TypeInferenceComboTest>()
+ .withFilter(TypeInferenceComboTest::badTestFilter)
+ .withFilter(TypeInferenceComboTest::redundantTestFilter)
+ .withDimension("SAM", (x, sam) -> x.samKind = sam, SamKind.values())
+ .withDimension("SAMTARGET", (x, target) -> x.samTargetType = target, TypeKind.values())
+ .withDimension("PARAMTYPE", (x, param) -> x.parameterType = param, TypeKind.values())
+ .withDimension("RETTYPE", (x, ret) -> x.returnType = ret, TypeKind.values())
+ .withDimension("CTX", (x, ctx) -> x.context = ctx, Context.values())
+ .withDimension("LAMBDABODY", (x, body) -> x.lambdaBodyType = body, LambdaBody.values())
+ .withDimension("LAMBDAKIND", (x, lambda) -> x.lambdaKind = lambda, LambdaKind.values())
+ .withDimension("PARAMKIND", (x, param) -> x.parameterKind = param, ParameterKind.values())
+ .withDimension("KEYWORD", (x, kw) -> x.keyword = kw, Keyword.values())
+ .withDimension("GENDECL", (x, gk) -> x.genericDeclKind = gk, GenericDeclKind.values())
+ .run(TypeInferenceComboTest::new);
}
SamKind samKind;
@@ -310,84 +249,75 @@
Keyword keyword;
GenericDeclKind genericDeclKind;
- TypeInferenceComboTest(SamKind sk, TypeKind samTargetT, TypeKind parameterT,
- TypeKind returnT, LambdaBody lb, Context c, LambdaKind lk,
- ParameterKind pk, Keyword kw, GenericDeclKind gdk) {
- samKind = sk;
- samTargetType = samTargetT;
- parameterType = parameterT;
- returnType = returnT;
- context = c;
- lambdaKind = lk;
- parameterKind = pk;
- keyword = kw;
- lambdaBodyType = lb;
- genericDeclKind = gdk;
+ boolean badTestFilter() {
+ if (samKind == SamKind.NON_GENERIC) {
+ return (parameterType != TypeKind.GENERIC && returnType != TypeKind.GENERIC);
+ } else {
+ return (samTargetType != TypeKind.VOID &&
+ samTargetType != TypeKind.INT &&
+ samTargetType != TypeKind.GENERIC &&
+ (parameterType == TypeKind.GENERIC ||
+ returnType == TypeKind.GENERIC));
+ }
}
- public static void main(String[] args) throws Exception {
- for(Context ct : Context.values()) {
- for (TypeKind returnT : TypeKind.values()) {
- for (TypeKind parameterT : TypeKind.values()) {
- for(LambdaBody lb : LambdaBody.values()) {
- for (ParameterKind parameterK : ParameterKind.values()) {
- for(LambdaKind lambdaK : LambdaKind.values()) {
- for (SamKind sk : SamKind.values()) {
- if (sk == SamKind.NON_GENERIC) {
- generateNonGenericSAM(ct, returnT,
- parameterT, lb, parameterK,
- lambdaK, sk);
- }
- else if (sk == SamKind.GENERIC) {
- generateGenericSAM(ct, returnT,
- parameterT, lb, parameterK,
- lambdaK, sk);
- }
- }
- }
- }
- }
- }
- }
- }
-
- checkAfterExec(false);
- }
-
- static void generateNonGenericSAM(Context ct, TypeKind returnT,
- TypeKind parameterT, LambdaBody lb, ParameterKind parameterK,
- LambdaKind lambdaK, SamKind sk) {
- if(parameterT != TypeKind.GENERIC && returnT != TypeKind.GENERIC ) {
- pool.execute(new TypeInferenceComboTest(sk, null, parameterT,
- returnT, lb, ct, lambdaK, parameterK, null, null));
+ boolean redundantTestFilter() {
+ if (samKind == SamKind.NON_GENERIC) {
+ return keyword.ordinal() == 0 && samTargetType.ordinal() == 0 && genericDeclKind.ordinal() == 0;
+ } else {
+ return context == Context.METHOD_CALL || genericDeclKind.ordinal() == 0;
}
}
- static void generateGenericSAM(Context ct, TypeKind returnT,
- TypeKind parameterT, LambdaBody lb, ParameterKind parameterK,
- LambdaKind lambdaK, SamKind sk) {
- for (Keyword kw : Keyword.values()) {
- for (TypeKind samTargetT : TypeKind.values()) {
- if(samTargetT != TypeKind.VOID &&
- samTargetT != TypeKind.INT &&
- samTargetT != TypeKind.GENERIC &&
- (parameterT == TypeKind.GENERIC ||
- returnT == TypeKind.GENERIC)) {
- if(ct != Context.METHOD_CALL) {
- pool.execute(
- new TypeInferenceComboTest(sk, samTargetT, parameterT,
- returnT, lb, ct, lambdaK, parameterK, kw, null));
- } else {//Context.METHOD_CALL
- for (GenericDeclKind gdk :
- GenericDeclKind.values())
- pool.execute(
- new TypeInferenceComboTest(sk, samTargetT,
- parameterT, returnT, lb, ct, lambdaK,
- parameterK, kw, gdk));
- }
- }
- }
- }
+ String sam_template = "#{SAM}\n" +
+ "interface SAM2 {\n" +
+ " SAM m();\n" +
+ "}\n";
+
+
+ String client_template = "class Client { \n" +
+ " #{CONTEXT}\n" +
+ "}";
+
+ @Override
+ public void doWork() throws IOException {
+ Result<?> res = newCompilationTask()
+ .withSourceFromTemplate("Sam", sam_template, this::samClass)
+ .withSourceFromTemplate("Client", client_template, this::clientContext)
+ .analyze();
+
+ if (res.hasErrors() == checkTypeInference()) {
+ fail("Unexpected compilation output when compiling instance: " + res.compilationInfo());
+ }
}
+ ComboParameter samClass(String parameterName) {
+ switch (parameterName) {
+ case "SAM":
+ return new ComboParameter.Constant<>(samKind.getSam(parameterType, returnType));
+ default:
+ return null;
+ }
+ }
+
+ ComboParameter clientContext(String parameterName) {
+ switch (parameterName) {
+ case "CONTEXT":
+ return new ComboParameter.Constant<>(context.getContext(samKind, samTargetType,
+ keyword, parameterType, returnType, lambdaKind, parameterKind, genericDeclKind, lambdaBodyType));
+ default:
+ return null;
+ }
+ }
+
+ boolean checkTypeInference() {
+ if (parameterType == TypeKind.VOID) {
+ if (lambdaBodyType != LambdaBody.RETURN_VOID)
+ return false;
+ }
+ else if (lambdaBodyType != LambdaBody.RETURN_ARG)
+ return false;
+
+ return true;
+ }
}
--- a/langtools/test/tools/javac/lib/JavacTestingAbstractThreadedTest.java Tue Sep 08 16:01:29 2015 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +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.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.tools.JavaCompiler;
-import javax.tools.StandardJavaFileManager;
-import javax.tools.ToolProvider;
-
-/**
- * An abstract superclass for threaded tests.
- *
- * This class will try to read a property named test.concurrency.
- * The property can be provided by passing this option to jtreg:
- * -javaoption:-Dtest.concurrency=#
- *
- * If the property is not set the class will use a heuristic to determine the
- * maximum number of threads that can be fired to execute a given test.
- *
- * This code will have to be revisited if jprt starts using concurrency for
- * for running jtreg tests.
- */
-public abstract class JavacTestingAbstractThreadedTest {
-
- protected static AtomicInteger numberOfThreads = new AtomicInteger();
-
- protected static int getThreadPoolSize() {
- Integer testConc = Integer.getInteger("test.concurrency");
- if (testConc != null) return testConc;
- int cores = Runtime.getRuntime().availableProcessors();
- numberOfThreads.set(Math.max(2, Math.min(8, cores / 2)));
- return numberOfThreads.get();
- }
-
- protected static void checkAfterExec() throws InterruptedException {
- checkAfterExec(true);
- };
-
- protected static boolean throwAssertionOnError = true;
-
- protected static boolean printAll = false;
-
- protected static StringWriter errSWriter = new StringWriter();
- protected static PrintWriter errWriter = new PrintWriter(errSWriter);
-
- protected static StringWriter outSWriter = new StringWriter();
- protected static PrintWriter outWriter = new PrintWriter(outSWriter);
-
- protected static void checkAfterExec(boolean printCheckCount)
- throws InterruptedException {
- pool.shutdown();
- pool.awaitTermination(15, TimeUnit.MINUTES);
- if (errCount.get() > 0) {
- if (throwAssertionOnError) {
- closePrinters();
- System.err.println(errSWriter.toString());
- throw new AssertionError(
- String.format("%d errors found", errCount.get()));
- } else {
- System.err.println(
- String.format("%d errors found", errCount.get()));
- }
- } else if (printCheckCount) {
- outWriter.println("Total check executed: " + checkCount.get());
- }
- /*
- * This output is for supporting debugging. It does not mean that a given
- * test had executed that number of threads concurrently. The value printed
- * here is the maximum possible amount.
- */
- closePrinters();
- if (printAll) {
- System.out.println(errSWriter.toString());
- System.out.println(outSWriter.toString());
- }
- System.out.println("Total number of threads in thread pool: " +
- numberOfThreads.get());
- }
-
- protected static void closePrinters() {
- errWriter.close();
- outWriter.close();
- }
-
- protected static void processException(Throwable t) {
- errCount.incrementAndGet();
- t.printStackTrace(errWriter);
- pool.shutdown();
- }
-
- //number of checks executed
- protected static AtomicInteger checkCount = new AtomicInteger();
-
- //number of errors found while running combo tests
- protected static AtomicInteger errCount = new AtomicInteger();
-
- //create default shared JavaCompiler - reused across multiple compilations
- protected static JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
-
- protected static ExecutorService pool = Executors.newFixedThreadPool(
- getThreadPoolSize(), new ThreadFactory() {
- @Override
- public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
- @Override
- public void uncaughtException(Thread t, Throwable e) {
- pool.shutdown();
- errCount.incrementAndGet();
- e.printStackTrace(System.err);
- }
- });
- return t;
- }
- });
-
- /*
- * File manager is not thread-safe so it cannot be re-used across multiple
- * threads. However we cache per-thread FileManager to avoid excessive
- * object creation
- */
- protected static final ThreadLocal<StandardJavaFileManager> fm =
- new ThreadLocal<StandardJavaFileManager>() {
- @Override protected StandardJavaFileManager initialValue() {
- return comp.getStandardFileManager(null, null, null);
- }
- };
-
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lib/combo/ComboInstance.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+
+package combo;
+
+import javax.tools.StandardJavaFileManager;
+import java.util.Optional;
+
+/**
+ * This class is the common superclass of all combo test instances. It defines few helper methods
+ * to build compilation tasks using the shared context object, as well as entry points for
+ * signalling test failures.
+ */
+public abstract class ComboInstance<X extends ComboInstance<X>> {
+
+ /** The test instance result status. */
+ private ResultStatus resultStatus = ResultStatus.PASSED;
+
+ /** The test instance execution environment. */
+ private ComboTestHelper<X>.Env env;
+
+ /**
+ * Entry point for executing a combo test instance; first, the test environment is saved
+ * in the corresponding field, then the instance is run (see {@link ComboInstance#doWork()}.
+ * During execution, the result status will be updated to match the test outcome.
+ */
+ final void run(ComboTestHelper<X>.Env env) {
+ try {
+ this.env = env;
+ doWork();
+ if (resultStatus.isSuccess()) {
+ env.info().passCount++;
+ }
+ } catch (Throwable ex) {
+ resultStatus = ResultStatus.ERROR;
+ env.info().errCount++;
+ env.info().lastError = Optional.of(ex);
+ } finally {
+ this.env = null;
+ }
+ }
+
+ /**
+ * Retrieve a unique ID associated with this test instance.
+ */
+ public int id() {
+ return env.info().comboCount;
+ }
+
+ /**
+ * Retrieve shared file manager.
+ */
+ public StandardJavaFileManager fileManager() {
+ return env.fileManager();
+ }
+
+ /**
+ * Create a new compilation task using shared compilation context.
+ */
+ protected ComboTask newCompilationTask() {
+ return new ComboTask(env);
+ }
+
+ /**
+ * Main test execution entry point; subclasses must implement this method to define the test
+ * logic.
+ */
+ protected abstract void doWork() throws Throwable;
+
+ /**
+ * Report a test failure.
+ */
+ protected void fail() {
+ //dump some default info (such as dimension bindings)
+ fail("Combo instance failed; " + env.bindings);
+ }
+
+ /**
+ * Report a test failure with corresponding failure message.
+ */
+ protected void fail(String msg) {
+ resultStatus = ResultStatus.FAILED;
+ env.info().failCount++;
+ env.info().lastFailure = Optional.of(msg);
+ }
+
+ /**
+ * The status associated with this test instance execution.
+ */
+ enum ResultStatus {
+ /** Test passed. */
+ PASSED(true),
+ /** Test failed. */
+ FAILED(false),
+ /** Test thrown unexpected error/exception. */
+ ERROR(false);
+
+ boolean success;
+
+ ResultStatus(boolean success) {
+ this.success = success;
+ }
+
+ boolean isSuccess() {
+ return success;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lib/combo/ComboParameter.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+
+package combo;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A combo parameter represents an 'hole' in a template that can be replaced with a given string.
+ * The schema of such holes is defined in {@link ComboParameter#pattern}; the main routine for
+ * replacing holes in a template scheme is {@link ComboParameter#expandTemplate(String, Resolver)}.
+ */
+public interface ComboParameter {
+
+ /**
+ * A combo parameter can take the form:
+ * <p>
+ * #{MAJOR}
+ * #{MAJOR.}
+ * #{MAJOR.MINOR}
+ * <p>
+ * where MAJOR can be IDENTIFIER or IDENTIFIER[NUMERIC_INDEX]
+ * and MINOR can be an identifier.
+ */
+ Pattern pattern = Pattern.compile("#\\{([A-Z_][A-Z0-9_]*(?:\\[\\d+\\])?)(?:\\.([A-Z0-9_]*))?\\}");
+
+ /**
+ * Entry point for the customizable replacement logic. Subclasses must implement this method to
+ * specify how a given template hole should be expanded. An optional contextual argument is passed
+ * in as parameter, to make expansion more flexible.
+ */
+ String expand(String optParameter);
+
+ /**
+ * Helper class for defining 'constant' combo parameters - i.e. parameters that always expand
+ * as a given string value - regardless of the context.
+ */
+ class Constant<D> implements ComboParameter {
+
+ D data;
+
+ public Constant(D data) {
+ this.data = data;
+ }
+
+ @Override
+ public String expand(String _unused) {
+ return String.valueOf(data);
+ }
+ }
+
+ /**
+ * Helper interface used to lookup parameters given a parameter name.
+ */
+ interface Resolver {
+ ComboParameter lookup(String name);
+ }
+
+ /**
+ * Main routine for replacing holes in a template string. Holes are repeatedly searches, their
+ * corresponding parameters retrieved, and replaced through expansion; since an expansion can
+ * lead to more holes, the process has to be applied until a fixed point is reached.
+ */
+ static String expandTemplate(String template, Resolver resolver) {
+ CharSequence in = template;
+ StringBuffer out = new StringBuffer();
+ while (true) {
+ boolean more = false;
+ Matcher m = pattern.matcher(in);
+ while (m.find()) {
+ String parameterName = m.group(1);
+ String minor = m.group(2);
+ ComboParameter parameter = resolver.lookup(parameterName);
+ if (parameter == null) {
+ throw new IllegalStateException("Unhandled parameter name " + parameterName);
+ }
+
+ String replacement = parameter.expand(minor);
+ more |= pattern.matcher(replacement).find();
+ m.appendReplacement(out, replacement);
+ }
+ m.appendTail(out);
+ if (!more)
+ return out.toString();
+ else {
+ in = out;
+ out = new StringBuffer();
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lib/combo/ComboTask.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+
+package combo;
+
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TaskEvent.Kind;
+import com.sun.source.util.TaskListener;
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.util.List;
+import combo.ComboParameter.Resolver;
+
+import javax.lang.model.element.Element;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import java.io.IOException;
+import java.io.Writer;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+/**
+ * This class represents a compilation task associated with a combo test instance. This is a small
+ * wrapper around {@link JavacTask} which allows for fluent setup style and which makes use of
+ * the shared compilation context to speedup performances.
+ */
+public class ComboTask {
+
+ /** Sources to be compiled in this task. */
+ private List<JavaFileObject> sources = List.nil();
+
+ /** Options associated with this task. */
+ private List<String> options = List.nil();
+
+ /** Diagnostic collector. */
+ private DiagnosticCollector diagsCollector = new DiagnosticCollector();
+
+ /** Output writer. */
+ private Writer out;
+
+ /** Listeners associated with this task. */
+ private List<TaskListener> listeners = List.nil();
+
+ /** Underlying javac task object. */
+ private JavacTask task;
+
+ /** Combo execution environment. */
+ private ComboTestHelper<?>.Env env;
+
+ ComboTask(ComboTestHelper<?>.Env env) {
+ this.env = env;
+ }
+
+ /**
+ * Add a new source to this task.
+ */
+ public ComboTask withSource(JavaFileObject comboSource) {
+ sources = sources.prepend(comboSource);
+ return this;
+ }
+
+ /**
+ * Add a new template source with given name to this task; the template is replaced with
+ * corresponding combo parameters (as defined in the combo test environment).
+ */
+ public ComboTask withSourceFromTemplate(String name, String template) {
+ return withSource(new ComboTemplateSource(name, template));
+ }
+
+ /**
+ * Add a new template source with default name ("Test") to this task; the template is replaced with
+ * corresponding combo parameters (as defined in the combo test environment).
+ */
+ public ComboTask withSourceFromTemplate(String template) {
+ return withSource(new ComboTemplateSource("Test", template));
+ }
+
+ /**
+ * Add a new template source with given name to this task; the template is replaced with
+ * corresponding combo parameters (as defined in the combo test environment). A custom resolver
+ * is used to add combo parameter mappings to the current combo test environment.
+ */
+ public ComboTask withSourceFromTemplate(String name, String template, Resolver resolver) {
+ return withSource(new ComboTemplateSource(name, template, resolver));
+ }
+
+ /**
+ * Add a new template source with default name ("Test") to this task; the template is replaced with
+ * corresponding combo parameters (as defined in the combo test environment). A custom resolver
+ * is used to add combo parameter mappings to the current combo test environment.
+ */
+ public ComboTask withSourceFromTemplate(String template, Resolver resolver) {
+ return withSource(new ComboTemplateSource("Test", template, resolver));
+ }
+
+ /**
+ * Add a new option to this task.
+ */
+ public ComboTask withOption(String opt) {
+ options = options.append(opt);
+ return this;
+ }
+
+ /**
+ * Add a set of options to this task.
+ */
+ public ComboTask withOptions(String[] opts) {
+ for (String opt : opts) {
+ options = options.append(opt);
+ }
+ return this;
+ }
+
+ /**
+ * Add a set of options to this task.
+ */
+ public ComboTask withOptions(Iterable<? extends String> opts) {
+ for (String opt : opts) {
+ options = options.append(opt);
+ }
+ return this;
+ }
+
+ /**
+ * Set the output writer associated with this task.
+ */
+ public ComboTask withWriter(Writer out) {
+ this.out = out;
+ return this;
+ }
+
+ /**
+ * Add a task listener to this task.
+ */
+ public ComboTask withListener(TaskListener listener) {
+ listeners = listeners.prepend(listener);
+ return this;
+ }
+
+ /**
+ * Parse the sources associated with this task.
+ */
+ public Result<Iterable<? extends CompilationUnitTree>> parse() throws IOException {
+ return new Result<>(getTask().parse());
+ }
+
+ /**
+ * Parse and analyzes the sources associated with this task.
+ */
+ public Result<Iterable<? extends Element>> analyze() throws IOException {
+ return new Result<>(getTask().analyze());
+ }
+
+ /**
+ * Parse, analyze and perform code generation for the sources associated with this task.
+ */
+ public Result<Iterable<? extends JavaFileObject>> generate() throws IOException {
+ return new Result<>(getTask().generate());
+ }
+
+ /**
+ * Fork a new compilation task; if possible the compilation context from previous executions is
+ * retained (see comments in ReusableContext as to when it's safe to do so); otherwise a brand
+ * new context is created.
+ */
+ public JavacTask getTask() {
+ if (task == null) {
+ ReusableContext context = env.context();
+ String opts = options == null ? "" :
+ StreamSupport.stream(options.spliterator(), false).collect(Collectors.joining());
+ context.clear();
+ if (!context.polluted && (context.opts == null || context.opts.equals(opts))) {
+ //we can reuse former context
+ env.info().ctxReusedCount++;
+ } else {
+ env.info().ctxDroppedCount++;
+ //it's not safe to reuse context - create a new one
+ context = env.setContext(new ReusableContext());
+ }
+ context.opts = opts;
+ JavacTask javacTask = ((JavacTool)env.javaCompiler()).getTask(out, env.fileManager(),
+ diagsCollector, options, null, sources, context);
+ javacTask.setTaskListener(context);
+ for (TaskListener l : listeners) {
+ javacTask.addTaskListener(l);
+ }
+ task = javacTask;
+ }
+ return task;
+ }
+
+ /**
+ * This class is used to help clients accessing the results of a given compilation task.
+ * Contains several helper methods to inspect diagnostics generated during the task execution.
+ */
+ public class Result<D> {
+
+ /** The underlying compilation results. */
+ private final D data;
+
+ public Result(D data) {
+ this.data = data;
+ }
+
+ public D get() {
+ return data;
+ }
+
+ /**
+ * Did this task generate any error diagnostics?
+ */
+ public boolean hasErrors() {
+ return diagsCollector.diagsByKind.containsKey(Diagnostic.Kind.ERROR);
+ }
+
+ /**
+ * Did this task generate any warning diagnostics?
+ */
+ public boolean hasWarnings() {
+ return diagsCollector.diagsByKind.containsKey(Diagnostic.Kind.WARNING);
+ }
+
+ /**
+ * Did this task generate any note diagnostics?
+ */
+ public boolean hasNotes() {
+ return diagsCollector.diagsByKind.containsKey(Diagnostic.Kind.NOTE);
+ }
+
+ /**
+ * Did this task generate any diagnostic with given key?
+ */
+ public boolean containsKey(String key) {
+ return diagsCollector.diagsByKeys.containsKey(key);
+ }
+
+ /**
+ * Retrieve the list of diagnostics of a given kind.
+ */
+ public List<Diagnostic<? extends JavaFileObject>> diagnosticsForKind(Diagnostic.Kind kind) {
+ List<Diagnostic<? extends JavaFileObject>> diags = diagsCollector.diagsByKind.get(kind);
+ return diags != null ? diags : List.nil();
+ }
+
+ /**
+ * Retrieve the list of diagnostics with given key.
+ */
+ public List<Diagnostic<? extends JavaFileObject>> diagnosticsForKey(String key) {
+ List<Diagnostic<? extends JavaFileObject>> diags = diagsCollector.diagsByKeys.get(key);
+ return diags != null ? diags : List.nil();
+ }
+
+ /**
+ * Dump useful info associated with this task.
+ */
+ public String compilationInfo() {
+ return "instance#" + env.info().comboCount + ":[ options = " + options
+ + ", diagnostics = " + diagsCollector.diagsByKeys.keySet()
+ + ", dimensions = " + env.bindings
+ + ", sources = \n" + sources.stream().map(s -> {
+ try {
+ return s.getCharContent(true);
+ } catch (IOException ex) {
+ return "";
+ }
+ }).collect(Collectors.joining(",")) + "]";
+ }
+ }
+
+ /**
+ * This class represents a Java source file whose contents are defined in terms of a template
+ * string. The holes in such template are expanded using corresponding combo parameter
+ * instances which can be retrieved using a resolver object.
+ */
+ class ComboTemplateSource extends SimpleJavaFileObject {
+
+ String source;
+ Map<String, ComboParameter> localParametersCache = new HashMap<>();
+
+ protected ComboTemplateSource(String name, String template) {
+ this(name, template, null);
+ }
+
+ protected ComboTemplateSource(String name, String template, Resolver resolver) {
+ super(URI.create("myfo:/" + env.info().comboCount + "/" + name + ".java"), Kind.SOURCE);
+ source = ComboParameter.expandTemplate(template, pname -> resolveParameter(pname, resolver));
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return source;
+ }
+
+ /**
+ * Combo parameter resolver function. First parameters are looked up in the global environment,
+ * then the local environment is looked up as a fallback.
+ */
+ ComboParameter resolveParameter(String pname, Resolver resolver) {
+ //first search the env
+ ComboParameter parameter = env.parametersCache.get(pname);
+ if (parameter == null) {
+ //then lookup local cache
+ parameter = localParametersCache.get(pname);
+ if (parameter == null && resolver != null) {
+ //if still null and we have a custom resolution function, try that
+ parameter = resolver.lookup(pname);
+ if (parameter != null) {
+ //if a match was found, store it in the local cache to aviod redundant recomputation
+ localParametersCache.put(pname, parameter);
+ }
+ }
+ }
+ return parameter;
+ }
+ }
+
+ /**
+ * Helper class to collect all diagnostic generated during the execution of a given compilation task.
+ */
+ class DiagnosticCollector implements DiagnosticListener<JavaFileObject> {
+
+ Map<Diagnostic.Kind, List<Diagnostic<? extends JavaFileObject>>> diagsByKind = new HashMap<>();
+ Map<String, List<Diagnostic<? extends JavaFileObject>>> diagsByKeys = new HashMap<>();
+
+ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ List<Diagnostic<? extends JavaFileObject>> diags =
+ diagsByKeys.getOrDefault(diagnostic.getCode(), List.nil());
+ diagsByKeys.put(diagnostic.getCode(), diags.prepend(diagnostic));
+ Diagnostic.Kind kind = diagnostic.getKind();
+ diags = diagsByKind.getOrDefault(kind, List.nil());
+ diagsByKind.put(kind, diags.prepend(diagnostic));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lib/combo/ComboTestHelper.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+
+package combo;
+
+import javax.tools.JavaCompiler;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Stack;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+
+/**
+ * An helper class for defining combinatorial (aka "combo" tests). A combo test is made up of one
+ * or more 'dimensions' - each of which represent a different axis of the test space. For instance,
+ * if we wanted to test class/interface declaration, one dimension could be the keyword used for
+ * the declaration (i.e. 'class' vs. 'interface') while another dimension could be the class/interface
+ * modifiers (i.e. 'public', 'pachake-private' etc.). A combo test consists in running a test instance
+ * for each point in the test space; that is, for any combination of the combo test dimension:
+ * <p>
+ * 'public' 'class'
+ * 'public' interface'
+ * 'package-private' 'class'
+ * 'package-private' 'interface'
+ * ...
+ * <p>
+ * A new test instance {@link ComboInstance} is created, and executed, after its dimensions have been
+ * initialized accordingly. Each instance can either pass, fail or throw an unexpected error; this helper
+ * class defines several policies for how failures should be handled during a combo test execution
+ * (i.e. should errors be ignored? Do we want the first failure to result in a failure of the whole
+ * combo test?).
+ * <p>
+ * Additionally, this helper class allows to specify filter methods that can be used to throw out
+ * illegal combinations of dimensions - for instance, in the example above, we might want to exclude
+ * all combinations involving 'protected' and 'private' modifiers, which are disallowed for toplevel
+ * declarations.
+ * <p>
+ * While combo tests can be used for a variety of workloads, typically their main task will consist
+ * in performing some kind of javac compilation. For this purpose, this framework defines an optimized
+ * javac context {@link ReusableContext} which can be shared across multiple combo instances,
+ * when the framework detects it's safe to do so. This allows to reduce the overhead associated with
+ * compiler initialization when the test space is big.
+ */
+public class ComboTestHelper<X extends ComboInstance<X>> {
+
+ /** Failure mode. */
+ FailMode failMode = FailMode.FAIL_FAST;
+
+ /** Ignore mode. */
+ IgnoreMode ignoreMode = IgnoreMode.IGNORE_NONE;
+
+ /** Combo test instance filter. */
+ Optional<Predicate<X>> optFilter = Optional.empty();
+
+ /** Combo test dimensions. */
+ List<DimensionInfo<?>> dimensionInfos = new ArrayList<>();
+
+ /** Combo test stats. */
+ Info info = new Info();
+
+ /** Shared JavaCompiler used across all combo test instances. */
+ JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+
+ /** Shared file manager used across all combo test instances. */
+ StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+
+ /** Shared context used across all combo instances. */
+ ReusableContext context = new ReusableContext();
+
+ /**
+ * Set failure mode for this combo test.
+ */
+ public ComboTestHelper<X> withFailMode(FailMode failMode) {
+ this.failMode = failMode;
+ return this;
+ }
+
+ /**
+ * Set ignore mode for this combo test.
+ */
+ public ComboTestHelper<X> withIgnoreMode(IgnoreMode ignoreMode) {
+ this.ignoreMode = ignoreMode;
+ return this;
+ }
+
+ /**
+ * Set a filter for combo test instances to be ignored.
+ */
+ public ComboTestHelper<X> withFilter(Predicate<X> filter) {
+ optFilter = Optional.of(optFilter.map(filter::and).orElse(filter));
+ return this;
+ }
+
+ /**
+ * Adds a new dimension to this combo test, with a given name an array of values.
+ */
+ @SafeVarargs
+ public final <D> ComboTestHelper<X> withDimension(String name, D... dims) {
+ return withDimension(name, null, dims);
+ }
+
+ /**
+ * Adds a new dimension to this combo test, with a given name, an array of values and a
+ * coresponding setter to be called in order to set the dimension value on the combo test instance
+ * (before test execution).
+ */
+ @SuppressWarnings("unchecked")
+ @SafeVarargs
+ public final <D> ComboTestHelper<X> withDimension(String name, DimensionSetter<X, D> setter, D... dims) {
+ dimensionInfos.add(new DimensionInfo<>(name, dims, setter));
+ return this;
+ }
+
+ /**
+ * Adds a new array dimension to this combo test, with a given base name. This allows to specify
+ * multiple dimensions at once; the names of the underlying dimensions will be generated from the
+ * base name, using standard array bracket notation - i.e. "DIM[0]", "DIM[1]", etc.
+ */
+ @SafeVarargs
+ public final <D> ComboTestHelper<X> withArrayDimension(String name, int size, D... dims) {
+ return withArrayDimension(name, null, size, dims);
+ }
+
+ /**
+ * Adds a new array dimension to this combo test, with a given base name, an array of values and a
+ * coresponding array setter to be called in order to set the dimension value on the combo test
+ * instance (before test execution). This allows to specify multiple dimensions at once; the names
+ * of the underlying dimensions will be generated from the base name, using standard array bracket
+ * notation - i.e. "DIM[0]", "DIM[1]", etc.
+ */
+ @SafeVarargs
+ public final <D> ComboTestHelper<X> withArrayDimension(String name, ArrayDimensionSetter<X, D> setter, int size, D... dims) {
+ for (int i = 0 ; i < size ; i++) {
+ dimensionInfos.add(new ArrayDimensionInfo<>(name, dims, i, setter));
+ }
+ return this;
+ }
+
+ /**
+ * Returns the stat object associated with this combo test.
+ */
+ public Info info() {
+ return info;
+ }
+
+ /**
+ * Runs this combo test. This will generate the combinatorial explosion of all dimensions, and
+ * execute a new test instance (built using given supplier) for each such combination.
+ */
+ public void run(Supplier<X> instanceBuilder) {
+ run(instanceBuilder, null);
+ }
+
+ /**
+ * Runs this combo test. This will generate the combinatorial explosion of all dimensions, and
+ * execute a new test instance (built using given supplier) for each such combination. Before
+ * executing the test instance entry point, the supplied initialization method is called on
+ * the test instance; this is useful for ad-hoc test instance initialization once all the dimension
+ * values have been set.
+ */
+ public void run(Supplier<X> instanceBuilder, Consumer<X> initAction) {
+ runInternal(0, new Stack<>(), instanceBuilder, Optional.ofNullable(initAction));
+ end();
+ }
+
+ /**
+ * Generate combinatorial explosion of all dimension values and create a new test instance
+ * for each combination.
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ private void runInternal(int index, Stack<DimensionBinding<?>> bindings, Supplier<X> instanceBuilder, Optional<Consumer<X>> initAction) {
+ if (index == dimensionInfos.size()) {
+ runCombo(instanceBuilder, initAction, bindings);
+ } else {
+ DimensionInfo<?> dinfo = dimensionInfos.get(index);
+ for (Object d : dinfo.dims) {
+ bindings.push(new DimensionBinding(d, dinfo));
+ runInternal(index + 1, bindings, instanceBuilder, initAction);
+ bindings.pop();
+ }
+ }
+ }
+
+ /**
+ * Run a new test instance using supplied dimension bindings. All required setters and initialization
+ * method are executed before calling the instance main entry point. Also checks if the instance
+ * is compatible with the specified test filters; if not, the test is simply skipped.
+ */
+ @SuppressWarnings("unchecked")
+ private void runCombo(Supplier<X> instanceBuilder, Optional<Consumer<X>> initAction, List<DimensionBinding<?>> bindings) {
+ X x = instanceBuilder.get();
+ for (DimensionBinding<?> binding : bindings) {
+ binding.init(x);
+ }
+ initAction.ifPresent(action -> action.accept(x));
+ info.comboCount++;
+ if (!optFilter.isPresent() || optFilter.get().test(x)) {
+ x.run(new Env(bindings));
+ if (failMode.shouldStop(ignoreMode, info)) {
+ end();
+ }
+ } else {
+ info.skippedCount++;
+ }
+ }
+
+ /**
+ * This method is executed upon combo test completion (either normal or erroneous). Closes down
+ * all pending resources and dumps useful stats info.
+ */
+ private void end() {
+ try {
+ fm.close();
+ if (info.hasFailures()) {
+ throw new AssertionError("Failure when executing combo:" + info.lastFailure.orElse(""));
+ } else if (info.hasErrors()) {
+ throw new AssertionError("Unexpected exception while executing combo", info.lastError.get());
+ }
+ } catch (IOException ex) {
+ throw new AssertionError("Failure when closing down shared file manager; ", ex);
+ } finally {
+ info.dump();
+ }
+ }
+
+ /**
+ * Functional interface for specifying combo test instance setters.
+ */
+ public interface DimensionSetter<X extends ComboInstance<X>, D> {
+ void set(X x, D d);
+ }
+
+ /**
+ * Functional interface for specifying combo test instance array setters. The setter method
+ * receives an extra argument for the index of the array element to be set.
+ */
+ public interface ArrayDimensionSetter<X extends ComboInstance<X>, D> {
+ void set(X x, D d, int index);
+ }
+
+ /**
+ * Dimension descriptor; each dimension has a name, an array of value and an optional setter
+ * to be called on the associated combo test instance.
+ */
+ class DimensionInfo<D> {
+ String name;
+ D[] dims;
+ boolean isParameter;
+ Optional<DimensionSetter<X, D>> optSetter;
+
+ DimensionInfo(String name, D[] dims, DimensionSetter<X, D> setter) {
+ this.name = name;
+ this.dims = dims;
+ this.optSetter = Optional.ofNullable(setter);
+ this.isParameter = dims[0] instanceof ComboParameter;
+ }
+ }
+
+ /**
+ * Array dimension descriptor. The dimension name is derived from a base name and an index using
+ * standard bracket notation; ; the setter accepts an additional 'index' argument to point
+ * to the array element to be initialized.
+ */
+ class ArrayDimensionInfo<D> extends DimensionInfo<D> {
+ public ArrayDimensionInfo(String name, D[] dims, int index, ArrayDimensionSetter<X, D> setter) {
+ super(String.format("%s[%d]", name, index), dims,
+ setter != null ? (x, d) -> setter.set(x, d, index) : null);
+ }
+ }
+
+ /**
+ * Failure policies for a combo test run.
+ */
+ public enum FailMode {
+ /** Combo test fails when first failure is detected. */
+ FAIL_FAST,
+ /** Combo test fails after all instances have been executed. */
+ FAIL_AFTER;
+
+ boolean shouldStop(IgnoreMode ignoreMode, Info info) {
+ switch (this) {
+ case FAIL_FAST:
+ return !ignoreMode.canIgnore(info);
+ default:
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Ignore policies for a combo test run.
+ */
+ public enum IgnoreMode {
+ /** No error or failure is ignored. */
+ IGNORE_NONE,
+ /** Only errors are ignored. */
+ IGNORE_ERRORS,
+ /** Only failures are ignored. */
+ IGNORE_FAILURES,
+ /** Both errors and failures are ignored. */
+ IGNORE_ALL;
+
+ boolean canIgnore(Info info) {
+ switch (this) {
+ case IGNORE_ERRORS:
+ return info.failCount == 0;
+ case IGNORE_FAILURES:
+ return info.errCount == 0;
+ case IGNORE_ALL:
+ return true;
+ default:
+ return info.failCount == 0 && info.errCount == 0;
+ }
+ }
+ }
+
+ /**
+ * A dimension binding. This is essentially a pair of a dimension value and its corresponding
+ * dimension info.
+ */
+ class DimensionBinding<D> {
+ D d;
+ DimensionInfo<D> info;
+
+ DimensionBinding(D d, DimensionInfo<D> info) {
+ this.d = d;
+ this.info = info;
+ }
+
+ void init(X x) {
+ info.optSetter.ifPresent(setter -> setter.set(x, d));
+ }
+
+ public String toString() {
+ return String.format("(%s -> %s)", info.name, d);
+ }
+ }
+
+ /**
+ * This class is used to keep track of combo tests stats; info such as numbero of failures/errors,
+ * number of times a context has been shared/dropped are all recorder here.
+ */
+ public static class Info {
+ int failCount;
+ int errCount;
+ int passCount;
+ int comboCount;
+ int skippedCount;
+ int ctxReusedCount;
+ int ctxDroppedCount;
+ Optional<String> lastFailure = Optional.empty();
+ Optional<Throwable> lastError = Optional.empty();
+
+ void dump() {
+ System.err.println(String.format("%d total checks executed", comboCount));
+ System.err.println(String.format("%d successes found", passCount));
+ System.err.println(String.format("%d failures found", failCount));
+ System.err.println(String.format("%d errors found", errCount));
+ System.err.println(String.format("%d skips found", skippedCount));
+ System.err.println(String.format("%d contexts shared", ctxReusedCount));
+ System.err.println(String.format("%d contexts dropped", ctxDroppedCount));
+ }
+
+ public boolean hasFailures() {
+ return failCount != 0;
+ }
+
+ public boolean hasErrors() {
+ return errCount != 0;
+ }
+ }
+
+ /**
+ * THe execution environment for a given combo test instance. An environment contains the
+ * bindings for all the dimensions, along with the combo parameter cache (this is non-empty
+ * only if one or more dimensions are subclasses of the {@code ComboParameter} interface).
+ */
+ class Env {
+ List<DimensionBinding<?>> bindings;
+ Map<String, ComboParameter> parametersCache = new HashMap<>();
+
+ @SuppressWarnings({"Unchecked", "rawtypes"})
+ Env(List<DimensionBinding<?>> bindings) {
+ this.bindings = bindings;
+ for (DimensionBinding<?> binding : bindings) {
+ if (binding.info.isParameter) {
+ parametersCache.put(binding.info.name, (ComboParameter)binding.d);
+ };
+ }
+ }
+
+ Info info() {
+ return ComboTestHelper.this.info();
+ }
+
+ StandardJavaFileManager fileManager() {
+ return fm;
+ }
+
+ JavaCompiler javaCompiler() {
+ return comp;
+ }
+
+ ReusableContext context() {
+ return context;
+ }
+
+ ReusableContext setContext(ReusableContext context) {
+ return ComboTestHelper.this.context = context;
+ }
+ }
+}
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lib/combo/ReusableContext.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+
+package combo;
+
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TaskEvent;
+import com.sun.source.util.TaskEvent.Kind;
+import com.sun.source.util.TaskListener;
+import com.sun.source.util.TreeScanner;
+import com.sun.tools.javac.api.MultiTaskListener;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.comp.Check;
+import com.sun.tools.javac.comp.CompileStates;
+import com.sun.tools.javac.comp.Enter;
+import com.sun.tools.javac.main.Arguments;
+import com.sun.tools.javac.main.JavaCompiler;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Log;
+
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A reusable context is a context that can be used safely across multiple compilation rounds
+ * arising from execution of a combo test. It achieves reuse by replacing some components
+ * (most notably JavaCompiler and Log) with reusable counterparts, and by exposing a method
+ * to cleanup leftovers from previous compilation.
+ * <p>
+ * There are, however, situations in which reusing the context is not safe: (i) when different
+ * compilations are using different sets of compiler options (as most option values are cached
+ * inside components themselves) and (ii) when the compilation unit happens to redefine classes
+ * in the java.* packages.
+ */
+class ReusableContext extends Context implements TaskListener {
+
+ Set<CompilationUnitTree> roots = new HashSet<>();
+
+ String opts;
+ boolean polluted = false;
+
+ ReusableContext() {
+ super();
+ put(Log.logKey, ReusableLog.factory);
+ put(JavaCompiler.compilerKey, ReusableJavaCompiler.factory);
+ }
+
+ void clear() {
+ drop(Arguments.argsKey);
+ drop(DiagnosticListener.class);
+ drop(Log.outKey);
+ drop(JavaFileManager.class);
+ drop(JavacTask.class);
+
+ if (ht.get(Log.logKey) instanceof ReusableLog) {
+ //log already inited - not first round
+ ((ReusableLog)Log.instance(this)).clear();
+ Enter.instance(this).newRound();
+ ((ReusableJavaCompiler)ReusableJavaCompiler.instance(this)).clear();
+ Types.instance(this).newRound();
+ Check.instance(this).newRound();
+ CompileStates.instance(this).clear();
+ MultiTaskListener.instance(this).clear();
+
+ //find if any of the roots have redefined java.* classes
+ Symtab syms = Symtab.instance(this);
+ new TreeScanner<Void, Void>() {
+ @Override
+ public Void visitClass(ClassTree node, Void aVoid) {
+ Symbol sym = ((JCClassDecl)node).sym;
+ if (sym != null) {
+ syms.classes.remove(sym.flatName());
+ if (sym.flatName().toString().startsWith("java.")) {
+ polluted = true;
+ }
+ }
+ return super.visitClass(node, aVoid);
+ }
+ }.scan(roots, null);
+ roots.clear();
+ }
+ }
+
+ @Override
+ public void finished(TaskEvent e) {
+ if (e.getKind() == Kind.PARSE) {
+ roots.add(e.getCompilationUnit());
+ }
+ }
+
+ @Override
+ public void started(TaskEvent e) {
+ //do nothing
+ }
+
+ <T> void drop(Key<T> k) {
+ ht.remove(k);
+ }
+
+ <T> void drop(Class<T> c) {
+ ht.remove(key(c));
+ }
+
+ /**
+ * Reusable JavaCompiler; exposes a method to clean up the component from leftovers associated with
+ * previous compilations.
+ */
+ static class ReusableJavaCompiler extends JavaCompiler {
+
+ static Factory<JavaCompiler> factory = ReusableJavaCompiler::new;
+
+ ReusableJavaCompiler(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void close() {
+ //do nothing
+ }
+
+ void clear() {
+ newRound();
+ }
+
+ @Override
+ protected void checkReusable() {
+ //do nothing - it's ok to reuse the compiler
+ }
+ }
+
+ /**
+ * Reusable Log; exposes a method to clean up the component from leftovers associated with
+ * previous compilations.
+ */
+ static class ReusableLog extends Log {
+
+ static Factory<Log> factory = ReusableLog::new;
+
+ Context context;
+
+ ReusableLog(Context context) {
+ super(context);
+ this.context = context;
+ }
+
+ void clear() {
+ recorded.clear();
+ sourceMap.clear();
+ nerrors = 0;
+ nwarnings = 0;
+ //Set a fake listener that will lazily lookup the context for the 'real' listener. Since
+ //this field is never updated when a new task is created, we cannot simply reset the field
+ //or keep old value. This is a hack to workaround the limitations in the current infrastructure.
+ diagListener = new DiagnosticListener<JavaFileObject>() {
+ DiagnosticListener<JavaFileObject> cachedListener;
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ if (cachedListener == null) {
+ cachedListener = context.get(DiagnosticListener.class);
+ }
+ cachedListener.report(diagnostic);
+ }
+ };
+ }
+ }
+}
--- a/langtools/test/tools/javac/multicatch/7030606/DisjunctiveTypeWellFormednessTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/multicatch/7030606/DisjunctiveTypeWellFormednessTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,30 +23,31 @@
/*
* @test
- * @bug 7030606 8006694
+ * @bug 7030606 8006694 8129962
* @summary Project-coin: multi-catch types should be pairwise disjoint
* temporarily workaround combo tests are causing time out in several platforms
- * @library ../../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm DisjunctiveTypeWellFormednessTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main DisjunctiveTypeWellFormednessTest
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import com.sun.source.util.JavacTask;
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
-public class DisjunctiveTypeWellFormednessTest
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
- enum Alternative {
+public class DisjunctiveTypeWellFormednessTest extends ComboInstance<DisjunctiveTypeWellFormednessTest> {
+
+ enum Alternative implements ComboParameter {
EXCEPTION("Exception"),
RUNTIME_EXCEPTION("RuntimeException"),
IO_EXCEPTION("java.io.IOException"),
@@ -55,21 +56,10 @@
String exceptionStr;
- private Alternative(String exceptionStr) {
+ Alternative(String exceptionStr) {
this.exceptionStr = exceptionStr;
}
- static String makeDisjunctiveType(Alternative... alternatives) {
- StringBuilder buf = new StringBuilder();
- String sep = "";
- for (Alternative alternative : alternatives) {
- buf.append(sep);
- buf.append(alternative.exceptionStr);
- sep = "|";
- }
- return buf.toString();
- }
-
boolean disjoint(Alternative that) {
return disjoint[this.ordinal()][that.ordinal()];
}
@@ -82,135 +72,85 @@
/*FileNotFoundException*/ { false, true, false, false, true },
/*IllegalArgumentException*/ { false, false, true, true, false }
};
+
+ @Override
+ public String expand(String optParameter) {
+ return exceptionStr;
+ }
}
- enum Arity {
- ONE(1),
- TWO(2),
- THREE(3),
- FOUR(4),
- FIVE(5);
+ enum Arity implements ComboParameter {
+ ONE(1, "#{TYPE[0]}"),
+ TWO(2, "#{TYPE[0]} | #{TYPE[1]}"),
+ THREE(3, "#{TYPE[0]} | #{TYPE[1]} | #{TYPE[2]}"),
+ FOUR(4, "#{TYPE[0]} | #{TYPE[1]} | #{TYPE[2]} | #{TYPE[3]}"),
+ FIVE(5, "#{TYPE[0]} | #{TYPE[1]} | #{TYPE[2]} | #{TYPE[3]} | #{TYPE[4]}");
int n;
+ String arityTemplate;
- private Arity(int n) {
+ Arity(int n, String arityTemplate) {
this.n = n;
+ this.arityTemplate = arityTemplate;
+ }
+
+ @Override
+ public String expand(String optParameter) {
+ return arityTemplate;
}
}
public static void main(String... args) throws Exception {
- for (Arity arity : Arity.values()) {
- for (Alternative a1 : Alternative.values()) {
- if (arity == Arity.ONE) {
- pool.execute(new DisjunctiveTypeWellFormednessTest(a1));
- continue;
- }
- for (Alternative a2 : Alternative.values()) {
- if (arity == Arity.TWO) {
- pool.execute(new DisjunctiveTypeWellFormednessTest(a1, a2));
- continue;
- }
- for (Alternative a3 : Alternative.values()) {
- if (arity == Arity.THREE) {
- pool.execute(new DisjunctiveTypeWellFormednessTest(a1, a2, a3));
- continue;
- }
- for (Alternative a4 : Alternative.values()) {
- if (arity == Arity.FOUR) {
- pool.execute(new DisjunctiveTypeWellFormednessTest(a1, a2, a3, a4));
- continue;
- }
- for (Alternative a5 : Alternative.values()) {
- pool.execute(new DisjunctiveTypeWellFormednessTest(a1, a2, a3, a4, a5));
- }
- }
- }
+ new ComboTestHelper<DisjunctiveTypeWellFormednessTest>()
+ .withFilter(DisjunctiveTypeWellFormednessTest::arityFilter)
+ .withDimension("CTYPE", (x, arity) -> x.arity = arity, Arity.values())
+ .withArrayDimension("TYPE", (x, type, idx) -> x.alternatives[idx] = type, 5, Alternative.values())
+ .run(DisjunctiveTypeWellFormednessTest::new);
+ }
+
+ Arity arity;
+ Alternative[] alternatives = new Alternative[5];
+
+ boolean arityFilter() {
+ for (int i = arity.n; i < alternatives.length ; i++) {
+ if (alternatives[i].ordinal() != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ String template = "class Test {\n" +
+ "void test() {\n" +
+ "try {} catch (#{CTYPE} e) {}\n" +
+ "}\n" +
+ "}\n";
+
+ @Override
+ public void doWork() throws IOException {
+ check(newCompilationTask()
+ .withSourceFromTemplate(template)
+ .analyze());
+ }
+
+ void check(Result<?> res) {
+
+ int non_disjoint = 0;
+ for (int i = 0 ; i < arity.n ; i++) {
+ for (int j = 0 ; j < i ; j++) {
+ if (!alternatives[i].disjoint(alternatives[j])) {
+ non_disjoint++;
+ break;
}
}
}
- checkAfterExec(false);
- }
-
- Alternative[] alternatives;
- JavaSource source;
- DiagnosticChecker diagChecker;
-
- DisjunctiveTypeWellFormednessTest(Alternative... alternatives) {
- this.alternatives = alternatives;
- this.source = new JavaSource();
- this.diagChecker = new DiagnosticChecker();
- }
-
- class JavaSource extends SimpleJavaFileObject {
-
- String template = "class Test {\n" +
- "void test() {\n" +
- "try {} catch (#T e) {}\n" +
- "}\n" +
- "}\n";
-
- String source;
-
- public JavaSource() {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
- source = template.replace("#T", Alternative.makeDisjunctiveType(alternatives));
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
+ int foundErrs = res.diagnosticsForKey("compiler.err.multicatch.types.must.be.disjoint").size();
+ if (non_disjoint != foundErrs) {
+ fail("invalid diagnostics for source:\n" +
+ res.compilationInfo() +
+ "\nFound errors: " + foundErrs +
+ "\nExpected errors: " + non_disjoint);
}
}
-
- @Override
- public void run() {
- JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
- null, null, Arrays.asList(source));
- try {
- ct.analyze();
- } catch (Throwable t) {
- processException(t);
- return;
- }
- check();
- }
-
- void check() {
-
- int non_disjoint = 0;
- int i = 0;
- for (Alternative a1 : alternatives) {
- int j = 0;
- for (Alternative a2 : alternatives) {
- if (i == j) continue;
- if (!a1.disjoint(a2)) {
- non_disjoint++;
- break;
- }
- j++;
- }
- i++;
- }
-
- if (non_disjoint != diagChecker.errorsFound) {
- throw new Error("invalid diagnostics for source:\n" +
- source.getCharContent(true) +
- "\nFound errors: " + diagChecker.errorsFound +
- "\nExpected errors: " + non_disjoint);
- }
- }
-
- static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- int errorsFound;
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
- diagnostic.getCode().startsWith("compiler.err.multicatch.types.must.be.disjoint")) {
- errorsFound++;
- }
- }
- }
-
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/parser/8134007/T8134007.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,488 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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 8134007
+ * @summary Improve string folding
+ * @compile T8134007.java
+ */
+class T8134007 {
+ String v = "";
+
+ //interleaved non-literals
+ String s1 = "Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v;
+
+ //heading non-literal
+ String s2 = v + "Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9";
+
+ //trailing non-literal
+ String s3 = "Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9"
+ +"Str0" + "Str1" + "Str2" + "Str3" + "Str4" + "Str5" + "Str6" + "Str7" + "Str8" + "Str9" + v;
+}
--- a/langtools/test/tools/javac/resolve/BitWiseOperators.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/resolve/BitWiseOperators.java Tue Sep 08 14:40:44 2015 -0700
@@ -21,47 +21,30 @@
* questions.
*/
-/**@test
- * @bug 8082311
+/*
+ * @test
+ * @bug 8082311 8129962
* @summary Verify that bitwise operators don't allow to mix numeric and boolean operands.
* @library ../lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main BitWiseOperators
*/
import com.sun.tools.javac.util.StringUtils;
-import java.net.URI;
-import java.util.Arrays;
-import java.util.List;
-import javax.tools.DiagnosticCollector;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-public class BitWiseOperators extends JavacTestingAbstractThreadedTest {
- public static void main(String... args) {
- new BitWiseOperators().run();
- }
+import java.io.IOException;
- void run() {
- for (TYPE type1 : TYPE.values()) {
- for (OPERATION op : OPERATION.values()) {
- for (TYPE type2 : TYPE.values()) {
- runTest(type1, op, type2);
- }
- }
- }
- }
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
- void runTest(TYPE type1, OPERATION op, TYPE type2) {
- DiagnosticCollector<JavaFileObject> dc = new DiagnosticCollector<>();
- List<JavaSource> files = Arrays.asList(new JavaSource(type1, op, type2));
- comp.getTask(null, null, dc, null, null, files).call();
- if (dc.getDiagnostics().isEmpty() ^ TYPE.compatible(type1, type2)) {
- throw new AssertionError("Unexpected behavior. Type1: " + type1 +
- "; type2: " + type2 +
- "; diagnostics: " + dc.getDiagnostics());
- }
- }
- enum TYPE {
+public class BitWiseOperators extends ComboInstance<BitWiseOperators> {
+
+ enum OperandType implements ComboParameter {
BYTE,
CHAR,
SHORT,
@@ -69,45 +52,57 @@
LONG,
BOOLEAN;
- public static boolean compatible(TYPE op1, TYPE op2) {
+ public static boolean compatible(OperandType op1, OperandType op2) {
return !(op1 == BOOLEAN ^ op2 == BOOLEAN);
}
+
+ @Override
+ public String expand(String optParameter) {
+ return StringUtils.toLowerCase(name());
+ }
}
- enum OPERATION {
+ enum OperatorKind implements ComboParameter {
BITAND("&"),
BITOR("|"),
BITXOR("^");
String op;
- private OPERATION(String op) {
+ OperatorKind(String op) {
this.op = op;
}
- }
-
- class JavaSource extends SimpleJavaFileObject {
-
- String template = "class Test {\n" +
- " public Object test(#TYPE1 var1, #TYPE2 var2) {\n" +
- " return var1 #OP var2;\n" +
- " }\n" +
- "}";
-
- String source;
-
- public JavaSource(TYPE type1, OPERATION op, TYPE type2) {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
- source = template.replaceAll("#TYPE1", StringUtils.toLowerCase(type1.name()))
- .replaceAll("#OP", StringUtils.toLowerCase(op.op))
- .replaceAll("#TYPE2", StringUtils.toLowerCase(type2.name()));
- }
-
@Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
+ public String expand(String optParameter) {
+ return op;
}
}
+ public static void main(String... args) {
+ new ComboTestHelper<BitWiseOperators>()
+ .withArrayDimension("TYPE", (x, type, idx) -> x.opTypes[idx] = type, 2, OperandType.values())
+ .withDimension("OP", OperatorKind.values())
+ .run(BitWiseOperators::new);
+ }
+
+ OperandType[] opTypes = new OperandType[2];
+
+ String template = "class Test {\n" +
+ " public Object test(#{TYPE[0]} var1, #{TYPE[1]} var2) {\n" +
+ " return var1 #{OP} var2;\n" +
+ " }\n" +
+ "}";
+
+ @Override
+ public void doWork() throws IOException {
+ Result<?> res = newCompilationTask()
+ .withSourceFromTemplate(template)
+ .analyze();
+ if (res.hasErrors() == OperandType.compatible(opTypes[0], opTypes[1])) {
+ fail("Unexpected behavior. Type1: " + opTypes[0] +
+ "; type2: " + opTypes[1] +
+ "; " + res.compilationInfo());
+ }
+ }
}
--- a/langtools/test/tools/javac/types/ScopeListenerTest.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/types/ScopeListenerTest.java Tue Sep 08 14:40:44 2015 -0700
@@ -29,6 +29,7 @@
*/
import com.sun.tools.javac.code.Scope;
+import com.sun.tools.javac.code.Scope.ScopeListenerList;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Types;
@@ -53,20 +54,14 @@
types.membersClosure(syms.stringType, true);
types.membersClosure(syms.stringType, false);
- Field listenersField = Scope.class.getDeclaredField("listeners");
-
- listenersField.setAccessible(true);
-
- int listenerCount =
- ((Collection) listenersField.get(syms.stringType.tsym.members())).size();
+ int listenerCount = listenerCount(syms.stringType.tsym.members());
for (int i = 0; i < 100; i++) {
types.membersClosure(syms.stringType, true);
types.membersClosure(syms.stringType, false);
}
- int newListenerCount
- = ((Collection) listenersField.get(syms.stringType.tsym.members())).size();
+ int newListenerCount = listenerCount(syms.stringType.tsym.members());
if (listenerCount != newListenerCount) {
throw new AssertionError("Orig listener count: " + listenerCount +
@@ -79,4 +74,12 @@
;
}
+ int listenerCount(Scope s) throws ReflectiveOperationException {
+ Field listenersListField = Scope.class.getDeclaredField("listeners");
+ listenersListField.setAccessible(true);
+ Field listenersField = ScopeListenerList.class.getDeclaredField("listeners");
+ listenersField.setAccessible(true);
+ return ((Collection<?>)listenersField.get(listenersListField.get(s))).size();
+ }
+
}
--- a/langtools/test/tools/javac/varargs/7042566/T7042566.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/varargs/7042566/T7042566.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,31 +23,25 @@
/*
* @test
- * @bug 7042566 8006694
+ * @bug 7042566 8006694 8129962
* @summary Unambiguous varargs method calls flagged as ambiguous
* temporarily workaround combo tests are causing time out in several platforms
- * @library ../../lib
+ * @library /tools/javac/lib
* @modules jdk.jdeps/com.sun.tools.classfile
+ * jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
* jdk.compiler/com.sun.tools.javac.util
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm T7042566
+ * @build combo.ComboTestHelper
+ * @run main T7042566
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
+import java.io.IOException;
+import java.io.InputStream;
+import javax.tools.JavaFileObject;
-import java.io.File;
-import java.net.URI;
-import java.util.Arrays;
-import java.util.Locale;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.tools.Diagnostic;
-import javax.tools.JavaCompiler;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.ToolProvider;
-
-import com.sun.source.util.JavacTask;
import com.sun.tools.classfile.Instruction;
import com.sun.tools.classfile.Attribute;
import com.sun.tools.classfile.ClassFile;
@@ -56,145 +50,12 @@
import com.sun.tools.classfile.Method;
import com.sun.tools.javac.util.List;
-public class T7042566
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
-
- VarargsMethod m1;
- VarargsMethod m2;
- TypeConfiguration actuals;
-
- T7042566(TypeConfiguration m1_conf, TypeConfiguration m2_conf,
- TypeConfiguration actuals) {
- this.m1 = new VarargsMethod(m1_conf);
- this.m2 = new VarargsMethod(m2_conf);
- this.actuals = actuals;
- }
-
- @Override
- public void run() {
- int id = checkCount.incrementAndGet();
- final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
- JavaSource source = new JavaSource(id);
- ErrorChecker ec = new ErrorChecker();
- JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), ec,
- null, null, Arrays.asList(source));
- ct.call();
- check(source, ec, id);
- }
-
- void check(JavaSource source, ErrorChecker ec, int id) {
- boolean resolutionError = false;
- VarargsMethod selectedMethod = null;
-
- boolean m1_applicable = m1.isApplicable(actuals);
- boolean m2_applicable = m2.isApplicable(actuals);
-
- if (!m1_applicable && !m2_applicable) {
- resolutionError = true;
- } else if (m1_applicable && m2_applicable) {
- //most specific
- boolean m1_moreSpecific = m1.isMoreSpecificThan(m2);
- boolean m2_moreSpecific = m2.isMoreSpecificThan(m1);
-
- resolutionError = m1_moreSpecific == m2_moreSpecific;
- selectedMethod = m1_moreSpecific ? m1 : m2;
- } else {
- selectedMethod = m1_applicable ?
- m1 : m2;
- }
-
- if (ec.errorFound != resolutionError) {
- throw new Error("invalid diagnostics for source:\n" +
- source.getCharContent(true) +
- "\nExpected resolution error: " + resolutionError +
- "\nFound error: " + ec.errorFound +
- "\nCompiler diagnostics:\n" + ec.printDiags());
- } else if (!resolutionError) {
- verifyBytecode(selectedMethod, source, id);
- }
- }
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
- void verifyBytecode(VarargsMethod selected, JavaSource source, int id) {
- bytecodeCheckCount.incrementAndGet();
- File compiledTest = new File(String.format("Test%d.class", id));
- try {
- ClassFile cf = ClassFile.read(compiledTest);
- Method testMethod = null;
- for (Method m : cf.methods) {
- if (m.getName(cf.constant_pool).equals("test")) {
- testMethod = m;
- break;
- }
- }
- if (testMethod == null) {
- throw new Error("Test method not found");
- }
- Code_attribute ea =
- (Code_attribute)testMethod.attributes.get(Attribute.Code);
- if (testMethod == null) {
- throw new Error("Code attribute for test() method not found");
- }
-
- for (Instruction i : ea.getInstructions()) {
- if (i.getMnemonic().equals("invokevirtual")) {
- int cp_entry = i.getUnsignedShort(1);
- CONSTANT_Methodref_info methRef =
- (CONSTANT_Methodref_info)cf.constant_pool.get(cp_entry);
- String type = methRef.getNameAndTypeInfo().getType();
- String sig = selected.parameterTypes.bytecodeSigStr;
- if (!type.contains(sig)) {
- throw new Error("Unexpected type method call: " +
- type + "" +
- "\nfound: " + sig +
- "\n" + source.getCharContent(true));
- }
- break;
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- throw new Error("error reading " + compiledTest +": " + e);
- }
- }
-
- class JavaSource extends SimpleJavaFileObject {
-
- static final String source_template = "class Test#ID {\n" +
- " #V1\n" +
- " #V2\n" +
- " void test() { m(#E); }\n" +
- "}";
-
- String source;
-
- public JavaSource(int id) {
- super(URI.create(String.format("myfo:/Test%d.java", id)),
- JavaFileObject.Kind.SOURCE);
- source = source_template.replaceAll("#V1", m1.toString())
- .replaceAll("#V2", m2.toString())
- .replaceAll("#E", actuals.expressionListStr)
- .replaceAll("#ID", String.valueOf(id));
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
- }
- }
-
- public static void main(String... args) throws Exception {
- for (TypeConfiguration tconf1 : TypeConfiguration.values()) {
- for (TypeConfiguration tconf2 : TypeConfiguration.values()) {
- for (TypeConfiguration tconf3 : TypeConfiguration.values()) {
- pool.execute(new T7042566(tconf1, tconf2, tconf3));
- }
- }
- }
-
- outWriter.println("Bytecode checks made: " + bytecodeCheckCount.get());
- checkAfterExec();
- }
+public class T7042566 extends ComboInstance<T7042566> {
enum TypeKind {
OBJECT("Object", "(Object)null", "Ljava/lang/Object;"),
@@ -216,7 +77,7 @@
}
}
- enum TypeConfiguration {
+ enum TypeConfiguration implements ComboParameter {
A(TypeKind.OBJECT),
B(TypeKind.STRING),
AA(TypeKind.OBJECT, TypeKind.OBJECT),
@@ -237,7 +98,7 @@
String parameterListStr;
String bytecodeSigStr;
- private TypeConfiguration(TypeKind... typeKindList) {
+ TypeConfiguration(TypeKind... typeKindList) {
this.typeKindList = List.from(typeKindList);
expressionListStr = asExpressionList();
parameterListStr = asParameterList();
@@ -284,6 +145,11 @@
}
return buf.toString();
}
+
+ @Override
+ public String expand(String optParameter) {
+ return expressionListStr;
+ }
}
static class VarargsMethod {
@@ -333,31 +199,119 @@
}
}
- static class ErrorChecker
- implements javax.tools.DiagnosticListener<JavaFileObject> {
+ public static void main(String[] args) {
+ new ComboTestHelper<T7042566>()
+ .withArrayDimension("SIG", (x, sig, idx) -> x.methodSignatures[idx] = sig, 2, TypeConfiguration.values())
+ .withDimension("ACTUALS", (x, actuals) -> x.actuals = actuals, TypeConfiguration.values())
+ .run(T7042566::new, T7042566::setup);
+ }
- boolean errorFound;
- List<String> errDiags = List.nil();
+ VarargsMethod m1;
+ VarargsMethod m2;
+ TypeConfiguration[] methodSignatures = new TypeConfiguration[2];
+ TypeConfiguration actuals;
+
+ void setup() {
+ this.m1 = new VarargsMethod(methodSignatures[0]);
+ this.m2 = new VarargsMethod(methodSignatures[1]);
+ }
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
- errDiags = errDiags
- .append(diagnostic.getMessage(Locale.getDefault()));
- errorFound = true;
- }
- }
+ final String source_template = "class Test {\n" +
+ " #{METH.1}\n" +
+ " #{METH.2}\n" +
+ " void test() { m(#{ACTUALS}); }\n" +
+ "}";
- String printDiags() {
- StringBuilder buf = new StringBuilder();
- for (String s : errDiags) {
- buf.append(s);
- buf.append("\n");
- }
- return buf.toString();
+ @Override
+ public void doWork() throws IOException {
+ check(newCompilationTask()
+ .withSourceFromTemplate(source_template, this::getMethodDecl)
+ .generate());
+ }
+
+ ComboParameter getMethodDecl(String parameterName) {
+ switch (parameterName) {
+ case "METH": return optParameter -> {
+ return optParameter.equals("1") ?
+ m1.toString() : m2.toString();
+ };
+ default:
+ return null;
}
}
- //number of bytecode checks made while running combo tests
- static AtomicInteger bytecodeCheckCount = new AtomicInteger();
+ void check(Result<Iterable<? extends JavaFileObject>> res) {
+ boolean resolutionError = false;
+ VarargsMethod selectedMethod = null;
+
+ boolean m1_applicable = m1.isApplicable(actuals);
+ boolean m2_applicable = m2.isApplicable(actuals);
+
+ if (!m1_applicable && !m2_applicable) {
+ resolutionError = true;
+ } else if (m1_applicable && m2_applicable) {
+ //most specific
+ boolean m1_moreSpecific = m1.isMoreSpecificThan(m2);
+ boolean m2_moreSpecific = m2.isMoreSpecificThan(m1);
+
+ resolutionError = m1_moreSpecific == m2_moreSpecific;
+ selectedMethod = m1_moreSpecific ? m1 : m2;
+ } else {
+ selectedMethod = m1_applicable ?
+ m1 : m2;
+ }
+
+ if (res.hasErrors() != resolutionError) {
+ fail("invalid diagnostics for source:\n" +
+ res.compilationInfo() +
+ "\nExpected resolution error: " + resolutionError +
+ "\nFound error: " + res.hasErrors());
+ } else if (!resolutionError) {
+ verifyBytecode(res, selectedMethod);
+ }
+ }
+ void verifyBytecode(Result<Iterable<? extends JavaFileObject>> res, VarargsMethod selected) {
+ try (InputStream is = res.get().iterator().next().openInputStream()) {
+ ClassFile cf = ClassFile.read(is);
+ Method testMethod = null;
+ for (Method m : cf.methods) {
+ if (m.getName(cf.constant_pool).equals("test")) {
+ testMethod = m;
+ break;
+ }
+ }
+ if (testMethod == null) {
+ fail("Test method not found");
+ return;
+ }
+ Code_attribute ea =
+ (Code_attribute)testMethod.attributes.get(Attribute.Code);
+ if (testMethod == null) {
+ fail("Code attribute for test() method not found");
+ return;
+ }
+
+ for (Instruction i : ea.getInstructions()) {
+ if (i.getMnemonic().equals("invokevirtual")) {
+ int cp_entry = i.getUnsignedShort(1);
+ CONSTANT_Methodref_info methRef =
+ (CONSTANT_Methodref_info)cf.constant_pool.get(cp_entry);
+ String type = methRef.getNameAndTypeInfo().getType();
+ String sig = selected.parameterTypes.bytecodeSigStr;
+ if (!type.contains(sig)) {
+ fail("Unexpected type method call: " +
+ type + "" +
+ "\nfound: " + sig +
+ "\n" + res.compilationInfo());
+ return;
+ }
+ break;
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("error reading classfile; " + res.compilationInfo() +": " + e);
+ }
+ }
}
--- a/langtools/test/tools/javac/varargs/warning/Warn4.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/varargs/warning/Warn4.java Tue Sep 08 14:40:44 2015 -0700
@@ -23,40 +23,39 @@
/**
* @test
- * @bug 6945418 6993978 8006694 7196160
+ * @bug 6945418 6993978 8006694 7196160 8129962
* @summary Project Coin: Simplified Varargs Method Invocation
* temporarily workaround combo tests are causing time out in several platforms
- * @author mcimadamore
- * @library ../../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
- * @run main/othervm Warn4
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+ * @run main Warn4
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
-import java.net.URI;
-import java.util.Arrays;
+import java.io.IOException;
import java.util.Set;
import java.util.HashSet;
import javax.tools.Diagnostic;
-import javax.tools.JavaCompiler;
+import javax.tools.Diagnostic.Kind;
import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.ToolProvider;
-import com.sun.source.util.JavacTask;
-public class Warn4
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
+
+public class Warn4 extends ComboInstance<Warn4> {
final static Warning[] error = null;
final static Warning[] none = new Warning[] {};
final static Warning[] vararg = new Warning[] { Warning.VARARGS };
final static Warning[] unchecked = new Warning[] { Warning.UNCHECKED };
- final static Warning[] both =
- new Warning[] { Warning.VARARGS, Warning.UNCHECKED };
+ final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED };
enum Warning {
UNCHECKED("generic.array.creation"),
@@ -105,7 +104,7 @@
}
}
- enum TrustMe {
+ enum TrustMe implements ComboParameter {
DONT_TRUST(""),
TRUST("@java.lang.SafeVarargs");
@@ -114,9 +113,14 @@
TrustMe(String anno) {
this.anno = anno;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return anno;
+ }
}
- enum ModifierKind {
+ enum ModifierKind implements ComboParameter {
NONE(" "),
FINAL("final "),
STATIC("static "),
@@ -127,9 +131,14 @@
ModifierKind(String mod) {
this.mod = mod;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return mod;
+ }
}
- enum SuppressLevel {
+ enum SuppressLevel implements ComboParameter {
NONE(""),
UNCHECKED("unchecked");
@@ -139,21 +148,22 @@
this.lint = lint;
}
- String getSuppressAnno() {
+ @Override
+ public String expand(String optParameter) {
return "@SuppressWarnings(\"" + lint + "\")";
}
}
- enum Signature {
- UNBOUND("void #name(List<?>#arity arg) { #body }",
+ enum Signature implements ComboParameter {
+ UNBOUND("void #NAME(List<?>#ARITY arg) { #BODY }",
new Warning[][] {none, none, none, none, error}),
- INVARIANT_TVAR("<Z> void #name(List<Z>#arity arg) { #body }",
+ INVARIANT_TVAR("<Z> void #NAME(List<Z>#ARITY arg) { #BODY }",
new Warning[][] {both, both, error, both, error}),
- TVAR("<Z> void #name(Z#arity arg) { #body }",
+ TVAR("<Z> void #NAME(Z#ARITY arg) { #BODY }",
new Warning[][] {both, both, both, both, vararg}),
- INVARIANT("void #name(List<String>#arity arg) { #body }",
+ INVARIANT("void #NAME(List<String>#ARITY arg) { #BODY }",
new Warning[][] {error, error, error, both, error}),
- UNPARAMETERIZED("void #name(String#arity arg) { #body }",
+ UNPARAMETERIZED("void #NAME(String#ARITY arg) { #BODY }",
new Warning[][] {error, error, error, error, none});
String template;
@@ -177,130 +187,85 @@
return warnings[other.ordinal()] == vararg ||
warnings[other.ordinal()] == both;
}
+
+ @Override
+ public String expand(String optParameter) {
+ if (optParameter.equals("CLIENT")) {
+ return template.replaceAll("#ARITY", "")
+ .replaceAll("#NAME", "test")
+ .replaceAll("#BODY", "m(arg)");
+ } else {
+ return template.replaceAll("#ARITY", "...")
+ .replaceAll("#NAME", "m")
+ .replaceAll("#BODY", "");
+ }
+ }
}
- public static void main(String... args) throws Exception {
- for (SourceLevel sourceLevel : SourceLevel.values()) {
- for (TrustMe trustMe : TrustMe.values()) {
- for (SuppressLevel suppressLevelClient : SuppressLevel.values()) {
- for (SuppressLevel suppressLevelDecl : SuppressLevel.values()) {
- for (ModifierKind modKind : ModifierKind.values()) {
- for (Signature vararg_meth : Signature.values()) {
- for (Signature client_meth : Signature.values()) {
- if (vararg_meth.isApplicableTo(client_meth)) {
- pool.execute(new Warn4(sourceLevel,
- trustMe,
- suppressLevelClient,
- suppressLevelDecl,
- modKind,
- vararg_meth,
- client_meth));
- }
- }
- }
- }
- }
- }
- }
- }
-
- checkAfterExec();
+ public static void main(String... args) {
+ new ComboTestHelper<Warn4>()
+ .withFilter(Warn4::badTestFilter)
+ .withDimension("SOURCE", (x, level) -> x.sourceLevel = level, SourceLevel.values())
+ .withDimension("TRUSTME", (x, trustme) -> x.trustMe = trustme, TrustMe.values())
+ .withArrayDimension("SUPPRESS", (x, suppress, idx) -> x.suppress[idx] = suppress, 2, SuppressLevel.values())
+ .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values())
+ .withArrayDimension("MTH", (x, sig, idx) -> x.sigs[idx] = sig, 2, Signature.values())
+ .run(Warn4::new);
}
SourceLevel sourceLevel;
TrustMe trustMe;
- SuppressLevel suppressLevelClient;
- SuppressLevel suppressLevelDecl;
+ SuppressLevel[] suppress = new SuppressLevel[2];
ModifierKind modKind;
- Signature vararg_meth;
- Signature client_meth;
- DiagnosticChecker diagChecker;
+ Signature[] sigs = new Signature[2];
- public Warn4(SourceLevel sourceLevel, TrustMe trustMe,
- SuppressLevel suppressLevelClient, SuppressLevel suppressLevelDecl,
- ModifierKind modKind, Signature vararg_meth, Signature client_meth) {
- this.sourceLevel = sourceLevel;
- this.trustMe = trustMe;
- this.suppressLevelClient = suppressLevelClient;
- this.suppressLevelDecl = suppressLevelDecl;
- this.modKind = modKind;
- this.vararg_meth = vararg_meth;
- this.client_meth = client_meth;
- this.diagChecker = new DiagnosticChecker();
+ boolean badTestFilter() {
+ return sigs[0].isApplicableTo(sigs[1]);
}
+ final String template = "import java.util.List;\n" +
+ "class Test {\n" +
+ " #{TRUSTME} #{SUPPRESS[0]} #{MOD} #{MTH[0].VARARG}\n" +
+ " #{SUPPRESS[1]} #{MTH[1].CLIENT}\n" +
+ "}";
+
@Override
- public void run() {
- int id = checkCount.incrementAndGet();
- final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
- JavaSource source = new JavaSource(id);
- JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker,
- Arrays.asList("-Xlint:unchecked", "-source", sourceLevel.sourceKey),
- null, Arrays.asList(source));
- ct.call(); //to get mandatory notes
- check(source, new boolean[] {vararg_meth.giveUnchecked(client_meth),
- vararg_meth.giveVarargs(client_meth)});
+ public void doWork() throws IOException {
+ check(newCompilationTask()
+ .withOption("-Xlint:unchecked")
+ .withOption("-source")
+ .withOption(sourceLevel.sourceKey)
+ .withSourceFromTemplate(template)
+ .analyze());
}
- void check(JavaSource source, boolean[] warnArr) {
+ void check(Result<?> res) {
+ boolean[] warnArr = new boolean[] {sigs[0].giveUnchecked(sigs[1]),
+ sigs[0].giveVarargs(sigs[1])};
+
+ Set<Warning> warnings = new HashSet<>();
+ for (Diagnostic<? extends JavaFileObject> d : res.diagnosticsForKind(Kind.MANDATORY_WARNING)) {
+ if (d.getCode().contains(Warning.VARARGS.key)) {
+ warnings.add(Warning.VARARGS);
+ } else if(d.getCode().contains(Warning.UNCHECKED.key)) {
+ warnings.add(Warning.UNCHECKED);
+ }
+ }
+
boolean badOutput = false;
for (Warning wkind : Warning.values()) {
boolean isSuppressed = wkind.isSuppressed(trustMe, sourceLevel,
- suppressLevelClient, suppressLevelDecl, modKind);
+ suppress[1], suppress[0], modKind);
badOutput |= (warnArr[wkind.ordinal()] && !isSuppressed) !=
- diagChecker.warnings.contains(wkind);
+ warnings.contains(wkind);
}
if (badOutput) {
- throw new Error("invalid diagnostics for source:\n" +
- source.getCharContent(true) +
+ fail("invalid diagnostics for source:\n" +
+ res.compilationInfo() +
"\nExpected unchecked warning: " + warnArr[0] +
"\nExpected unsafe vararg warning: " + warnArr[1] +
- "\nWarnings: " + diagChecker.warnings +
+ "\nWarnings: " + warnings +
"\nSource level: " + sourceLevel);
}
}
-
- class JavaSource extends SimpleJavaFileObject {
-
- String source;
-
- public JavaSource(int id) {
- super(URI.create(String.format("myfo:/Test%d.java", id)),
- JavaFileObject.Kind.SOURCE);
- String meth1 = vararg_meth.template.replace("#arity", "...");
- meth1 = meth1.replace("#name", "m");
- meth1 = meth1.replace("#body", "");
- meth1 = trustMe.anno + "\n" + suppressLevelDecl.getSuppressAnno() +
- modKind.mod + meth1;
- String meth2 = client_meth.template.replace("#arity", "");
- meth2 = meth2.replace("#name", "test");
- meth2 = meth2.replace("#body", "m(arg);");
- meth2 = suppressLevelClient.getSuppressAnno() + meth2;
- source = String.format("import java.util.List;\n" +
- "class Test%s {\n %s \n %s \n } \n", id, meth1, meth2);
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
- }
- }
-
- static class DiagnosticChecker
- implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- Set<Warning> warnings = new HashSet<>();
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING ||
- diagnostic.getKind() == Diagnostic.Kind.WARNING) {
- if (diagnostic.getCode().contains(Warning.VARARGS.key)) {
- warnings.add(Warning.VARARGS);
- } else if(diagnostic.getCode().contains(Warning.UNCHECKED.key)) {
- warnings.add(Warning.UNCHECKED);
- }
- }
- }
- }
-
}
--- a/langtools/test/tools/javac/varargs/warning/Warn5.java Tue Sep 08 16:01:29 2015 +0400
+++ b/langtools/test/tools/javac/varargs/warning/Warn5.java Tue Sep 08 14:40:44 2015 -0700
@@ -26,29 +26,30 @@
* @bug 6993978 7097436 8006694 7196160
* @summary Project Coin: Annotation to reduce varargs warnings
* temporarily workaround combo tests are causing time out in several platforms
- * @author mcimadamore
- * @library ../../lib
- * @modules jdk.compiler
- * @build JavacTestingAbstractThreadedTest
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.comp
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.compiler/com.sun.tools.javac.tree
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
* @run main/othervm Warn5
*/
-// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
-// see JDK-8006746
-
-import java.net.URI;
-import java.util.Arrays;
+import java.io.IOException;
import java.util.EnumSet;
import javax.tools.Diagnostic;
-import javax.tools.JavaCompiler;
+import javax.tools.Diagnostic.Kind;
import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.ToolProvider;
-import com.sun.source.util.JavacTask;
-public class Warn5
- extends JavacTestingAbstractThreadedTest
- implements Runnable {
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask.Result;
+import combo.ComboTestHelper;
+
+
+public class Warn5 extends ComboInstance<Warn5> {
enum XlintOption {
NONE("none"),
@@ -65,7 +66,7 @@
}
}
- enum TrustMe {
+ enum TrustMe implements ComboParameter {
DONT_TRUST(""),
TRUST("@java.lang.SafeVarargs");
@@ -74,20 +75,26 @@
TrustMe(String anno) {
this.anno = anno;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return anno;
+ }
}
- enum SuppressLevel {
+ enum SuppressLevel implements ComboParameter {
NONE,
VARARGS;
- String getSuppressAnno() {
+ @Override
+ public String expand(String optParameter) {
return this == VARARGS ?
"@SuppressWarnings(\"varargs\")" :
"";
}
}
- enum ModifierKind {
+ enum ModifierKind implements ComboParameter {
NONE(""),
FINAL("final"),
STATIC("static"),
@@ -98,9 +105,14 @@
ModifierKind(String mod) {
this.mod = mod;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return mod;
+ }
}
- enum MethodKind {
+ enum MethodKind implements ComboParameter {
METHOD("void m"),
CONSTRUCTOR("Test");
@@ -109,6 +121,11 @@
MethodKind(String name) {
this.name = name;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return name;
+ }
}
enum SourceLevel {
@@ -123,11 +140,11 @@
}
}
- enum SignatureKind {
- VARARGS_X("#K <X>#N(X... x)", false, true),
- VARARGS_STRING("#K #N(String... x)", true, true),
- ARRAY_X("#K <X>#N(X[] x)", false, false),
- ARRAY_STRING("#K #N(String[] x)", true, false);
+ enum SignatureKind implements ComboParameter {
+ VARARGS_X("<X>#{NAME}(X... x)", false, true),
+ VARARGS_STRING("#{NAME}(String... x)", true, true),
+ ARRAY_X("<X>#{NAME}(X[] x)", false, false),
+ ARRAY_STRING("#{NAME}(String[] x)", true, false);
String stub;
boolean isReifiableArg;
@@ -139,14 +156,13 @@
this.isVarargs = isVarargs;
}
- String getSignature(ModifierKind modKind, MethodKind methKind) {
- return methKind != MethodKind.CONSTRUCTOR ?
- stub.replace("#K", modKind.mod).replace("#N", methKind.name) :
- stub.replace("#K", "").replace("#N", methKind.name);
+ @Override
+ public String expand(String optParameter) {
+ return stub;
}
}
- enum BodyKind {
+ enum BodyKind implements ComboParameter {
ASSIGN("Object o = x;", true),
CAST("Object o = (Object)x;", true),
METH("test(x);", true),
@@ -162,82 +178,84 @@
this.body = body;
this.hasAliasing = hasAliasing;
}
+
+ @Override
+ public String expand(String optParameter) {
+ return body;
+ }
}
enum WarningKind {
- UNSAFE_BODY,
- UNSAFE_DECL,
- MALFORMED_SAFEVARARGS,
- REDUNDANT_SAFEVARARGS;
+ UNSAFE_BODY("compiler.warn.varargs.unsafe.use.varargs.param"),
+ UNSAFE_DECL("compiler.warn.unchecked.varargs.non.reifiable.type"),
+ MALFORMED_SAFEVARARGS("compiler.err.varargs.invalid.trustme.anno"),
+ REDUNDANT_SAFEVARARGS("compiler.warn.varargs.redundant.trustme.anno");
+
+ String code;
+
+ WarningKind(String code) {
+ this.code = code;
+ }
+ }
+
+ public static void main(String[] args) {
+ new ComboTestHelper<Warn5>()
+ .withFilter(Warn5::badTestFilter)
+ .withDimension("SOURCE", (x, level) -> x.sourceLevel = level, SourceLevel.values())
+ .withDimension("LINT", (x, lint) -> x.xlint = lint, XlintOption.values())
+ .withDimension("TRUSTME", (x, trustme) -> x.trustMe = trustme, TrustMe.values())
+ .withDimension("SUPPRESS", (x, suppress) -> x.suppressLevel = suppress, SuppressLevel.values())
+ .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values())
+ .withDimension("NAME", (x, name) -> x.methKind = name, MethodKind.values())
+ .withDimension("SIG", (x, sig) -> x.sig = sig, SignatureKind.values())
+ .withDimension("BODY", (x, body) -> x.body = body, BodyKind.values())
+ .run(Warn5::new);
}
- public static void main(String... args) throws Exception {
- for (SourceLevel sourceLevel : SourceLevel.values()) {
- for (XlintOption xlint : XlintOption.values()) {
- for (TrustMe trustMe : TrustMe.values()) {
- for (SuppressLevel suppressLevel : SuppressLevel.values()) {
- for (ModifierKind modKind : ModifierKind.values()) {
- for (MethodKind methKind : MethodKind.values()) {
- for (SignatureKind sig : SignatureKind.values()) {
- for (BodyKind body : BodyKind.values()) {
- pool.execute(new Warn5(sourceLevel,
- xlint, trustMe, suppressLevel,
- modKind, methKind, sig, body));
- }
- }
- }
- }
+ SourceLevel sourceLevel;
+ XlintOption xlint;
+ TrustMe trustMe;
+ SuppressLevel suppressLevel;
+ ModifierKind modKind;
+ MethodKind methKind;
+ SignatureKind sig;
+ BodyKind body;
+
+ boolean badTestFilter() {
+ return (methKind != MethodKind.CONSTRUCTOR || modKind == ModifierKind.NONE);
+ }
+
+ String template = "import com.sun.tools.javac.api.*;\n" +
+ "import java.util.List;\n" +
+ "class Test {\n" +
+ " static void test(Object o) {}\n" +
+ " static void testArr(Object[] o) {}\n" +
+ " #{TRUSTME} #{SUPPRESS} #{MOD} #{SIG} { #{BODY} }\n" +
+ "}\n";
+
+ @Override
+ public void doWork() throws IOException {
+ check(newCompilationTask()
+ .withOption(xlint.getXlintOption())
+ .withOption("-source")
+ .withOption(sourceLevel.sourceKey)
+ .withSourceFromTemplate(template)
+ .analyze());
+ }
+
+ void check(Result<?> res) {
+
+ EnumSet<WarningKind> foundWarnings = EnumSet.noneOf(WarningKind.class);
+ for (Diagnostic.Kind kind : new Kind[] { Kind.ERROR, Kind.MANDATORY_WARNING, Kind.WARNING}) {
+ for (Diagnostic<? extends JavaFileObject> diag : res.diagnosticsForKind(kind)) {
+ for (WarningKind wk : WarningKind.values()) {
+ if (wk.code.equals(diag.getCode())) {
+ foundWarnings.add(wk);
}
}
}
}
- checkAfterExec(false);
- }
-
- final SourceLevel sourceLevel;
- final XlintOption xlint;
- final TrustMe trustMe;
- final SuppressLevel suppressLevel;
- final ModifierKind modKind;
- final MethodKind methKind;
- final SignatureKind sig;
- final BodyKind body;
- final JavaSource source;
- final DiagnosticChecker dc;
-
- public Warn5(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe,
- SuppressLevel suppressLevel, ModifierKind modKind,
- MethodKind methKind, SignatureKind sig, BodyKind body) {
- this.sourceLevel = sourceLevel;
- this.xlint = xlint;
- this.trustMe = trustMe;
- this.suppressLevel = suppressLevel;
- this.modKind = modKind;
- this.methKind = methKind;
- this.sig = sig;
- this.body = body;
- this.source = new JavaSource();
- this.dc = new DiagnosticChecker();
- }
-
- @Override
- public void run() {
- final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
- JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), dc,
- Arrays.asList(xlint.getXlintOption(),
- "-source", sourceLevel.sourceKey),
- null, Arrays.asList(source));
- try {
- ct.analyze();
- } catch (Throwable t) {
- processException(t);
- }
- check();
- }
-
- void check() {
-
EnumSet<WarningKind> expectedWarnings =
EnumSet.noneOf(WarningKind.class);
@@ -284,77 +302,14 @@
expectedWarnings.add(WarningKind.REDUNDANT_SAFEVARARGS);
}
- if (!expectedWarnings.containsAll(dc.warnings) ||
- !dc.warnings.containsAll(expectedWarnings)) {
- throw new Error("invalid diagnostics for source:\n" +
- source.getCharContent(true) +
+ if (!expectedWarnings.containsAll(foundWarnings) ||
+ !foundWarnings.containsAll(expectedWarnings)) {
+ fail("invalid diagnostics for source:\n" +
+ res.compilationInfo() +
"\nOptions: " + xlint.getXlintOption() +
"\nSource Level: " + sourceLevel +
"\nExpected warnings: " + expectedWarnings +
- "\nFound warnings: " + dc.warnings);
- }
- }
-
- class JavaSource extends SimpleJavaFileObject {
-
- String template = "import com.sun.tools.javac.api.*;\n" +
- "import java.util.List;\n" +
- "class Test {\n" +
- " static void test(Object o) {}\n" +
- " static void testArr(Object[] o) {}\n" +
- " #T \n #S #M { #B }\n" +
- "}\n";
-
- String source;
-
- public JavaSource() {
- super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
- source = template.replace("#T", trustMe.anno).
- replace("#S", suppressLevel.getSuppressAnno()).
- replace("#M", sig.getSignature(modKind, methKind)).
- replace("#B", body.body);
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return source;
+ "\nFound warnings: " + foundWarnings);
}
}
-
- class DiagnosticChecker
- implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- EnumSet<WarningKind> warnings = EnumSet.noneOf(WarningKind.class);
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- if (diagnostic.getKind() == Diagnostic.Kind.WARNING) {
- if (diagnostic.getCode().
- contains("unsafe.use.varargs.param")) {
- setWarning(WarningKind.UNSAFE_BODY);
- } else if (diagnostic.getCode().
- contains("redundant.trustme")) {
- setWarning(WarningKind.REDUNDANT_SAFEVARARGS);
- }
- } else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING &&
- diagnostic.getCode().
- contains("varargs.non.reifiable.type")) {
- setWarning(WarningKind.UNSAFE_DECL);
- } else if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
- diagnostic.getCode().contains("invalid.trustme")) {
- setWarning(WarningKind.MALFORMED_SAFEVARARGS);
- }
- }
-
- void setWarning(WarningKind wk) {
- if (!warnings.add(wk)) {
- throw new AssertionError("Duplicate warning of kind " +
- wk + " in source:\n" + source);
- }
- }
-
- boolean hasWarning(WarningKind wk) {
- return warnings.contains(wk);
- }
- }
-
}
--- a/make/Init.gmk Tue Sep 08 16:01:29 2015 +0400
+++ b/make/Init.gmk Tue Sep 08 14:40:44 2015 -0700
@@ -253,6 +253,7 @@
main: $(INIT_TARGETS)
ifneq ($(SEQUENTIAL_TARGETS)$(PARALLEL_TARGETS), )
$(call RotateLogFiles)
+ $(call PrepareFailureLogs)
$(BUILD_LOG_WRAPPER) $(PRINTF) "Building $(TARGET_DESCRIPTION)\n"
ifneq ($(SEQUENTIAL_TARGETS), )
# Don't touch build output dir since we might be cleaning. That
@@ -266,10 +267,13 @@
$(call PrepareSmartJavac)
( cd $(TOPDIR) && \
$(BUILD_LOG_WRAPPER) $(MAKE) $(MAKE_ARGS) $(OUTPUT_SYNC_FLAG) \
- -j $(JOBS) -f make/Main.gmk $(USER_MAKE_VARS) \
- $(PARALLEL_TARGETS) || \
- ( exitcode=$$? && $(BUILD_LOG_WRAPPER) $(PRINTF) "\nERROR: Build failed for $(TARGET_DESCRIPTION) (exit code $$exitcode) \n" && \
- $(PRINTF) "Hint: If caused by a warning, try configure --disable-warnings-as-errors \n\n" && exit $$exitcode ) )
+ -j $(JOBS) -f make/Main.gmk $(USER_MAKE_VARS) \
+ $(PARALLEL_TARGETS) || \
+ ( exitcode=$$? && $(BUILD_LOG_WRAPPER) \
+ $(PRINTF) "\nERROR: Build failed for $(TARGET_DESCRIPTION) (exit code $$exitcode) \n" && \
+ cd $(TOPDIR) && $(MAKE) $(MAKE_ARGS) -j 1 -f make/Init.gmk \
+ HAS_SPEC=true on-failure ; \
+ exit $$exitcode ) )
$(call CleanupSmartJavac)
$(call StopGlobalTimer)
$(call ReportBuildTimes)
@@ -277,5 +281,25 @@
$(BUILD_LOG_WRAPPER) $(PRINTF) "Finished building $(TARGET_DESCRIPTION)\n"
endif
- .PHONY: print-targets print-modules reconfigure main
+ on-failure:
+ ifneq ($(wildcard $(MAKESUPPORT_OUTPUTDIR)/failure-logs/*), )
+ $(PRINTF) "=== Output from failing command(s) repeated here ===\n"
+ $(foreach logfile, $(sort $(wildcard $(MAKESUPPORT_OUTPUTDIR)/failure-logs/*)), \
+ $(PRINTF) "* For target $(notdir $(basename $(logfile))):\n" $(NEWLINE) \
+ $(CAT) $(logfile) | $(GREP) -v -e "^Note: including file:" $(NEWLINE) \
+ )
+ $(PRINTF) "=== End of repeated output ===\n"
+ endif
+ if $(GREP) -q "recipe for target .* failed" $(BUILD_LOG) 2> /dev/null; then \
+ $(PRINTF) "=== Make failure sequence repeated here ===\n" ; \
+ $(GREP) "recipe for target .* failed" $(BUILD_LOG) ; \
+ $(PRINTF) "=== End of repeated output ===\n" ; \
+ $(PRINTF) "Hint: Try searching the build log for the name of the first failed target.\n" ; \
+ else \
+ $(PRINTF) "No indication of failed target found.\n" ; \
+ $(PRINTF) "Hint: Try searching the build log for '] Error'.\n" ; \
+ fi
+ $(PRINTF) "Hint: If caused by a warning, try configure --disable-warnings-as-errors.\n\n"
+
+ .PHONY: print-targets print-modules reconfigure main on-failure
endif
--- a/make/InitSupport.gmk Tue Sep 08 16:01:29 2015 +0400
+++ b/make/InitSupport.gmk Tue Sep 08 14:40:44 2015 -0700
@@ -318,6 +318,11 @@
)
endef
+ define PrepareFailureLogs
+ $(RM) -r $(MAKESUPPORT_OUTPUTDIR)/failure-logs 2> /dev/null
+ $(MKDIR) -p $(MAKESUPPORT_OUTPUTDIR)/failure-logs
+ endef
+
# Remove any javac server logs and port files. This
# prevents a new make run to reuse the previous servers.
define PrepareSmartJavac
--- a/make/common/JavaCompilation.gmk Tue Sep 08 16:01:29 2015 +0400
+++ b/make/common/JavaCompilation.gmk Tue Sep 08 14:40:44 2015 -0700
@@ -563,18 +563,19 @@
$(MKDIR) -p $$(@D) $$(dir $$($1_SJAVAC_PORTFILE))
$$(call ListPathsSafely,$1_SRCS,\n, >> $$($1_BIN)/_the.$1_batch.tmp)
$(ECHO) Compiling $1
- ($$($1_JVM) $$($1_SJAVAC) \
- $$($1_REMOTE) \
- -j 1 \
- --permit-unidentified-artifacts \
- --permit-sources-without-package \
- --compare-found-sources $$($1_BIN)/_the.$1_batch.tmp \
- --log=$(LOG_LEVEL) \
- $$($1_SJAVAC_ARGS) \
- $$($1_FLAGS) \
- $$($1_HEADERS_ARG) \
- -d $$($1_BIN) && \
- $(MV) $$($1_BIN)/_the.$1_batch.tmp $$($1_BIN)/_the.$1_batch)
+ $(call LogFailures, $$($1_BIN)/_the.$1_batch.log, $1, \
+ $$($1_JVM) $$($1_SJAVAC) \
+ $$($1_REMOTE) \
+ -j 1 \
+ --permit-unidentified-artifacts \
+ --permit-sources-without-package \
+ --compare-found-sources $$($1_BIN)/_the.$1_batch.tmp \
+ --log=$(LOG_LEVEL) \
+ $$($1_SJAVAC_ARGS) \
+ $$($1_FLAGS) \
+ $$($1_HEADERS_ARG) \
+ -d $$($1_BIN)) && \
+ $(MV) $$($1_BIN)/_the.$1_batch.tmp $$($1_BIN)/_the.$1_batch
# Create a pubapi file that only changes when the pubapi changes. Dependent
# compilations can use this file to only get recompiled when pubapi has changed.
# Grep returns 1 if no matching lines are found. Do not fail for this.
@@ -619,11 +620,11 @@
$(RM) $$($1_BIN)/_the.$1_batch $$($1_BIN)/_the.$1_batch.tmp
$$(call ListPathsSafely,$1_SRCS,\n, >> $$($1_BIN)/_the.$1_batch.tmp)
$(ECHO) Compiling `$(WC) $$($1_BIN)/_the.$1_batch.tmp | $(TR) -s ' ' | $(CUT) -f 2 -d ' '` files for $1
- ($$($1_JVM) $$($1_JAVAC) $$($1_FLAGS) \
- -implicit:none \
- -d $$($1_BIN) $$($1_HEADERS_ARG) @$$($1_BIN)/_the.$1_batch.tmp && \
- $(MV) $$($1_BIN)/_the.$1_batch.tmp $$($1_BIN)/_the.$1_batch)
-
+ $(call LogFailures, $$($1_BIN)/_the.$1_batch.log, $1, \
+ $$($1_JVM) $$($1_JAVAC) $$($1_FLAGS) \
+ -implicit:none \
+ -d $$($1_BIN) $$($1_HEADERS_ARG) @$$($1_BIN)/_the.$1_batch.tmp) && \
+ $(MV) $$($1_BIN)/_the.$1_batch.tmp $$($1_BIN)/_the.$1_batch
endif
# Add all targets to main variable
--- a/make/common/MakeBase.gmk Tue Sep 08 16:01:29 2015 +0400
+++ b/make/common/MakeBase.gmk Tue Sep 08 14:40:44 2015 -0700
@@ -755,6 +755,20 @@
$(call DependOnVariableHelper,$(strip $1),$(strip $2))
################################################################################
+# Failure logging support macros. These are supposed to be used by the Setup*
+# compilation macros.
+#
+# LogFailures will run a command and store a copy of output in a specified file.
+# If the command succeeds, the file is deleted, otherwise it is moved to the
+# failure-logs directory.
+# Param 1 - The log file of the failed command
+# Param 2 - A compact but representative name to describe this command
+# Param 3 - Command to run
+LogFailures = \
+ ( ($(BASH) $(SRC_ROOT)/common/bin/logger.sh $1 $3 && $(RM) $1) || \
+ (exitcode=$(DOLLAR)$(DOLLAR)? && $(MV) $1 $(MAKESUPPORT_OUTPUTDIR)/failure-logs/$(strip $2).log && exit $(DOLLAR)$(DOLLAR)exitcode) )
+
+################################################################################
# Find lib dir for module
# Param 1 - module name
ifeq ($(OPENJDK_TARGET_OS_TYPE), unix)
--- a/make/common/NativeCompilation.gmk Tue Sep 08 16:01:29 2015 +0400
+++ b/make/common/NativeCompilation.gmk Tue Sep 08 14:40:44 2015 -0700
@@ -201,23 +201,25 @@
$$($1_$2_OBJ) : $2 $$($1_COMPILE_VARDEPS_FILE) | $$($1_BUILD_INFO)
$(ECHO) $(LOG_INFO) "Compiling $$(notdir $2) (for $$(notdir $$($1_TARGET)))"
ifneq ($(TOOLCHAIN_TYPE), microsoft)
- # The Solaris studio compiler doesn't output the full path to the object file in the
- # generated deps files. Fixing it with sed. If compiling assembly, don't try this.
ifeq ($(TOOLCHAIN_TYPE)$$(filter %.s,$2), solstudio)
- $$($1_$2_COMP) $$($1_$2_FLAGS) $$($1_$2_DEP_FLAG) $$($1_$2_DEP).tmp $(CC_OUT_OPTION)$$($1_$2_OBJ) $2
+ # The Solaris studio compiler doesn't output the full path to the object file in the
+ # generated deps files. Fixing it with sed. If compiling assembly, don't try this.
+ $(call LogFailures, $$($1_$2_OBJ).log, $1_$$(notdir $2), \
+ $$($1_$2_COMP) $$($1_$2_FLAGS) $$($1_$2_DEP_FLAG) $$($1_$2_DEP).tmp $(CC_OUT_OPTION)$$($1_$2_OBJ) $2)
$(SED) 's|^$$(@F):|$$@:|' $$($1_$2_DEP).tmp > $$($1_$2_DEP)
else
- $$($1_$2_COMP) $$($1_$2_FLAGS) $$($1_$2_DEP_FLAG) $$($1_$2_DEP) $(CC_OUT_OPTION)$$($1_$2_OBJ) $2
+ $(call LogFailures, $$($1_$2_OBJ).log, $1_$$(notdir $2), \
+ $$($1_$2_COMP) $$($1_$2_FLAGS) $$($1_$2_DEP_FLAG) $$($1_$2_DEP) $(CC_OUT_OPTION)$$($1_$2_OBJ) $2)
endif
- endif
- # The Visual Studio compiler lacks a feature for generating make dependencies, but by
- # setting -showIncludes, all included files are printed. These are filtered out and
- # parsed into make dependences.
- ifeq ($(TOOLCHAIN_TYPE), microsoft)
- ($$($1_$2_COMP) $$($1_$2_FLAGS) -showIncludes $$($1_$2_DEBUG_OUT_FLAGS) \
- $(CC_OUT_OPTION)$$($1_$2_OBJ) $2 ; echo $$$$? > $$($1_$2_DEP).exitvalue) \
+ else
+ # The Visual Studio compiler lacks a feature for generating make dependencies, but by
+ # setting -showIncludes, all included files are printed. These are filtered out and
+ # parsed into make dependences.
+ ($(call LogFailures, $$($1_$2_OBJ).log, $1_$$(notdir $2), \
+ $$($1_$2_COMP) $$($1_$2_FLAGS) -showIncludes $$($1_$2_DEBUG_OUT_FLAGS) \
+ $(CC_OUT_OPTION)$$($1_$2_OBJ) $2) ; echo $$$$? > $$($1_$2_DEP).exitvalue) \
| $(TEE) $$($1_$2_DEP).raw | $(GREP) -v -e "^Note: including file:" \
- -e "^$(notdir $2)$$$$" || test "$$$$?" = "1" ; \
+ -e "^$(notdir $2)$$$$" || test "$$$$?" = "1" ; \
exit `cat $$($1_$2_DEP).exitvalue`
$(RM) $$($1_$2_DEP).exitvalue
($(ECHO) $$@: \\ \
@@ -694,10 +696,11 @@
$$($1_TARGET): $$($1_EXPECTED_OBJS) $$($1_RES) $$($1_REAL_MAPFILE) \
$$($1_DEBUGINFO_EXTRA_DEPS) $$($1_VARDEPS_FILE)
$(ECHO) $(LOG_INFO) "Linking $$($1_BASENAME)"
- $$($1_LD) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $$($1_SYSROOT_LDFLAGS) \
+ $(call LogFailures, $$($1_OBJECT_DIR)/$1_link.log, $1_link, \
+ $$($1_LD) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $$($1_SYSROOT_LDFLAGS) \
$(LD_OUT_OPTION)$$@ \
$$($1_EXPECTED_OBJS) $$($1_RES) \
- $$($1_LDFLAGS_SUFFIX) $$($1_EXTRA_LDFLAGS_SUFFIX)
+ $$($1_LDFLAGS_SUFFIX) $$($1_EXTRA_LDFLAGS_SUFFIX))
$$($1_CREATE_DEBUGINFO_CMDS)
# Touch target to make sure it has a later time stamp than the debug
# symbol files to avoid unnecessary relinking on rebuild.
@@ -716,8 +719,9 @@
# Generating a static library, ie object file archive.
$$($1_TARGET): $$($1_EXPECTED_OBJS) $$($1_RES) $$($1_VARDEPS_FILE)
$(ECHO) $(LOG_INFO) "Archiving $$($1_STATIC_LIBRARY)"
- $$($1_AR) $$($1_ARFLAGS) $(AR_OUT_OPTION)$$($1_TARGET) $$($1_EXPECTED_OBJS) \
- $$($1_RES) $$($1_LDFLAGS_SUFFIX) $$($1_EXTRA_LDFLAGS_SUFFIX)
+ $(call LogFailures, $$($1_OBJECT_DIR)/$1_link.log, $1_link, \
+ $$($1_AR) $$($1_ARFLAGS) $(AR_OUT_OPTION)$$($1_TARGET) $$($1_EXPECTED_OBJS) \
+ $$($1_RES) $$($1_LDFLAGS_SUFFIX) $$($1_EXTRA_LDFLAGS_SUFFIX))
endif
ifneq (,$$($1_PROGRAM))
@@ -733,10 +737,11 @@
$$($1_TARGET): $$($1_EXPECTED_OBJS) $$($1_RES) $$($1_MANIFEST) \
$$($1_DEBUGINFO_EXTRA_DEPS) $$($1_VARDEPS_FILE)
$(ECHO) $(LOG_INFO) "Linking executable $$($1_BASENAME)"
- $$($1_LD) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $$($1_SYSROOT_LDFLAGS) \
- $(EXE_OUT_OPTION)$$($1_TARGET) \
- $$($1_EXPECTED_OBJS) $$($1_RES) \
- $$($1_LDFLAGS_SUFFIX) $$($1_EXTRA_LDFLAGS_SUFFIX)
+ $(call LogFailures, $$($1_OBJECT_DIR)/$1_link.log, $1_link, \
+ $$($1_LD) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $$($1_SYSROOT_LDFLAGS) \
+ $(EXE_OUT_OPTION)$$($1_TARGET) \
+ $$($1_EXPECTED_OBJS) $$($1_RES) \
+ $$($1_LDFLAGS_SUFFIX) $$($1_EXTRA_LDFLAGS_SUFFIX))
ifeq ($(OPENJDK_TARGET_OS), windows)
ifneq ($$($1_MANIFEST), )
$$($1_MT) -nologo -manifest $$($1_MANIFEST) -identity:"$$($1_PROGRAM).exe, version=$$($1_MANIFEST_VERSION)" -outputresource:$$@;#1
--- a/nashorn/.hgtags Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/.hgtags Tue Sep 08 14:40:44 2015 -0700
@@ -313,3 +313,4 @@
33cecbc59f2ad78ac0934cbc3e014d346077e848 jdk9-b77
6f634e84387e97b2421d5e776e46935784156d1c jdk9-b78
9b3eca69b88b2d1bebce92d58280ae66fc0b6091 jdk9-b79
+61b401b23fc28208930977d46b690423911173c6 jdk9-b80
--- a/nashorn/make/project.properties Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/make/project.properties Tue Sep 08 14:40:44 2015 -0700
@@ -302,7 +302,7 @@
-XX:+HeapDumpOnOutOfMemoryError
# turn on assertions for tests
-run.test.jvmargs.main=${run.test.jvmargs.common} -esa -ea
+run.test.jvmargs.main=${run.test.jvmargs.common} -esa -ea -da:java.lang.invoke.LambdaFormEditor
# Extra jvmargs that might be useful for debugging
# and performance improvements/monitoring
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java Tue Sep 08 14:40:44 2015 -0700
@@ -107,7 +107,7 @@
private final AccessibleObject target;
private final MethodType type;
- public CallerSensitiveDynamicMethod(final AccessibleObject target) {
+ CallerSensitiveDynamicMethod(final AccessibleObject target) {
super(getName(target));
this.target = target;
this.type = getMethodType(target);
@@ -115,8 +115,9 @@
private static String getName(final AccessibleObject target) {
final Member m = (Member)target;
- return getMethodNameWithSignature(getMethodType(target), getClassAndMethodName(m.getDeclaringClass(),
- m.getName()));
+ final boolean constructor = m instanceof Constructor;
+ return getMethodNameWithSignature(getMethodType(target), constructor ? m.getName() :
+ getClassAndMethodName(m.getDeclaringClass(), m.getName()), !constructor);
}
@Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java Tue Sep 08 14:40:44 2015 -0700
@@ -86,7 +86,9 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.text.Collator;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -242,6 +244,35 @@
return methods.getFirst().isConstructor();
}
+ @Override
+ public String toString() {
+ // First gather the names and sort them. This makes it consistent and easier to read.
+ final List<String> names = new ArrayList<>(methods.size());
+ int len = 0;
+ for (final SingleDynamicMethod m: methods) {
+ final String name = m.getName();
+ len += name.length();
+ names.add(name);
+ }
+ // Case insensitive sorting, so e.g. "Object" doesn't come before "boolean".
+ final Collator collator = Collator.getInstance();
+ collator.setStrength(Collator.SECONDARY);
+ Collections.sort(names, collator);
+
+ final String className = getClass().getName();
+ // Class name length + length of signatures + 2 chars/per signature for indentation and newline +
+ // 3 for brackets and initial newline
+ final int totalLength = className.length() + len + 2 * names.size() + 3;
+ final StringBuilder b = new StringBuilder(totalLength);
+ b.append('[').append(className).append('\n');
+ for(final String name: names) {
+ b.append(' ').append(name).append('\n');
+ }
+ b.append(']');
+ assert b.length() == totalLength;
+ return b.toString();
+ };
+
ClassLoader getClassLoader() {
return classLoader;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SimpleDynamicMethod.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SimpleDynamicMethod.java Tue Sep 08 14:40:44 2015 -0700
@@ -122,13 +122,13 @@
* @param constructor does this represent a constructor?
*/
SimpleDynamicMethod(final MethodHandle target, final Class<?> clazz, final String name, final boolean constructor) {
- super(getName(target, clazz, name));
+ super(getName(target, clazz, name, constructor));
this.target = target;
this.constructor = constructor;
}
- private static String getName(final MethodHandle target, final Class<?> clazz, final String name) {
- return getMethodNameWithSignature(target.type(), getClassAndMethodName(clazz, name));
+ private static String getName(final MethodHandle target, final Class<?> clazz, final String name, final boolean constructor) {
+ return getMethodNameWithSignature(target.type(), constructor ? name : getClassAndMethodName(clazz, name), !constructor);
}
@Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SingleDynamicMethod.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SingleDynamicMethod.java Tue Sep 08 14:40:44 2015 -0700
@@ -143,14 +143,18 @@
return getMethodType().parameterList().equals(method.getMethodType().parameterList());
}
- static String getMethodNameWithSignature(final MethodType type, final String methodName) {
+ static String getMethodNameWithSignature(final MethodType type, final String methodName, final boolean withReturnType) {
final String typeStr = 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);
+ final StringBuilder b = new StringBuilder();
+ if (withReturnType) {
+ b.append(typeStr, retTypeIndex, typeStr.length()).append(' ');
+ }
+ return b.append(methodName).append('(').append(typeStr, secondParamIndex, retTypeIndex).toString();
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornException.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornException.java Tue Sep 08 14:40:44 2015 -0700
@@ -51,6 +51,8 @@
private String fileName;
// script line number
private int line;
+ // are the line and fileName unknown?
+ private boolean lineAndFileNameUnknown;
// script column number
private int column;
// underlying ECMA error object - lazily initialized
@@ -92,27 +94,10 @@
*/
protected NashornException(final String msg, final Throwable cause) {
super(msg, cause == null ? null : cause);
- // This is not so pretty - but it gets the job done. Note that the stack
- // trace has been already filled by "fillInStackTrace" call from
- // Throwable
- // constructor and so we don't pay additional cost for it.
-
// Hard luck - no column number info
this.column = -1;
-
- // Find the first JavaScript frame by walking and set file, line from it
- // Usually, we should be able to find it in just few frames depth.
- for (final StackTraceElement ste : getStackTrace()) {
- if (ECMAErrors.isScriptFrame(ste)) {
- // Whatever here is compiled from JavaScript code
- this.fileName = ste.getFileName();
- this.line = ste.getLineNumber();
- return;
- }
- }
-
- this.fileName = null;
- this.line = 0;
+ // We can retrieve the line number and file name from the stack trace if needed
+ this.lineAndFileNameUnknown = true;
}
/**
@@ -121,6 +106,7 @@
* @return the file name
*/
public final String getFileName() {
+ ensureLineAndFileName();
return fileName;
}
@@ -131,6 +117,7 @@
*/
public final void setFileName(final String fileName) {
this.fileName = fileName;
+ lineAndFileNameUnknown = false;
}
/**
@@ -139,6 +126,7 @@
* @return the line number
*/
public final int getLineNumber() {
+ ensureLineAndFileName();
return line;
}
@@ -148,6 +136,7 @@
* @param line the line number
*/
public final void setLineNumber(final int line) {
+ lineAndFileNameUnknown = false;
this.line = line;
}
@@ -274,4 +263,19 @@
public void setEcmaError(final Object ecmaError) {
this.ecmaError = ecmaError;
}
+
+ private void ensureLineAndFileName() {
+ if (lineAndFileNameUnknown) {
+ for (final StackTraceElement ste : getStackTrace()) {
+ if (ECMAErrors.isScriptFrame(ste)) {
+ // Whatever here is compiled from JavaScript code
+ fileName = ste.getFileName();
+ line = ste.getLineNumber();
+ return;
+ }
+ }
+
+ lineAndFileNameUnknown = false;
+ }
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ApplySpecialization.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ApplySpecialization.java Tue Sep 08 14:40:44 2015 -0700
@@ -283,17 +283,13 @@
start++;
}
- start++; //we always uses this
+ start++; // we always use this
- final List<IdentNode> params = functionNode.getParameters();
+ assert functionNode.getNumOfParams() == 0 : "apply2call on function with named paramaters!";
final List<IdentNode> newParams = new ArrayList<>();
- final long to = Math.max(params.size(), actualCallSiteType.parameterCount() - start);
+ final long to = actualCallSiteType.parameterCount() - start;
for (int i = 0; i < to; i++) {
- if (i >= params.size()) {
- newParams.add(new IdentNode(functionNode.getToken(), functionNode.getFinish(), EXPLODED_ARGUMENT_PREFIX.symbolName() + (i)));
- } else {
- newParams.add(params.get(i));
- }
+ newParams.add(new IdentNode(functionNode.getToken(), functionNode.getFinish(), EXPLODED_ARGUMENT_PREFIX.symbolName() + (i)));
}
callSiteTypes.push(actualCallSiteType);
@@ -316,6 +312,10 @@
return false;
}
+ if (functionNode.getNumOfParams() != 0) {
+ return false;
+ }
+
if (functionNode.hasEval()) {
return false;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Tue Sep 08 14:40:44 2015 -0700
@@ -149,12 +149,14 @@
private final Deque<Set<String>> thisProperties = new ArrayDeque<>();
private final Map<String, Symbol> globalSymbols = new HashMap<>(); //reuse the same global symbol
private final Compiler compiler;
+ private final boolean isOnDemand;
public AssignSymbols(final Compiler compiler) {
super(new LexicalContext());
this.compiler = compiler;
this.log = initLogger(compiler.getContext());
this.debug = log.isEnabled();
+ this.isOnDemand = compiler.isOnDemandCompilation();
}
@Override
@@ -390,7 +392,7 @@
// Create and add to appropriate block.
symbol = createSymbol(name, flags);
- symbolBlock.putSymbol(lc, symbol);
+ symbolBlock.putSymbol(symbol);
if ((flags & IS_SCOPE) == 0) {
// Initial assumption; symbol can lose its slot later
@@ -440,7 +442,7 @@
start(block);
if (lc.isFunctionBody()) {
- block.clearSymbols();
+ assert !block.hasSymbols();
final FunctionNode fn = lc.getCurrentFunction();
if (isUnparsedFunction(fn)) {
// It's a skipped nested function. Just mark the symbols being used by it as being in use.
@@ -459,7 +461,7 @@
}
private boolean isUnparsedFunction(final FunctionNode fn) {
- return compiler.isOnDemandCompilation() && fn != lc.getOutermostFunction();
+ return isOnDemand && fn != lc.getOutermostFunction();
}
@Override
@@ -747,28 +749,6 @@
}
}
- @Override
- public Node leaveBlock(final Block block) {
- // It's not necessary to guard the marking of symbols as locals with this "if" condition for
- // correctness, it's just an optimization -- runtime type calculation is not used when the compilation
- // is not an on-demand optimistic compilation, so we can skip locals marking then.
- if (compiler.useOptimisticTypes() && compiler.isOnDemandCompilation()) {
- // OTOH, we must not declare symbols from nested functions to be locals. As we're doing on-demand
- // compilation, and we're skipping parsing the function bodies for nested functions, this
- // basically only means their parameters. It'd be enough to mistakenly declare to be a local a
- // symbol in the outer function named the same as one of the parameters, though.
- if (lc.getFunction(block) == lc.getOutermostFunction()) {
- for (final Symbol symbol: block.getSymbols()) {
- if (!symbol.isScope()) {
- assert symbol.isVar() || symbol.isParam();
- compiler.declareLocalSymbol(symbol.getName());
- }
- }
- }
- }
- return block;
- }
-
private Node leaveDELETE(final UnaryNode unaryNode) {
final FunctionNode currentFunctionNode = lc.getCurrentFunction();
final boolean strictMode = currentFunctionNode.isStrict();
@@ -786,9 +766,9 @@
if (symbol.isThis()) {
// Can't delete "this", ignore and return true
- return LiteralNode.newInstance(unaryNode, true).accept(this);
+ return LiteralNode.newInstance(unaryNode, true);
}
- final Expression literalNode = (Expression)LiteralNode.newInstance(unaryNode, name).accept(this);
+ final Expression literalNode = LiteralNode.newInstance(unaryNode, name);
final boolean failDelete = strictMode || (!symbol.isScope() && (symbol.isParam() || (symbol.isVar() && !symbol.isProgramLevel())));
if (!failDelete) {
@@ -799,7 +779,7 @@
if (failDelete) {
request = Request.FAIL_DELETE;
- } else if (symbol.isGlobal() && !symbol.isFunctionDeclaration()) {
+ } else if ((symbol.isGlobal() && !symbol.isFunctionDeclaration()) || symbol.isProgramLevel()) {
request = Request.SLOW_DELETE;
}
} else if (rhs instanceof AccessNode) {
@@ -807,7 +787,7 @@
final String property = ((AccessNode)rhs).getProperty();
args.add(base);
- args.add((Expression)LiteralNode.newInstance(unaryNode, property).accept(this));
+ args.add(LiteralNode.newInstance(unaryNode, property));
args.add(strictFlagNode);
} else if (rhs instanceof IndexNode) {
@@ -820,15 +800,15 @@
args.add(strictFlagNode);
} else {
- return LiteralNode.newInstance(unaryNode, true).accept(this);
+ return LiteralNode.newInstance(unaryNode, true);
}
- return new RuntimeNode(unaryNode, request, args).accept(this);
+ return new RuntimeNode(unaryNode, request, args);
}
@Override
public Node leaveForNode(final ForNode forNode) {
if (forNode.isForIn()) {
- forNode.setIterator(newObjectInternal(ITERATOR_PREFIX)); //NASHORN-73
+ return forNode.setIterator(lc, newObjectInternal(ITERATOR_PREFIX)); //NASHORN-73
}
return end(forNode);
@@ -904,19 +884,18 @@
public Node leaveSwitchNode(final SwitchNode switchNode) {
// We only need a symbol for the tag if it's not an integer switch node
if(!switchNode.isUniqueInteger()) {
- switchNode.setTag(newObjectInternal(SWITCH_TAG_PREFIX));
+ return switchNode.setTag(lc, newObjectInternal(SWITCH_TAG_PREFIX));
}
return switchNode;
}
@Override
public Node leaveTryNode(final TryNode tryNode) {
- tryNode.setException(exceptionSymbol());
assert tryNode.getFinallyBody() == null;
end(tryNode);
- return tryNode;
+ return tryNode.setException(lc, exceptionSymbol());
}
private Node leaveTYPEOF(final UnaryNode unaryNode) {
@@ -925,13 +904,13 @@
final List<Expression> args = new ArrayList<>();
if (rhs instanceof IdentNode && !isParamOrVar((IdentNode)rhs)) {
args.add(compilerConstantIdentifier(SCOPE));
- args.add((Expression)LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null
+ args.add(LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName())); //null
} else {
args.add(rhs);
- args.add((Expression)LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this'
+ args.add(LiteralNode.newInstance(unaryNode)); //null, do not reuse token of identifier rhs, it can be e.g. 'this'
}
- final Node runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args).accept(this);
+ final Node runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args);
end(unaryNode);
@@ -939,7 +918,7 @@
}
private FunctionNode markProgramBlock(final FunctionNode functionNode) {
- if (compiler.isOnDemandCompilation() || !functionNode.isProgram()) {
+ if (isOnDemand || !functionNode.isProgram()) {
return functionNode;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AstSerializer.java Tue Sep 08 16:01:29 2015 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
- * 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.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectOutputStream;
-import java.util.Collections;
-import java.util.zip.Deflater;
-import java.util.zip.DeflaterOutputStream;
-import jdk.nashorn.internal.ir.Block;
-import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.LexicalContext;
-import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.Statement;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.options.Options;
-
-/**
- * This static utility class performs serialization of FunctionNode ASTs to a byte array.
- * The format is a standard Java serialization stream, deflated.
- */
-final class AstSerializer {
- // Experimentally, we concluded that compression level 4 gives a good tradeoff between serialization speed
- // and size.
- private static final int COMPRESSION_LEVEL = Options.getIntProperty("nashorn.serialize.compression", 4);
- static byte[] serialize(final FunctionNode fn) {
- final ByteArrayOutputStream out = new ByteArrayOutputStream();
- final Deflater deflater = new Deflater(COMPRESSION_LEVEL);
- try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out, deflater))) {
- oout.writeObject(removeInnerFunctionBodies(fn));
- } catch (final IOException e) {
- throw new AssertionError("Unexpected exception serializing function", e);
- } finally {
- deflater.end();
- }
- return out.toByteArray();
- }
-
- private static FunctionNode removeInnerFunctionBodies(final FunctionNode fn) {
- return (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
- @Override
- public Node leaveBlock(final Block block) {
- if (lc.isFunctionBody() && lc.getFunction(block) != lc.getOutermostFunction()) {
- return block.setStatements(lc, Collections.<Statement>emptyList());
- }
- return super.leaveBlock(block);
- }
- });
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CacheAst.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.ArrayDeque;
+import java.util.Collections;
+import java.util.Deque;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.Statement;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
+
+class CacheAst extends NodeVisitor<LexicalContext> {
+ private final Deque<RecompilableScriptFunctionData> dataStack = new ArrayDeque<>();
+
+ private final Compiler compiler;
+
+ CacheAst(final Compiler compiler) {
+ super(new LexicalContext());
+ this.compiler = compiler;
+ assert !compiler.isOnDemandCompilation();
+ }
+
+ @Override
+ public boolean enterFunctionNode(final FunctionNode functionNode) {
+ final int id = functionNode.getId();
+ // It isn't necessary to keep a stack of RecompilableScriptFunctionData, but then we'd need to do a
+ // potentially transitive lookup with compiler.getScriptFunctionData(id) for deeper functions; this way
+ // we keep it constant time.
+ dataStack.push(dataStack.isEmpty() ? compiler.getScriptFunctionData(id) : dataStack.peek().getScriptFunctionData(id));
+ return true;
+ }
+
+ @Override
+ public Node leaveFunctionNode(final FunctionNode functionNode) {
+ final RecompilableScriptFunctionData data = dataStack.pop();
+ if (functionNode.isSplit()) {
+ // NOTE: cache only split function ASTs from eager pass. Caching non-split functions would require
+ // some additional work, namely creating the concept of "uncacheable" function and reworking
+ // ApplySpecialization to ensure that functions undergoing apply-to-call transformations are not
+ // cacheable as well as recomputing Symbol.useCount when caching the eagerly parsed AST.
+ // Recomputing Symbol.useCount would be needed so it will only reflect uses from within the
+ // function being cached (and not reflect uses from its own nested functions or functions it is
+ // nested in). This is consistent with the count an on-demand recompilation of the function would
+ // produce. This is important as the decision to emit shared scope calls is based on this count,
+ // and if it is not matched between a previous version of the code and its deoptimizing rest-of
+ // compilation, it can result in rest-of not emitting a shared scope call where a previous version
+ // of the code (compiled from a cached eager pre-pass seeing higher (global) useCount) would emit
+ // it, causing a mismatch in stack shapes between previous code and its rest-of.
+ data.setCachedAst(functionNode);
+ }
+
+ if (!dataStack.isEmpty() && ((dataStack.peek().getFunctionFlags() & FunctionNode.IS_SPLIT) != 0)) {
+ // Return a function node with no body so that caching outer functions doesn't hold on to nested
+ // functions' bodies. Note we're doing this only for functions directly nested inside split
+ // functions, since we're only caching the split ones. It is not necessary to limit body removal
+ // to just these functions, but it's a cheap way to prevent unnecessary AST mutations.
+ return functionNode.setBody(lc, functionNode.getBody().setStatements(null, Collections.<Statement>emptyList()));
+ }
+ return functionNode;
+ }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java Tue Sep 08 14:40:44 2015 -0700
@@ -48,11 +48,13 @@
import java.util.Set;
import jdk.nashorn.internal.AssertsEnabled;
import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
+import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.debug.ASTWriter;
import jdk.nashorn.internal.ir.debug.PrintVisitor;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -189,7 +191,7 @@
}
},
- SERIALIZE_SPLIT_PHASE(
+ CACHE_AST(
EnumSet.of(
INITIALIZED,
PARSED,
@@ -199,20 +201,21 @@
SPLIT)) {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
- return transformFunction(fn, new NodeVisitor<LexicalContext>(new LexicalContext()) {
- @Override
- public boolean enterFunctionNode(final FunctionNode functionNode) {
- if (functionNode.isSplit()) {
- compiler.serializeAst(functionNode);
- }
- return true;
- }
- });
+ if (!compiler.isOnDemandCompilation()) {
+ // Only do this on initial preprocessing of the source code. For on-demand compilations from
+ // source, FindScopeDepths#leaveFunctionNode() calls data.setCachedAst() for the sole function
+ // being compiled.
+ transformFunction(fn, new CacheAst(compiler));
+ }
+ // NOTE: we're returning the original fn as we have destructively modified the cached functions by
+ // removing their bodies. This step is associating FunctionNode objects with
+ // RecompilableScriptFunctionData; it's not really modifying the AST.
+ return fn;
}
@Override
public String toString() {
- return "'Serialize Split Functions'";
+ return "'Cache ASTs'";
}
},
@@ -255,6 +258,51 @@
}
},
+ DECLARE_LOCAL_SYMBOLS_TO_COMPILER(
+ EnumSet.of(
+ INITIALIZED,
+ PARSED,
+ CONSTANT_FOLDED,
+ LOWERED,
+ BUILTINS_TRANSFORMED,
+ SPLIT,
+ SYMBOLS_ASSIGNED,
+ SCOPE_DEPTHS_COMPUTED)) {
+ @Override
+ FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
+ // It's not necessary to guard the marking of symbols as locals with this "if" condition for
+ // correctness, it's just an optimization -- runtime type calculation is not used when the compilation
+ // is not an on-demand optimistic compilation, so we can skip locals marking then.
+ if (compiler.useOptimisticTypes() && compiler.isOnDemandCompilation()) {
+ fn.getBody().accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ @Override
+ public boolean enterFunctionNode(final FunctionNode functionNode) {
+ // OTOH, we must not declare symbols from nested functions to be locals. As we're doing on-demand
+ // compilation, and we're skipping parsing the function bodies for nested functions, this
+ // basically only means their parameters. It'd be enough to mistakenly declare to be a local a
+ // symbol in the outer function named the same as one of the parameters, though.
+ return false;
+ };
+ @Override
+ public boolean enterBlock(final Block block) {
+ for (final Symbol symbol: block.getSymbols()) {
+ if (!symbol.isScope()) {
+ compiler.declareLocalSymbol(symbol.getName());
+ }
+ }
+ return true;
+ };
+ });
+ }
+ return fn;
+ }
+
+ @Override
+ public String toString() {
+ return "'Local Symbols Declaration'";
+ }
+ },
+
OPTIMISTIC_TYPE_ASSIGNMENT_PHASE(
EnumSet.of(
INITIALIZED,
@@ -382,7 +430,7 @@
}
},
- REINITIALIZE_SERIALIZED(
+ REINITIALIZE_CACHED(
EnumSet.of(
INITIALIZED,
PARSED,
@@ -430,7 +478,7 @@
@Override
public String toString() {
- return "'Deserialize'";
+ return "'Reinitialize cached'";
}
},
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java Tue Sep 08 14:40:44 2015 -0700
@@ -160,42 +160,41 @@
*/
private static final int COMPILE_UNIT_NAME_BUFFER_SIZE = 32;
- private final Map<Integer, byte[]> serializedAsts = new HashMap<>();
-
/**
* Compilation phases that a compilation goes through
*/
public static class CompilationPhases implements Iterable<CompilationPhase> {
/**
- * Singleton that describes compilation up to the phase where a function can be serialized.
+ * Singleton that describes compilation up to the phase where a function can be cached.
*/
- private final static CompilationPhases COMPILE_UPTO_SERIALIZABLE = new CompilationPhases(
+ private final static CompilationPhases COMPILE_UPTO_CACHED = new CompilationPhases(
"Common initial phases",
CompilationPhase.CONSTANT_FOLDING_PHASE,
CompilationPhase.LOWERING_PHASE,
CompilationPhase.TRANSFORM_BUILTINS_PHASE,
CompilationPhase.SPLITTING_PHASE,
CompilationPhase.PROGRAM_POINT_PHASE,
- CompilationPhase.SERIALIZE_SPLIT_PHASE
+ CompilationPhase.SYMBOL_ASSIGNMENT_PHASE,
+ CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE,
+ CompilationPhase.CACHE_AST
);
- private final static CompilationPhases COMPILE_SERIALIZABLE_UPTO_BYTECODE = new CompilationPhases(
+ private final static CompilationPhases COMPILE_CACHED_UPTO_BYTECODE = new CompilationPhases(
"After common phases, before bytecode generator",
- CompilationPhase.SYMBOL_ASSIGNMENT_PHASE,
- CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE,
+ CompilationPhase.DECLARE_LOCAL_SYMBOLS_TO_COMPILER,
CompilationPhase.OPTIMISTIC_TYPE_ASSIGNMENT_PHASE,
CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE
);
/**
- * Singleton that describes additional steps to be taken after deserializing, all the way up to (but not
- * including) generating and installing code.
+ * Singleton that describes additional steps to be taken after retrieving a cached function, all the
+ * way up to (but not including) generating and installing code.
*/
- public final static CompilationPhases RECOMPILE_SERIALIZED_UPTO_BYTECODE = new CompilationPhases(
- "Recompile serialized function up to bytecode",
- CompilationPhase.REINITIALIZE_SERIALIZED,
- COMPILE_SERIALIZABLE_UPTO_BYTECODE
+ public final static CompilationPhases RECOMPILE_CACHED_UPTO_BYTECODE = new CompilationPhases(
+ "Recompile cached function up to bytecode",
+ CompilationPhase.REINITIALIZE_CACHED,
+ COMPILE_CACHED_UPTO_BYTECODE
);
/**
@@ -211,8 +210,8 @@
/** Singleton that describes compilation up to the CodeGenerator, but not actually generating code */
public final static CompilationPhases COMPILE_UPTO_BYTECODE = new CompilationPhases(
"Compile upto bytecode",
- COMPILE_UPTO_SERIALIZABLE,
- COMPILE_SERIALIZABLE_UPTO_BYTECODE);
+ COMPILE_UPTO_CACHED,
+ COMPILE_CACHED_UPTO_BYTECODE);
/** Singleton that describes a standard eager compilation, but no installation, for example used by --compile-only */
public final static CompilationPhases COMPILE_ALL_NO_INSTALL = new CompilationPhases(
@@ -227,9 +226,9 @@
GENERATE_BYTECODE_AND_INSTALL);
/** Singleton that describes a full compilation - this includes code installation - from serialized state*/
- public final static CompilationPhases COMPILE_ALL_SERIALIZED = new CompilationPhases(
+ public final static CompilationPhases COMPILE_ALL_CACHED = new CompilationPhases(
"Eager compilation from serializaed state",
- RECOMPILE_SERIALIZED_UPTO_BYTECODE,
+ RECOMPILE_CACHED_UPTO_BYTECODE,
GENERATE_BYTECODE_AND_INSTALL);
/**
@@ -248,9 +247,9 @@
GENERATE_BYTECODE_AND_INSTALL_RESTOF);
/** Compile from serialized for a rest of method */
- public final static CompilationPhases COMPILE_SERIALIZED_RESTOF = new CompilationPhases(
+ public final static CompilationPhases COMPILE_CACHED_RESTOF = new CompilationPhases(
"Compile serialized, rest of",
- RECOMPILE_SERIALIZED_UPTO_BYTECODE,
+ RECOMPILE_CACHED_UPTO_BYTECODE,
GENERATE_BYTECODE_AND_INSTALL_RESTOF);
private final List<CompilationPhase> phases;
@@ -313,7 +312,7 @@
}
boolean isRestOfCompilation() {
- return this == COMPILE_ALL_RESTOF || this == GENERATE_BYTECODE_AND_INSTALL_RESTOF || this == COMPILE_SERIALIZED_RESTOF;
+ return this == COMPILE_ALL_RESTOF || this == GENERATE_BYTECODE_AND_INSTALL_RESTOF || this == COMPILE_CACHED_RESTOF;
}
String getDesc() {
@@ -766,14 +765,6 @@
compileUnits.addAll(newUnits);
}
- void serializeAst(final FunctionNode fn) {
- serializedAsts.put(fn.getId(), AstSerializer.serialize(fn));
- }
-
- byte[] removeSerializedAst(final int fnId) {
- return serializedAsts.remove(fnId);
- }
-
CompileUnit findUnit(final long weight) {
for (final CompileUnit unit : compileUnits) {
if (unit.canHold(weight)) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FindScopeDepths.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FindScopeDepths.java Tue Sep 08 14:40:44 2015 -0700
@@ -188,6 +188,9 @@
log.fine("Reviving scriptfunction ", quote(name), " as defined in previous (now lost) dynamic scope.");
newFunctionNode = newFunctionNode.setInDynamicContext(lc);
}
+ if (newFunctionNode == lc.getOutermostFunction() && !newFunctionNode.hasApplyToCallSpecialization()) {
+ data.setCachedAst(newFunctionNode);
+ }
return newFunctionNode;
}
@@ -208,8 +211,7 @@
ObjectClassGenerator.createAllocationStrategy(newFunctionNode.getThisProperties(), compiler.getContext().useDualFields()),
nestedFunctions,
externalSymbolDepths.get(fnId),
- internalSymbols.get(fnId),
- compiler.removeSerializedAst(fnId));
+ internalSymbols.get(fnId));
if (lc.getOutermostFunction() != newFunctionNode) {
final FunctionNode parentFn = lc.getParentFunction(newFunctionNode);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Label.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Label.java Tue Sep 08 14:40:44 2015 -0700
@@ -497,7 +497,7 @@
private transient Label.Stack stack;
/** ASM representation of this label */
- private jdk.internal.org.objectweb.asm.Label label;
+ private transient jdk.internal.org.objectweb.asm.Label label;
/** Id for debugging purposes, remove if footprint becomes unmanageable */
private final int id;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeMap.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeMap.java Tue Sep 08 14:40:44 2015 -0700
@@ -27,21 +27,18 @@
import java.lang.invoke.MethodType;
import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
import java.util.NoSuchElementException;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.runtime.ScriptFunction;
/**
- * A data structure that maps one or several function nodes (by their unique id:s, not by
- * the FunctionNode object itself, due to copy on write changing it several times through
- * code generation.
+ * A tuple containing function id, parameter types, return type and needsCallee flag.
*/
-public class TypeMap {
- private final Map<Integer, Type[]> paramTypeMap = new HashMap<>();
- private final Map<Integer, Type> returnTypeMap = new HashMap<>();
+public final class TypeMap {
+ private final int functionNodeId;
+ private final Type[] paramTypes;
+ private final Type returnType;
private final boolean needsCallee;
/**
@@ -56,9 +53,10 @@
for (final Class<?> p : type.parameterArray()) {
types[pos++] = Type.typeFor(p);
}
- paramTypeMap.put(functionNodeId, types);
- returnTypeMap.put(functionNodeId, Type.typeFor(type.returnType()));
+ this.functionNodeId = functionNodeId;
+ this.paramTypes = types;
+ this.returnType = Type.typeFor(type.returnType());
this.needsCallee = needsCallee;
}
@@ -69,20 +67,14 @@
* @throws NoSuchElementException if the type map has no mapping for the requested function
*/
public Type[] getParameterTypes(final int functionNodeId) {
- final Type[] paramTypes = paramTypeMap.get(functionNodeId);
- if (paramTypes == null) {
- throw new NoSuchElementException(Integer.toString(functionNodeId));
- }
+ assert this.functionNodeId == functionNodeId;
return paramTypes.clone();
}
MethodType getCallSiteType(final FunctionNode functionNode) {
- final Type[] types = paramTypeMap.get(functionNode.getId());
- if (types == null) {
- return null;
- }
-
- MethodType mt = MethodType.methodType(returnTypeMap.get(functionNode.getId()).getTypeClass());
+ assert this.functionNodeId == functionNode.getId();
+ final Type[] types = paramTypes;
+ MethodType mt = MethodType.methodType(returnType.getTypeClass());
if (needsCallee) {
mt = mt.appendParameterTypes(ScriptFunction.class);
}
@@ -116,7 +108,8 @@
* @return parameter type for this callsite if known
*/
Type get(final FunctionNode functionNode, final int pos) {
- final Type[] types = paramTypeMap.get(functionNode.getId());
+ assert this.functionNodeId == functionNode.getId();
+ final Type[] types = paramTypes;
assert types == null || pos < types.length : "fn = " + functionNode.getId() + " " + "types=" + Arrays.toString(types) + " || pos=" + pos + " >= length=" + types.length + " in " + this;
if (types != null && pos < types.length) {
return types[pos];
@@ -124,13 +117,6 @@
return null;
}
- boolean has(final FunctionNode functionNode) {
- final int id = functionNode.getId();
- final Type[] paramTypes = paramTypeMap.get(id);
- assert (paramTypes == null) == (returnTypeMap.get(id) == null) : "inconsistent param and return types in param map";
- return paramTypes != null;
- }
-
@Override
public String toString() {
return toString("");
@@ -139,27 +125,16 @@
String toString(final String prefix) {
final StringBuilder sb = new StringBuilder();
- if (paramTypeMap.isEmpty()) {
- sb.append(prefix).append("\t<empty>");
- return sb.toString();
- }
-
- for (final Map.Entry<Integer, Type[]> entry : paramTypeMap.entrySet()) {
- final int id = entry.getKey();
- sb.append(prefix).append('\t');
- sb.append("function ").append(id).append('\n');
- sb.append(prefix).append("\t\tparamTypes=");
- if (entry.getValue() == null) {
- sb.append("[]");
- } else {
- sb.append(Arrays.toString(entry.getValue()));
- }
- sb.append('\n');
- sb.append(prefix).append("\t\treturnType=");
- final Type ret = returnTypeMap.get(id);
- sb.append(ret == null ? "N/A" : ret);
- sb.append('\n');
- }
+ final int id = functionNodeId;
+ sb.append(prefix).append('\t');
+ sb.append("function ").append(id).append('\n');
+ sb.append(prefix).append("\t\tparamTypes=");
+ sb.append(Arrays.toString(paramTypes));
+ sb.append('\n');
+ sb.append(prefix).append("\t\treturnType=");
+ final Type ret = returnType;
+ sb.append(ret == null ? "N/A" : ret);
+ sb.append('\n');
return sb.toString();
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java Tue Sep 08 14:40:44 2015 -0700
@@ -159,11 +159,42 @@
}
/**
- * Clear the symbols in the block.
- * TODO: make this immutable.
+ * Returns true if this block defines any symbols.
+ * @return true if this block defines any symbols.
+ */
+ public boolean hasSymbols() {
+ return !symbols.isEmpty();
+ }
+
+ /**
+ * Replaces symbols defined in this block with different symbols. Used to ensure symbol tables are
+ * immutable upon construction and have copy-on-write semantics. Note that this method only replaces the
+ * symbols in the symbol table, it does not act on any contained AST nodes that might reference the symbols.
+ * Those should be updated separately as this method is meant to be used as part of such an update pass.
+ * @param lc the current lexical context
+ * @param replacements the map of symbol replacements
+ * @return a new block with replaced symbols, or this block if none of the replacements modified the symbol
+ * table.
*/
- public void clearSymbols() {
- symbols.clear();
+ public Block replaceSymbols(final LexicalContext lc, final Map<Symbol, Symbol> replacements) {
+ if (symbols.isEmpty()) {
+ return this;
+ }
+ final LinkedHashMap<String, Symbol> newSymbols = new LinkedHashMap<>(symbols);
+ for (final Map.Entry<String, Symbol> entry: newSymbols.entrySet()) {
+ final Symbol newSymbol = replacements.get(entry.getValue());
+ assert newSymbol != null : "Missing replacement for " + entry.getKey();
+ entry.setValue(newSymbol);
+ }
+ return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, newSymbols, conversion));
+ }
+
+ /**
+ * Returns a copy of this block with a shallow copy of the symbol table.
+ * @return a copy of this block with a shallow copy of the symbol table.
+ */
+ public Block copyWithNewSymbols() {
+ return new Block(this, finish, statements, flags, new LinkedHashMap<>(symbols), conversion);
}
@Override
@@ -191,7 +222,7 @@
* @return symbol iterator
*/
public List<Symbol> getSymbols() {
- return Collections.unmodifiableList(new ArrayList<>(symbols.values()));
+ return symbols.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(new ArrayList<>(symbols.values()));
}
/**
@@ -355,10 +386,9 @@
/**
* Add or overwrite an existing symbol in the block
*
- * @param lc get lexical context
* @param symbol symbol
*/
- public void putSymbol(final LexicalContext lc, final Symbol symbol) {
+ public void putSymbol(final Symbol symbol) {
symbols.put(symbol.getName(), symbol);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java Tue Sep 08 14:40:44 2015 -0700
@@ -43,7 +43,7 @@
private final JoinPredecessorExpression modify;
/** Iterator symbol. */
- private Symbol iterator;
+ private final Symbol iterator;
/** Is this a normal for in loop? */
public static final int IS_FOR_IN = 1 << 0;
@@ -86,23 +86,23 @@
this.flags = flags;
this.init = init;
this.modify = modify;
+ this.iterator = null;
}
private ForNode(final ForNode forNode, final Expression init, final JoinPredecessorExpression test,
- final Block body, final JoinPredecessorExpression modify, final int flags, final boolean controlFlowEscapes, final LocalVariableConversion conversion) {
+ final Block body, final JoinPredecessorExpression modify, final int flags,
+ final boolean controlFlowEscapes, final LocalVariableConversion conversion, final Symbol iterator) {
super(forNode, test, body, controlFlowEscapes, conversion);
this.init = init;
this.modify = modify;
this.flags = flags;
- // Even if the for node gets cloned in try/finally, the symbol can be shared as only one branch of the finally
- // is executed.
- this.iterator = forNode.iterator;
+ this.iterator = iterator;
}
@Override
public Node ensureUniqueLabels(final LexicalContext lc) {
- return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
@Override
@@ -175,7 +175,7 @@
if (this.init == init) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
/**
@@ -204,10 +204,15 @@
/**
* Assign an iterator symbol to this ForNode. Used for for in and for each constructs
+ * @param lc the current lexical context
* @param iterator the iterator symbol
+ * @return a ForNode with the iterator set
*/
- public void setIterator(final Symbol iterator) {
- this.iterator = iterator;
+ public ForNode setIterator(final LexicalContext lc, final Symbol iterator) {
+ if (this.iterator == iterator) {
+ return this;
+ }
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
/**
@@ -228,7 +233,7 @@
if (this.modify == modify) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
@Override
@@ -236,7 +241,7 @@
if (this.test == test) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
@Override
@@ -249,7 +254,7 @@
if (this.body == body) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
@Override
@@ -257,12 +262,12 @@
if (this.controlFlowEscapes == controlFlowEscapes) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
@Override
JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
- return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
@Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Tue Sep 08 14:40:44 2015 -0700
@@ -264,6 +264,11 @@
*/
public static final int NEEDS_CALLEE = 1 << 26;
+ /**
+ * Is the function node cached?
+ */
+ public static final int IS_CACHED = 1 << 27;
+
/** extension callsite flags mask */
public static final int EXTENSION_CALLSITE_FLAGS = IS_PRINT_PARSE |
IS_PRINT_LOWER_PARSE | IS_PRINT_AST | IS_PRINT_LOWER_AST |
@@ -353,7 +358,7 @@
final List<IdentNode> parameters,
final int thisProperties,
final Class<?> rootClass,
- final Source source, Namespace namespace) {
+ final Source source, final Namespace namespace) {
super(functionNode);
this.endParserState = endParserState;
@@ -757,7 +762,7 @@
*/
public boolean needsCallee() {
// NOTE: we only need isSplit() here to ensure that :scope can never drop below slot 2 for splitting array units.
- return needsParentScope() || usesSelfSymbol() || isSplit() || (needsArguments() && !isStrict()) || hasOptimisticApplyToCall();
+ return needsParentScope() || usesSelfSymbol() || isSplit() || (needsArguments() && !isStrict()) || hasApplyToCallSpecialization();
}
/**
@@ -774,7 +779,7 @@
* Return true if function contains an apply to call transform
* @return true if this function has transformed apply to call
*/
- public boolean hasOptimisticApplyToCall() {
+ public boolean hasApplyToCallSpecialization() {
return getFlag(HAS_APPLY_TO_CALL_SPECIALIZATION);
}
@@ -1026,6 +1031,14 @@
}
/**
+ * Return the number of parameters to this function
+ * @return the number of parameters
+ */
+ public int getNumOfParams() {
+ return parameters.size();
+ }
+
+ /**
* Returns the identifier for a named parameter at the specified position in this function's parameter list.
* @param index the parameter's position.
* @return the identifier for the requested named parameter.
@@ -1162,6 +1175,24 @@
}
/**
+ * Returns true if this function node has been cached.
+ * @return true if this function node has been cached.
+ */
+ public boolean isCached() {
+ return getFlag(IS_CACHED);
+ }
+
+ /**
+ * Mark this function node as having been cached.
+ * @param lc the current lexical context
+ * @return a function node equivalent to this one, with the flag set.
+ */
+ public FunctionNode setCached(final LexicalContext lc) {
+ return setFlag(lc, IS_CACHED);
+ }
+
+
+ /**
* Get the compile unit used to compile this function
* @see Compiler
* @return the compile unit
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SwitchNode.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SwitchNode.java Tue Sep 08 14:40:44 2015 -0700
@@ -53,7 +53,7 @@
private final boolean uniqueInteger;
/** Tag symbol. */
- private Symbol tag;
+ private final Symbol tag;
/**
* Constructor
@@ -71,15 +71,16 @@
this.cases = cases;
this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase);
this.uniqueInteger = false;
+ this.tag = null;
}
private SwitchNode(final SwitchNode switchNode, final Expression expression, final List<CaseNode> cases,
- final int defaultCaseIndex, final LocalVariableConversion conversion, final boolean uniqueInteger) {
+ final int defaultCaseIndex, final LocalVariableConversion conversion, final boolean uniqueInteger, final Symbol tag) {
super(switchNode, conversion);
this.expression = expression;
this.cases = cases;
this.defaultCaseIndex = defaultCaseIndex;
- this.tag = switchNode.getTag(); //TODO are symbols inherited as references?
+ this.tag = tag;
this.uniqueInteger = uniqueInteger;
}
@@ -89,7 +90,7 @@
for (final CaseNode caseNode : cases) {
newCases.add(new CaseNode(caseNode, caseNode.getTest(), caseNode.getBody(), caseNode.getLocalVariableConversion()));
}
- return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex, conversion, uniqueInteger));
+ return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex, conversion, uniqueInteger, tag));
}
@Override
@@ -157,7 +158,7 @@
if (this.cases == cases) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
+ return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger, tag));
}
/**
@@ -189,7 +190,7 @@
if (this.expression == expression) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
+ return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger, tag));
}
/**
@@ -204,10 +205,15 @@
/**
* Set the tag symbol for this switch. The tag symbol is where
* the switch expression result is stored
+ * @param lc lexical context
* @param tag a symbol
+ * @return a switch node with the symbol set
*/
- public void setTag(final Symbol tag) {
- this.tag = tag;
+ public SwitchNode setTag(final LexicalContext lc, final Symbol tag) {
+ if (this.tag == tag) {
+ return this;
+ }
+ return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger, tag));
}
/**
@@ -229,12 +235,12 @@
if(this.uniqueInteger == uniqueInteger) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
+ return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger, tag));
}
@Override
JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
- return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
+ return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger, tag));
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java Tue Sep 08 14:40:44 2015 -0700
@@ -25,7 +25,10 @@
package jdk.nashorn.internal.ir;
+import java.io.IOException;
+import java.io.ObjectInputStream;
import java.io.PrintWriter;
+import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
@@ -47,7 +50,9 @@
* refer to their location.
*/
-public final class Symbol implements Comparable<Symbol> {
+public final class Symbol implements Comparable<Symbol>, Cloneable, Serializable {
+ private static final long serialVersionUID = 1L;
+
/** Is this Global */
public static final int IS_GLOBAL = 1;
/** Is this a variable */
@@ -94,10 +99,10 @@
/** First bytecode method local variable slot for storing the value(s) of this variable. -1 indicates the variable
* is not stored in local variable slots or it is not yet known. */
- private int firstSlot = -1;
+ private transient int firstSlot = -1;
/** Field number in scope or property; array index in varargs when not using arguments object. */
- private int fieldIndex = -1;
+ private transient int fieldIndex = -1;
/** Number of times this symbol is used in code */
private int useCount;
@@ -144,6 +149,15 @@
}
}
+ @Override
+ public Symbol clone() {
+ try {
+ return (Symbol)super.clone();
+ } catch (final CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+ }
+
private static String align(final String string, final int max) {
final StringBuilder sb = new StringBuilder();
sb.append(string.substring(0, Math.min(string.length(), max)));
@@ -337,7 +351,7 @@
* Flag this symbol as scope as described in {@link Symbol#isScope()}
* @return the symbol
*/
- public Symbol setIsScope() {
+ public Symbol setIsScope() {
if (!isScope()) {
if(shouldTrace()) {
trace("SET IS SCOPE");
@@ -609,11 +623,11 @@
/**
* Increase the symbol's use count by one.
- * @return the symbol
*/
- public Symbol increaseUseCount() {
- useCount++;
- return this;
+ public void increaseUseCount() {
+ if (isScope()) { // Avoid dirtying a cache line; we only need the use count for scoped symbols
+ useCount++;
+ }
}
/**
@@ -669,4 +683,10 @@
new Throwable().printStackTrace(Context.getCurrentErr());
}
}
+
+ private void readObject(final ObjectInputStream in) throws ClassNotFoundException, IOException {
+ in.defaultReadObject();
+ firstSlot = -1;
+ fieldIndex = -1;
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java Tue Sep 08 14:40:44 2015 -0700
@@ -65,7 +65,7 @@
private final List<Block> inlinedFinallies;
/** Exception symbol. */
- private Symbol exception;
+ private final Symbol exception;
private final LocalVariableConversion conversion;
@@ -86,22 +86,23 @@
this.finallyBody = finallyBody;
this.conversion = null;
this.inlinedFinallies = Collections.emptyList();
+ this.exception = null;
}
- private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody, final LocalVariableConversion conversion, final List<Block> inlinedFinallies) {
+ private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody, final LocalVariableConversion conversion, final List<Block> inlinedFinallies, final Symbol exception) {
super(tryNode);
this.body = body;
this.catchBlocks = catchBlocks;
this.finallyBody = finallyBody;
this.conversion = conversion;
this.inlinedFinallies = inlinedFinallies;
- this.exception = tryNode.exception;
+ this.exception = exception;
}
@Override
public Node ensureUniqueLabels(final LexicalContext lc) {
//try nodes are never in lex context
- return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies);
+ return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception);
}
@Override
@@ -160,7 +161,7 @@
if (this.body == body) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
+ return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception));
}
/**
@@ -197,7 +198,7 @@
if (this.catchBlocks == catchBlocks) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
+ return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception));
}
/**
@@ -209,12 +210,15 @@
}
/**
* Set the exception symbol for this try block
+ * @param lc lexical context
* @param exception a symbol for the compiler to store the exception in
* @return new TryNode or same if unchanged
*/
- public TryNode setException(final Symbol exception) {
- this.exception = exception;
- return this;
+ public TryNode setException(final LexicalContext lc, final Symbol exception) {
+ if (this.exception == exception) {
+ return this;
+ }
+ return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception));
}
/**
@@ -277,7 +281,7 @@
if (this.finallyBody == finallyBody) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
+ return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception));
}
/**
@@ -293,7 +297,7 @@
return this;
}
assert checkInlinedFinallies(inlinedFinallies);
- return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
+ return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception));
}
private static boolean checkInlinedFinallies(final List<Block> inlinedFinallies) {
@@ -314,7 +318,7 @@
if(this.conversion == conversion) {
return this;
}
- return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies);
+ return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception);
}
@Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Tue Sep 08 14:40:44 2015 -0700
@@ -2419,7 +2419,7 @@
}
private void initScripting(final ScriptEnvironment scriptEnv) {
- Object value;
+ ScriptObject value;
value = ScriptFunctionImpl.makeFunction("readLine", ScriptingFunctions.READLINE);
addOwnProperty("readLine", Attribute.NOT_ENUMERABLE, value);
@@ -2428,11 +2428,13 @@
final String execName = ScriptingFunctions.EXEC_NAME;
value = ScriptFunctionImpl.makeFunction(execName, ScriptingFunctions.EXEC);
+ value.addOwnProperty(ScriptingFunctions.THROW_ON_ERROR_NAME, Attribute.NOT_ENUMERABLE, false);
+
addOwnProperty(execName, Attribute.NOT_ENUMERABLE, value);
// Nashorn extension: global.echo (scripting-mode-only)
// alias for "print"
- value = get("print");
+ value = (ScriptObject)get("print");
addOwnProperty("echo", Attribute.NOT_ENUMERABLE, value);
// Nashorn extension: global.$OPTIONS (scripting-mode-only)
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java Tue Sep 08 14:40:44 2015 -0700
@@ -26,6 +26,7 @@
package jdk.nashorn.internal.parser;
import static jdk.nashorn.internal.parser.TokenType.ADD;
+import static jdk.nashorn.internal.parser.TokenType.BINARY_NUMBER;
import static jdk.nashorn.internal.parser.TokenType.COMMENT;
import static jdk.nashorn.internal.parser.TokenType.DECIMAL;
import static jdk.nashorn.internal.parser.TokenType.DIRECTIVE_COMMENT;
@@ -40,6 +41,7 @@
import static jdk.nashorn.internal.parser.TokenType.LBRACE;
import static jdk.nashorn.internal.parser.TokenType.LPAREN;
import static jdk.nashorn.internal.parser.TokenType.OCTAL;
+import static jdk.nashorn.internal.parser.TokenType.OCTAL_LEGACY;
import static jdk.nashorn.internal.parser.TokenType.RBRACE;
import static jdk.nashorn.internal.parser.TokenType.REGEX;
import static jdk.nashorn.internal.parser.TokenType.RPAREN;
@@ -47,6 +49,7 @@
import static jdk.nashorn.internal.parser.TokenType.XML;
import java.io.Serializable;
+
import jdk.nashorn.internal.runtime.ECMAErrors;
import jdk.nashorn.internal.runtime.ErrorManager;
import jdk.nashorn.internal.runtime.JSErrorType;
@@ -75,6 +78,9 @@
/** True if here and edit strings are supported. */
private final boolean scripting;
+ /** True if parsing in ECMAScript 6 mode. */
+ private final boolean es6;
+
/** True if a nested scan. (scan to completion, no EOF.) */
private final boolean nested;
@@ -173,7 +179,7 @@
* @param stream the token stream to lex
*/
public Lexer(final Source source, final TokenStream stream) {
- this(source, stream, false);
+ this(source, stream, false, false);
}
/**
@@ -182,9 +188,10 @@
* @param source the source
* @param stream the token stream to lex
* @param scripting are we in scripting mode
+ * @param es6 are we in ECMAScript 6 mode
*/
- public Lexer(final Source source, final TokenStream stream, final boolean scripting) {
- this(source, 0, source.getLength(), stream, scripting, false);
+ public Lexer(final Source source, final TokenStream stream, final boolean scripting, final boolean es6) {
+ this(source, 0, source.getLength(), stream, scripting, es6, false);
}
/**
@@ -195,16 +202,18 @@
* @param len length of source segment to lex
* @param stream token stream to lex
* @param scripting are we in scripting mode
+ * @param es6 are we in ECMAScript 6 mode
* @param pauseOnFunctionBody if true, lexer will return from {@link #lexify()} when it encounters a
* function body. This is used with the feature where the parser is skipping nested function bodies to
* avoid reading ahead unnecessarily when we skip the function bodies.
*/
- public Lexer(final Source source, final int start, final int len, final TokenStream stream, final boolean scripting, final boolean pauseOnFunctionBody) {
+ public Lexer(final Source source, final int start, final int len, final TokenStream stream, final boolean scripting, final boolean es6, final boolean pauseOnFunctionBody) {
super(source.getContent(), 1, start, len);
this.source = source;
this.stream = stream;
this.scripting = scripting;
+ this.es6 = es6;
this.nested = false;
this.pendingLine = 1;
this.last = EOL;
@@ -218,6 +227,7 @@
source = lexer.source;
stream = lexer.stream;
scripting = lexer.scripting;
+ es6 = lexer.es6;
nested = true;
pendingLine = state.pendingLine;
@@ -1088,6 +1098,24 @@
}
type = HEXADECIMAL;
+ } else if (digit == 0 && es6 && (ch1 == 'o' || ch1 == 'O') && convertDigit(ch2, 8) != -1) {
+ // Skip over 0oN.
+ skip(3);
+ // Skip over remaining digits.
+ while (convertDigit(ch0, 8) != -1) {
+ skip(1);
+ }
+
+ type = OCTAL;
+ } else if (digit == 0 && es6 && (ch1 == 'b' || ch1 == 'B') && convertDigit(ch2, 2) != -1) {
+ // Skip over 0bN.
+ skip(3);
+ // Skip over remaining digits.
+ while (convertDigit(ch0, 2) != -1) {
+ skip(1);
+ }
+
+ type = BINARY_NUMBER;
} else {
// Check for possible octal constant.
boolean octal = digit == 0;
@@ -1105,7 +1133,7 @@
}
if (octal && position - start > 1) {
- type = OCTAL;
+ type = OCTAL_LEGACY;
} else if (ch0 == '.' || ch0 == 'E' || ch0 == 'e') {
// Must be a double.
if (ch0 == '.') {
@@ -1637,10 +1665,14 @@
switch (Token.descType(token)) {
case DECIMAL:
return Lexer.valueOf(source.getString(start, len), 10); // number
- case OCTAL:
- return Lexer.valueOf(source.getString(start, len), 8); // number
case HEXADECIMAL:
return Lexer.valueOf(source.getString(start + 2, len - 2), 16); // number
+ case OCTAL_LEGACY:
+ return Lexer.valueOf(source.getString(start, len), 8); // number
+ case OCTAL:
+ return Lexer.valueOf(source.getString(start + 2, len - 2), 8); // number
+ case BINARY_NUMBER:
+ return Lexer.valueOf(source.getString(start + 2, len - 2), 2); // number
case FLOATING:
final String str = source.getString(start, len);
final double value = Double.valueOf(str);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Tue Sep 08 14:40:44 2015 -0700
@@ -273,7 +273,7 @@
try {
stream = new TokenStream();
- lexer = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, reparsedFunction != null);
+ lexer = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, env._es6, reparsedFunction != null);
lexer.line = lexer.pendingLine = lineOffset + 1;
line = lineOffset;
@@ -309,7 +309,7 @@
public List<IdentNode> parseFormalParameterList() {
try {
stream = new TokenStream();
- lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions);
+ lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6);
// Set up first token (skips opening EOL.)
k = -1;
@@ -333,7 +333,7 @@
public FunctionNode parseFunctionBody() {
try {
stream = new TokenStream();
- lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions);
+ lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6);
final int functionLine = line;
// Set up first token (skips opening EOL.)
@@ -716,7 +716,7 @@
restoreBlock(body);
body.setFlag(Block.NEEDS_SCOPE);
- final Block programBody = new Block(functionToken, functionLine, body.getFlags() | Block.IS_SYNTHETIC, body.getStatements());
+ final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC, body.getStatements());
lc.pop(script);
script.setLastToken(token);
@@ -1216,11 +1216,10 @@
final long forToken = token;
final int forLine = line;
// start position of this for statement. This is used
- // for sort order for variables declared in the initialzer
+ // for sort order for variables declared in the initializer
// part of this 'for' statement (if any).
final int forStart = Token.descPosition(forToken);
// When ES6 for-let is enabled we create a container block to capture the LET.
- final int startLine = start;
final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null;
// Create FOR node, capturing FOR token.
@@ -1341,22 +1340,24 @@
body = getStatement();
} finally {
lc.pop(forNode);
- }
-
- if (vars != null) {
- for (final VarNode var : vars) {
- appendStatement(var);
+
+ if (vars != null) {
+ for (final VarNode var : vars) {
+ appendStatement(var);
+ }
+ }
+ if (body != null) {
+ appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify));
}
- }
- if (body != null) {
- appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify));
- }
- if (outer != null) {
- restoreBlock(outer);
- appendStatement(new BlockStatement(startLine, new Block(
- outer.getToken(),
- body.getFinish(),
- outer.getStatements())));
+ if (outer != null) {
+ restoreBlock(outer);
+ if (body != null) {
+ appendStatement(new BlockStatement(forLine, new Block(
+ outer.getToken(),
+ body.getFinish(),
+ outer.getStatements())));
+ }
+ }
}
}
@@ -1954,7 +1955,7 @@
}
detectSpecialProperty(ident);
return ident;
- case OCTAL:
+ case OCTAL_LEGACY:
if (isStrictMode) {
throw error(AbstractParser.message("strict.no.octal"), token);
}
@@ -1962,6 +1963,8 @@
case ESCSTRING:
case DECIMAL:
case HEXADECIMAL:
+ case OCTAL:
+ case BINARY_NUMBER:
case FLOATING:
case REGEX:
case XML:
@@ -2053,13 +2056,13 @@
// LBRACKET tested in caller.
next();
- // Prepare to accummulating elements.
+ // Prepare to accumulate elements.
final List<Expression> elements = new ArrayList<>();
// Track elisions.
boolean elision = true;
loop:
while (true) {
- switch (type) {
+ switch (type) {
case RBRACKET:
next();
@@ -2223,7 +2226,7 @@
switch (type) {
case IDENT:
return getIdent().setIsPropertyName();
- case OCTAL:
+ case OCTAL_LEGACY:
if (isStrictMode) {
throw error(AbstractParser.message("strict.no.octal"), token);
}
@@ -2231,6 +2234,8 @@
case ESCSTRING:
case DECIMAL:
case HEXADECIMAL:
+ case OCTAL:
+ case BINARY_NUMBER:
case FLOATING:
return getLiteral();
default:
@@ -2284,7 +2289,7 @@
}
}
- propertyName = createIdentNode(propertyToken, finish, ident).setIsPropertyName();
+ propertyName = createIdentNode(propertyToken, finish, ident).setIsPropertyName();
} else {
propertyName = propertyName();
}
@@ -2553,7 +2558,7 @@
final long callToken = token;
switch (type) {
- case LBRACKET:
+ case LBRACKET: {
next();
// Get array index.
@@ -2565,8 +2570,8 @@
lhs = new IndexNode(callToken, finish, lhs, index);
break;
-
- case PERIOD:
+ }
+ case PERIOD: {
if (lhs == null) {
throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
}
@@ -2579,7 +2584,7 @@
lhs = new AccessNode(callToken, finish, lhs, property.getName());
break;
-
+ }
default:
break loop;
}
@@ -3034,7 +3039,7 @@
assert parserState != null;
stream.reset();
- lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions);
+ lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions, env._es6);
line = parserState.line;
linePosition = parserState.linePosition;
// Doesn't really matter, but it's safe to treat it as if there were a semicolon before
@@ -3063,8 +3068,8 @@
this.linePosition = linePosition;
}
- Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting) {
- final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, true);
+ Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting, final boolean es6) {
+ final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, es6, true);
newLexer.restoreState(new Lexer.State(position, Integer.MAX_VALUE, line, -1, linePosition, SEMICOLON));
return newLexer;
}
@@ -3107,15 +3112,6 @@
return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
}
- /*
- * parse LHS [a, b, ..., c].
- *
- * JavaScript 1.8.
- */
- //private Node destructureExpression() {
- // return null;
- //}
-
/**
* PostfixExpression :
* LeftHandSideExpression
@@ -3127,7 +3123,7 @@
* UnaryExpression :
* PostfixExpression
* delete UnaryExpression
- * Node UnaryExpression
+ * void UnaryExpression
* typeof UnaryExpression
* ++ UnaryExpression
* -- UnaryExpression
@@ -3333,7 +3329,6 @@
// This method is protected so that subclass can get details
// at expression start point!
- // TODO - Destructuring array.
// Include commas in expression parsing.
return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false);
}
@@ -3407,7 +3402,6 @@
// This method is protected so that subclass can get details
// at assignment expression start point!
- // TODO - Handle decompose.
// Exclude commas in expression parsing.
return expression(unaryExpression(), ASSIGN.getPrecedence(), noIn);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java Tue Sep 08 14:40:44 2015 -0700
@@ -170,8 +170,10 @@
YIELD (FUTURESTRICT, "yield"),
DECIMAL (LITERAL, null),
+ HEXADECIMAL (LITERAL, null),
+ OCTAL_LEGACY (LITERAL, null),
OCTAL (LITERAL, null),
- HEXADECIMAL (LITERAL, null),
+ BINARY_NUMBER (LITERAL, null),
FLOATING (LITERAL, null),
STRING (LITERAL, null),
ESCSTRING (LITERAL, null),
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AstSerializer.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * 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.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.runtime.options.Options;
+
+/**
+ * This static utility class performs serialization of FunctionNode ASTs to a byte array.
+ * The format is a standard Java serialization stream, deflated.
+ */
+final class AstSerializer {
+ // Experimentally, we concluded that compression level 4 gives a good tradeoff between serialization speed
+ // and size.
+ private static final int COMPRESSION_LEVEL = Options.getIntProperty("nashorn.serialize.compression", 4);
+ static byte[] serialize(final FunctionNode fn) {
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ final Deflater deflater = new Deflater(COMPRESSION_LEVEL);
+ try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out, deflater))) {
+ oout.writeObject(fn);
+ } catch (final IOException e) {
+ throw new AssertionError("Unexpected exception serializing function", e);
+ } finally {
+ deflater.end();
+ }
+ return out.toByteArray();
+ }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java Tue Sep 08 14:40:44 2015 -0700
@@ -27,6 +27,7 @@
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
+
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -820,7 +821,7 @@
// isn't available, we'll use the old one bound into the call site.
final OptimismInfo effectiveOptInfo = currentOptInfo != null ? currentOptInfo : oldOptInfo;
FunctionNode fn = effectiveOptInfo.reparse();
- final boolean serialized = effectiveOptInfo.isSerialized();
+ final boolean cached = fn.isCached();
final Compiler compiler = effectiveOptInfo.getCompiler(fn, ct, re); //set to non rest-of
if (!shouldRecompile) {
@@ -828,11 +829,11 @@
// recompiled a deoptimized version for an inner invocation.
// We still need to do the rest of from the beginning
logRecompile("Rest-of compilation [STANDALONE] ", fn, ct, effectiveOptInfo.invalidatedProgramPoints);
- return restOfHandle(effectiveOptInfo, compiler.compile(fn, serialized ? CompilationPhases.COMPILE_SERIALIZED_RESTOF : CompilationPhases.COMPILE_ALL_RESTOF), currentOptInfo != null);
+ return restOfHandle(effectiveOptInfo, compiler.compile(fn, cached ? CompilationPhases.COMPILE_CACHED_RESTOF : CompilationPhases.COMPILE_ALL_RESTOF), currentOptInfo != null);
}
logRecompile("Deoptimizing recompilation (up to bytecode) ", fn, ct, effectiveOptInfo.invalidatedProgramPoints);
- fn = compiler.compile(fn, serialized ? CompilationPhases.RECOMPILE_SERIALIZED_UPTO_BYTECODE : CompilationPhases.COMPILE_UPTO_BYTECODE);
+ fn = compiler.compile(fn, cached ? CompilationPhases.RECOMPILE_CACHED_UPTO_BYTECODE : CompilationPhases.COMPILE_UPTO_BYTECODE);
log.fine("Reusable IR generated");
// compile the rest of the function, and install it
@@ -956,10 +957,6 @@
FunctionNode reparse() {
return data.reparse();
}
-
- boolean isSerialized() {
- return data.isSerialized();
- }
}
@SuppressWarnings("unused")
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Tue Sep 08 14:40:44 2015 -0700
@@ -26,16 +26,24 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
+
import java.io.IOException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
+import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import jdk.internal.dynalink.support.NameCodec;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
@@ -45,8 +53,15 @@
import jdk.nashorn.internal.codegen.OptimisticTypesPersistence;
import jdk.nashorn.internal.codegen.TypeMap;
import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.SwitchNode;
+import jdk.nashorn.internal.ir.Symbol;
+import jdk.nashorn.internal.ir.TryNode;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.parser.Parser;
@@ -55,6 +70,7 @@
import jdk.nashorn.internal.runtime.logging.DebugLogger;
import jdk.nashorn.internal.runtime.logging.Loggable;
import jdk.nashorn.internal.runtime.logging.Logger;
+import jdk.nashorn.internal.runtime.options.Options;
/**
* This is a subclass that represents a script function that may be regenerated,
* for example with specialization based on call site types, or lazily generated.
@@ -66,6 +82,8 @@
/** Prefix used for all recompiled script classes */
public static final String RECOMPILATION_PREFIX = "Recompilation$";
+ private static final ExecutorService astSerializerExecutorService = createAstSerializerExecutorService();
+
/** Unique function node id for this function node */
private final int functionNodeId;
@@ -77,8 +95,12 @@
/** Source from which FunctionNode was parsed. */
private transient Source source;
- /** Serialized, compressed form of the AST. Used by split functions as they can't be reparsed from source. */
- private final byte[] serializedAst;
+ /**
+ * Cached form of the AST. Either a {@code SerializedAst} object used by split functions as they can't be
+ * reparsed from source, or a soft reference to a {@code FunctionNode} for other functions (it is safe
+ * to be cleared as they can be reparsed).
+ */
+ private volatile Object cachedAst;
/** Token of this function within the source. */
private final long token;
@@ -128,7 +150,6 @@
* @param nestedFunctions nested function map
* @param externalScopeDepths external scope depths
* @param internalSymbols internal symbols to method, defined in its scope
- * @param serializedAst a serialized AST representation. Normally only used for split functions.
*/
public RecompilableScriptFunctionData(
final FunctionNode functionNode,
@@ -136,8 +157,7 @@
final AllocationStrategy allocationStrategy,
final Map<Integer, RecompilableScriptFunctionData> nestedFunctions,
final Map<String, Integer> externalScopeDepths,
- final Set<String> internalSymbols,
- final byte[] serializedAst) {
+ final Set<String> internalSymbols) {
super(functionName(functionNode),
Math.min(functionNode.getParameters().size(), MAX_ARITY),
@@ -161,7 +181,6 @@
nfn.setParent(this);
}
- this.serializedAst = serializedAst;
createLogger();
}
@@ -244,7 +263,7 @@
* @return parent data, or null if non exists and also null IF UNKNOWN.
*/
public RecompilableScriptFunctionData getParent() {
- return parent;
+ return parent;
}
void setParent(final RecompilableScriptFunctionData parent) {
@@ -358,13 +377,11 @@
return allocationStrategy.allocate(map);
}
- boolean isSerialized() {
- return serializedAst != null;
- }
-
FunctionNode reparse() {
- if (isSerialized()) {
- return deserialize();
+ final FunctionNode cachedFunction = getCachedAst();
+ if (cachedFunction != null) {
+ assert cachedFunction.isCached();
+ return cachedFunction;
}
final int descPosition = Token.descPosition(token);
@@ -391,7 +408,98 @@
return (isProgram() ? program : extractFunctionFromScript(program)).setName(null, functionName);
}
- private FunctionNode deserialize() {
+ private FunctionNode getCachedAst() {
+ final Object lCachedAst = cachedAst;
+ // Are we softly caching the AST?
+ if (lCachedAst instanceof Reference<?>) {
+ final FunctionNode fn = (FunctionNode)((Reference<?>)lCachedAst).get();
+ if (fn != null) {
+ // Yes we are - this is fast
+ return cloneSymbols(fn);
+ }
+ // Are we strongly caching a serialized AST (for split functions only)?
+ } else if (lCachedAst instanceof SerializedAst) {
+ final SerializedAst serializedAst = (SerializedAst)lCachedAst;
+ // Even so, are we also softly caching the AST?
+ final FunctionNode cachedFn = serializedAst.cachedAst.get();
+ if (cachedFn != null) {
+ // Yes we are - this is fast
+ return cloneSymbols(cachedFn);
+ }
+ final FunctionNode deserializedFn = deserialize(serializedAst.serializedAst);
+ // Softly cache after deserialization, maybe next time we won't need to deserialize
+ serializedAst.cachedAst = new SoftReference<>(deserializedFn);
+ return deserializedFn;
+ }
+ // No cached representation; return null for reparsing
+ return null;
+ }
+
+ /**
+ * Sets the AST to cache in this function
+ * @param astToCache the new AST to cache
+ */
+ public void setCachedAst(final FunctionNode astToCache) {
+ assert astToCache.getId() == functionNodeId; // same function
+ assert !(cachedAst instanceof SerializedAst); // Can't overwrite serialized AST
+
+ final boolean isSplit = astToCache.isSplit();
+ // If we're caching a split function, we're doing it in the eager pass, hence there can be no other
+ // cached representation already. In other words, isSplit implies cachedAst == null.
+ assert !isSplit || cachedAst == null; //
+
+ final FunctionNode symbolClonedAst = cloneSymbols(astToCache);
+ final Reference<FunctionNode> ref = new SoftReference<>(symbolClonedAst);
+ cachedAst = ref;
+
+ // Asynchronously serialize split functions.
+ if (isSplit) {
+ astSerializerExecutorService.execute(() -> {
+ cachedAst = new SerializedAst(symbolClonedAst, ref);
+ });
+ }
+ }
+
+ /**
+ * Creates the AST serializer executor service used for in-memory serialization of split functions' ASTs.
+ * It is created with an unbounded queue (so it can queue any number of pending tasks). Its core and max
+ * threads is the same, but they are all allowed to time out so when there's no work, they can all go
+ * away. The threads will be daemons, and they will time out if idle for a minute. Their priority is also
+ * slightly lower than normal priority as we'd prefer the CPU to keep running the program; serializing
+ * split function is a memory conservation measure (it allows us to release the AST), it can wait a bit.
+ * @return an executor service with above described characteristics.
+ */
+ private static ExecutorService createAstSerializerExecutorService() {
+ final int threads = Math.max(1, Options.getIntProperty("nashorn.serialize.threads", Runtime.getRuntime().availableProcessors() / 2));
+ final ThreadPoolExecutor service = new ThreadPoolExecutor(threads, threads, 1, TimeUnit.MINUTES, new LinkedBlockingDeque<>(),
+ (r) -> {
+ final Thread t = new Thread(r, "Nashorn AST Serializer");
+ t.setDaemon(true);
+ t.setPriority(Thread.NORM_PRIORITY - 1);
+ return t;
+ });
+ service.allowCoreThreadTimeOut(true);
+ return service;
+ }
+
+ /**
+ * A tuple of a serialized AST and a soft reference to a deserialized AST. This is used to cache split
+ * functions. Since split functions are altered from their source form, they can't be reparsed from
+ * source. While we could just use the {@code byte[]} representation in {@link RecompilableScriptFunctionData#cachedAst}
+ * we're using this tuple instead to also keep a deserialized AST around in memory to cut down on
+ * deserialization costs.
+ */
+ private static class SerializedAst {
+ private final byte[] serializedAst;
+ private volatile Reference<FunctionNode> cachedAst;
+
+ SerializedAst(final FunctionNode fn, final Reference<FunctionNode> cachedAst) {
+ this.serializedAst = AstSerializer.serialize(fn);
+ this.cachedAst = cachedAst;
+ }
+ }
+
+ private FunctionNode deserialize(final byte[] serializedAst) {
final ScriptEnvironment env = installer.getOwner();
final Timing timing = env._timing;
final long t1 = System.nanoTime();
@@ -402,6 +510,107 @@
}
}
+ private FunctionNode cloneSymbols(final FunctionNode fn) {
+ final IdentityHashMap<Symbol, Symbol> symbolReplacements = new IdentityHashMap<>();
+ final boolean cached = fn.isCached();
+ // blockDefinedSymbols is used to re-mark symbols defined outside the function as global. We only
+ // need to do this when we cache an eagerly parsed function (which currently means a split one, as we
+ // don't cache non-split functions from the eager pass); those already cached, or those not split
+ // don't need this step.
+ final Set<Symbol> blockDefinedSymbols = fn.isSplit() && !cached ? Collections.newSetFromMap(new IdentityHashMap<>()) : null;
+ FunctionNode newFn = (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+
+ private Symbol getReplacement(final Symbol original) {
+ if (original == null) {
+ return null;
+ }
+ final Symbol existingReplacement = symbolReplacements.get(original);
+ if (existingReplacement != null) {
+ return existingReplacement;
+ }
+ final Symbol newReplacement = original.clone();
+ symbolReplacements.put(original, newReplacement);
+ return newReplacement;
+ }
+
+ @Override
+ public Node leaveIdentNode(final IdentNode identNode) {
+ final Symbol oldSymbol = identNode.getSymbol();
+ if (oldSymbol != null) {
+ final Symbol replacement = getReplacement(oldSymbol);
+ return identNode.setSymbol(replacement);
+ }
+ return identNode;
+ }
+
+ @Override
+ public Node leaveForNode(final ForNode forNode) {
+ return ensureUniqueLabels(forNode.setIterator(lc, getReplacement(forNode.getIterator())));
+ }
+
+ @Override
+ public Node leaveSwitchNode(final SwitchNode switchNode) {
+ return ensureUniqueLabels(switchNode.setTag(lc, getReplacement(switchNode.getTag())));
+ }
+
+ @Override
+ public Node leaveTryNode(final TryNode tryNode) {
+ return ensureUniqueLabels(tryNode.setException(lc, getReplacement(tryNode.getException())));
+ }
+
+ @Override
+ public boolean enterBlock(final Block block) {
+ for(final Symbol symbol: block.getSymbols()) {
+ final Symbol replacement = getReplacement(symbol);
+ if (blockDefinedSymbols != null) {
+ blockDefinedSymbols.add(replacement);
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public Node leaveBlock(final Block block) {
+ return ensureUniqueLabels(block.replaceSymbols(lc, symbolReplacements));
+ }
+
+ @Override
+ public Node leaveFunctionNode(final FunctionNode functionNode) {
+ return functionNode.setParameters(lc, functionNode.visitParameters(this));
+ }
+
+ @Override
+ protected Node leaveDefault(final Node node) {
+ return ensureUniqueLabels(node);
+ };
+
+ private Node ensureUniqueLabels(final Node node) {
+ // If we're returning a cached AST, we must also ensure unique labels
+ return cached ? node.ensureUniqueLabels(lc) : node;
+ }
+ });
+
+ if (blockDefinedSymbols != null) {
+ // Mark all symbols not defined in blocks as globals
+ Block newBody = null;
+ for(final Symbol symbol: symbolReplacements.values()) {
+ if(!blockDefinedSymbols.contains(symbol)) {
+ assert symbol.isScope(); // must be scope
+ assert externalScopeDepths.containsKey(symbol.getName()); // must be known to us as an external
+ // Register it in the function body symbol table as a new global symbol
+ symbol.setFlags((symbol.getFlags() & ~Symbol.KINDMASK) | Symbol.IS_GLOBAL);
+ if (newBody == null) {
+ newBody = newFn.getBody().copyWithNewSymbols();
+ newFn = newFn.setBody(null, newBody);
+ }
+ assert newBody.getExistingSymbol(symbol.getName()) == null; // must not be defined in the body already
+ newBody.putSymbol(symbol);
+ }
+ }
+ }
+ return newFn.setCached(null);
+ }
+
private boolean getFunctionFlag(final int flag) {
return (functionFlags & flag) != 0;
}
@@ -512,9 +721,9 @@
final FunctionNode fn = reparse();
final Compiler compiler = getCompiler(fn, actualCallSiteType, runtimeScope);
final FunctionNode compiledFn = compiler.compile(fn,
- isSerialized() ? CompilationPhases.COMPILE_ALL_SERIALIZED : CompilationPhases.COMPILE_ALL);
+ fn.isCached() ? CompilationPhases.COMPILE_ALL_CACHED : CompilationPhases.COMPILE_ALL);
- if (persist && !compiledFn.getFlag(FunctionNode.HAS_APPLY_TO_CALL_SPECIALIZATION)) {
+ if (persist && !compiledFn.hasApplyToCallSpecialization()) {
compiler.persistClassInfo(cacheKey, compiledFn);
}
return new FunctionInitializer(compiledFn, compiler.getInvalidatedProgramPoints());
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java Tue Sep 08 14:40:44 2015 -0700
@@ -26,6 +26,7 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
+import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
@@ -70,6 +71,9 @@
/** EXIT name - special property used by $EXEC API. */
public static final String EXIT_NAME = "$EXIT";
+ /** THROW_ON_ERROR name - special property of the $EXEC function used by $EXEC API. */
+ public static final String THROW_ON_ERROR_NAME = "throwOnError";
+
/** Names of special properties used by $ENV API. */
public static final String ENV_NAME = "$ENV";
@@ -247,6 +251,19 @@
}
}
+ // if we got a non-zero exit code ("failure"), then we have to decide to throw error or not
+ if (exit != 0) {
+ // get the $EXEC function object from the global object
+ final Object exec = global.get(EXEC_NAME);
+ assert exec instanceof ScriptObject : EXEC_NAME + " is not a script object!";
+
+ // Check if the user has set $EXEC.throwOnError property to true. If so, throw RangeError
+ // If that property is not set or set to false, then silently proceed with the rest.
+ if (JSType.toBoolean(((ScriptObject)exec).get(THROW_ON_ERROR_NAME))) {
+ throw rangeError("exec.returned.non.zero", ScriptRuntime.safeToString(exit));
+ }
+ }
+
// Return the result from stdout.
return out;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/InvalidArrayIndexException.java Tue Sep 08 16:01:29 2015 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +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.runtime.arrays;
-
-/**
- * Mechanism for communicating that something isn't a plain
- * numeric integer array index. This enables things like
- * array getters for the fast case in a try, basically
- * just consisting of an "array[index]" access without
- * any checks of boundary conditions that rarely happen
- */
-@SuppressWarnings("serial")
-class InvalidArrayIndexException extends Exception {
-
- private final Object index;
-
- InvalidArrayIndexException(final Object index) {
- super(index == null ? "null" : index.toString());
- this.index = index;
- }
-
- InvalidArrayIndexException(final int index) {
- this(Integer.valueOf(index));
- }
-
- InvalidArrayIndexException(final long index) {
- this(Long.valueOf(index));
- }
-
- InvalidArrayIndexException(final double index) {
- this(Double.valueOf(index));
- }
-
- @Override
- public String toString() {
- return index.toString();
- }
-
- Object getIndex() {
- return index;
- }
-
-}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/AdaptationException.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/AdaptationException.java Tue Sep 08 14:40:44 2015 -0700
@@ -30,6 +30,7 @@
private final AdaptationResult adaptationResult;
AdaptationException(final AdaptationResult.Outcome outcome, final String classList) {
+ super(null, null, false, false);
this.adaptationResult = new AdaptationResult(outcome, classList);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java Tue Sep 08 14:40:44 2015 -0700
@@ -189,7 +189,7 @@
* @return true if the obj is an instance of @FunctionalInterface interface
*/
public static boolean isFunctionalInterfaceObject(final Object obj) {
- return !JSType.isPrimitive(obj) && (NashornBeansLinker.getFunctionalInterfaceMethod(obj.getClass()) != null);
+ return !JSType.isPrimitive(obj) && (NashornBeansLinker.getFunctionalInterfaceMethodName(obj.getClass()) != null);
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Tue Sep 08 14:40:44 2015 -0700
@@ -79,10 +79,10 @@
}
// cache of @FunctionalInterface method of implementor classes
- private static final ClassValue<Method> FUNCTIONAL_IFACE_METHOD = new ClassValue<Method>() {
+ private static final ClassValue<String> FUNCTIONAL_IFACE_METHOD_NAME = new ClassValue<String>() {
@Override
- protected Method computeValue(final Class<?> type) {
- return findFunctionalInterfaceMethod(type);
+ protected String computeValue(final Class<?> type) {
+ return findFunctionalInterfaceMethodName(type);
}
};
@@ -107,19 +107,21 @@
// annotated interface. This way Java method, constructor references or
// implementations of java.util.function.* interfaces can be called as though
// those are script functions.
- final Method m = getFunctionalInterfaceMethod(self.getClass());
- if (m != null) {
+ final String name = getFunctionalInterfaceMethodName(self.getClass());
+ if (name != null) {
final MethodType callType = desc.getMethodType();
- // 'callee' and 'thiz' passed from script + actual arguments
- if (callType.parameterCount() != m.getParameterCount() + 2) {
- throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self));
- }
- return new GuardedInvocation(
- // drop 'thiz' passed from the script.
- MH.dropArguments(linkerServices.filterInternalObjects(desc.getLookup().unreflect(m)), 1,
- callType.parameterType(1)), Guards.getInstanceOfGuard(
- m.getDeclaringClass())).asTypeSafeReturn(
- new NashornBeansLinkerServices(linkerServices), callType);
+ // drop callee (Undefined ScriptFunction) and change the request to be dyn:callMethod:<name>
+ final NashornCallSiteDescriptor newDesc = NashornCallSiteDescriptor.get(desc.getLookup(),
+ "dyn:callMethod:" + name, desc.getMethodType().dropParameterTypes(1, 2),
+ NashornCallSiteDescriptor.getFlags(desc));
+ final GuardedInvocation gi = getGuardedInvocation(beansLinker,
+ linkRequest.replaceArguments(newDesc, linkRequest.getArguments()),
+ new NashornBeansLinkerServices(linkerServices));
+
+ // drop 'thiz' passed from the script.
+ return gi.replaceMethods(
+ MH.dropArguments(linkerServices.filterInternalObjects(gi.getInvocation()), 1, callType.parameterType(1)),
+ gi.getGuard());
}
}
return getGuardedInvocation(beansLinker, linkRequest, linkerServices);
@@ -163,7 +165,7 @@
return arg instanceof ConsString ? arg.toString() : arg;
}
- private static Method findFunctionalInterfaceMethod(final Class<?> clazz) {
+ private static String findFunctionalInterfaceMethodName(final Class<?> clazz) {
if (clazz == null) {
return null;
}
@@ -179,20 +181,20 @@
// return the first abstract method
for (final Method m : iface.getMethods()) {
if (Modifier.isAbstract(m.getModifiers())) {
- return m;
+ return m.getName();
}
}
}
}
// did not find here, try super class
- return findFunctionalInterfaceMethod(clazz.getSuperclass());
+ return findFunctionalInterfaceMethodName(clazz.getSuperclass());
}
// Returns @FunctionalInterface annotated interface's single abstract
- // method. If not found, returns null.
- static Method getFunctionalInterfaceMethod(final Class<?> clazz) {
- return FUNCTIONAL_IFACE_METHOD.get(clazz);
+ // method name. If not found, returns null.
+ static String getFunctionalInterfaceMethodName(final Class<?> clazz) {
+ return FUNCTIONAL_IFACE_METHOD_NAME.get(clazz);
}
static MethodHandleTransformer createHiddenObjectFilter() {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/regexp/joni/exception/JOniException.java Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/regexp/joni/exception/JOniException.java Tue Sep 08 14:40:44 2015 -0700
@@ -24,6 +24,6 @@
private static final long serialVersionUID = -6027192180014164667L;
public JOniException(final String message) {
- super(message);
+ super(message, null, false, false);
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Tue Sep 08 14:40:44 2015 -0700
@@ -163,6 +163,7 @@
range.error.invalid.date=Invalid Date
range.error.too.many.errors=Script contains too many errors: {0} errors
range.error.concat.string.too.big=Concatenated String is too big
+range.error.exec.returned.non.zero=$EXEC returned non-zero exit code: {0}
reference.error.not.defined="{0}" is not defined
reference.error.cant.be.used.as.lhs="{0}" can not be used as the left-hand side of assignment
--- a/nashorn/test/script/basic/JDK-8043232.js.EXPECTED Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/test/script/basic/JDK-8043232.js.EXPECTED Tue Sep 08 14:40:44 2015 -0700
@@ -1,14 +1,28 @@
bcd
-[jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)]
+[jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)]
red
TypeError: No such Java class: java.lang.NonExistent
TypeError: No such Java constructor: Object(String)
TypeError: Java constructor signature invalid: Object()xxxxx
TypeError: Java constructor signature invalid: Object(
TypeError: Java constructor signature invalid: Object)
-TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.lang.System.getProperty] cannot be used as a constructor.
-TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println] cannot be used as a constructor.
-TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)] requires "new".
+TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod
+ String java.lang.System.getProperty(String,String)
+ String java.lang.System.getProperty(String)
+] cannot be used as a constructor.
+TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod
+ void java.io.PrintStream.println()
+ void java.io.PrintStream.println(boolean)
+ void java.io.PrintStream.println(char)
+ void java.io.PrintStream.println(char[])
+ void java.io.PrintStream.println(double)
+ void java.io.PrintStream.println(float)
+ void java.io.PrintStream.println(int)
+ void java.io.PrintStream.println(long)
+ void java.io.PrintStream.println(Object)
+ void java.io.PrintStream.println(String)
+] cannot be used as a constructor.
+TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)] requires "new".
TypeError: No such Java constructor: Runnable()
TypeError: No such Java constructor: Runnable(int)
java.lang.InstantiationException: java.io.InputStream
--- a/nashorn/test/script/basic/JDK-8049242.js.EXPECTED Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/test/script/basic/JDK-8049242.js.EXPECTED Tue Sep 08 14:40:44 2015 -0700
@@ -1,10 +1,10 @@
abc
-[jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)]
+[jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)]
ava
TypeError: null is not a function
TypeError: null is not a function
TypeError: null is not a function
-TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)] requires "new".
+TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)] requires "new".
TypeError: null is not a function
TypeError: null is not a function
java.lang.InstantiationException: java.io.InputStream
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8068901.js Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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-8068901: Surprising behavior with more than one functional interface on a class
+ *
+ * @test
+ * @run
+ */
+
+var Consumer = java.util.function.Consumer;
+var JFunction = java.util.function.Function;
+
+var fc = new (Java.extend(JFunction, Consumer))({
+ apply: function(x) { print("fc invoked as a function") },
+ accept: function(x) { print("fc invoked as a consumer") }
+});
+
+var c = new Consumer(function(x) { print("c invoked as a consumer") });
+
+var cf = new (Java.extend(Consumer, JFunction))({
+ apply: function(x) { print("cf invoked as a function") },
+ accept: function(x) { print("cf invoked as a consumer") }
+});
+
+var f = new JFunction(function(x) { print("f invoked as a function") });
+
+for each(x in [fc, c, fc, cf, f, cf, c, fc, f, cf]) { x(null); }
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8068901.js.EXPECTED Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,10 @@
+fc invoked as a function
+c invoked as a consumer
+fc invoked as a function
+cf invoked as a consumer
+f invoked as a function
+cf invoked as a consumer
+c invoked as a consumer
+fc invoked as a function
+f invoked as a function
+cf invoked as a consumer
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8068903.js Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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-8068903: Can't invoke vararg @FunctionalInterface methods
+ *
+ * @test
+ * @run
+ */
+
+var vc = new (Java.type("jdk.nashorn.test.models.VarArgConsumer"))(
+ function(x) {
+ Assert.assertTrue(x.length == 3);
+ Assert.assertTrue(x[0] == 1);
+ Assert.assertTrue(x[1] == 2);
+ Assert.assertTrue(x[2] == 3);
+ }
+);
+
+vc(1, 2, 3);
--- a/nashorn/test/script/basic/JDK-8079470.js.EXPECTED Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/test/script/basic/JDK-8079470.js.EXPECTED Tue Sep 08 14:40:44 2015 -0700
@@ -1,2 +1,2 @@
-TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod File java.io.File.java.io.File(String,String)] with the passed arguments; they do not match any of its method signatures.
-TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] with the passed arguments; they do not match any of its method signatures.
+TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.io.File(String,String)] with the passed arguments; they do not match any of its method signatures.
+TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.awt.Color(int,int,int)] with the passed arguments; they do not match any of its method signatures.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8134731.js Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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-8134731: `Function.prototype.apply` interacts incorrectly with `arguments`
+ *
+ * @test
+ * @run
+ */
+
+function func() {
+ return (function(f){
+ return function(a1, a2, a3, a4){
+ return (f.apply(this, arguments));
+ }
+ })(function(){
+ return arguments.length;
+ })
+}
+
+Assert.assertTrue(func()() == 0);
+Assert.assertTrue(func()(33) == 1);
+Assert.assertTrue(func()(33, true) == 2);
+Assert.assertTrue(func()(33, true, "hello") == 3);
+Assert.assertTrue(func()(33, true, "hello", "world") == 4);
+Assert.assertTrue(func()(33, true, "hello", "world", 42) == 5);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8134865.js Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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-8134865: Need to restore for container block from lexical context in finally
+ *
+ * @test
+ * @option --language=es6
+ */
+
+try {
+ eval("function f() { for (x : y) { } }");
+ throw "should not reach here";
+} catch (e) {
+ if (!(e instanceof SyntaxError)) throw e;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8134939.js Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
+ * 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-8134939: Improve toString method of Dynalink OverloadedDynamicMethod
+ *
+ * @test
+ * @run
+ */
+
+var overloadedSetter = new (Java.type("jdk.nashorn.test.models.OverloadedSetter"));
+
+Assert.assertEquals(String(overloadedSetter.foo),
+ "[jdk.internal.dynalink.beans.OverloadedDynamicMethod\n" +
+ " String jdk.nashorn.test.models.OverloadedSetter.foo(String)\n" +
+ " void jdk.nashorn.test.models.OverloadedSetter.foo(int)\n" +
+ "]");
+
+Assert.assertEquals(String(overloadedSetter.setColor),
+ "[jdk.internal.dynalink.beans.OverloadedDynamicMethod\n" +
+ " void jdk.nashorn.test.models.OverloadedSetter.setColor(int)\n" +
+ " void jdk.nashorn.test.models.OverloadedSetter.setColor(String)\n" +
+ "]");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/numeric-literals.js Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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-8134873: ECMAScript 6 Numeric Literals
+ *
+ * @test
+ * @option --language=es6
+ */
+
+function assertEquals(expected, actual) {
+ if (expected !== actual) {
+ throw new Error("expected: " + expected + ", actual: " + actual);
+ }
+}
+
+assertEquals(0b0, 0);
+assertEquals(0B0, 0);
+assertEquals(0b01, 1);
+assertEquals(0B10, 2);
+assertEquals(0b11111111, 255);
+assertEquals(0b11111111111111111111111111111111, 4294967295);
+
+assertEquals(0o0, 0);
+assertEquals(0O0, 0);
+assertEquals(0o01, 1);
+assertEquals(0O10, 8);
+assertEquals(0o777, 511);
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/trusted/JDK-8087292.js Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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-8087292: nashorn should have a "fail-fast" option for scripting, analog to bash "set -e"
+ *
+ * @test
+ * @option -scripting
+ * @run
+ */
+
+function tryExec() {
+ try {
+ `java`
+ } catch (e) {
+ print(e);
+ }
+
+ // make sure we got non-zero ("failure") exit code!
+ if ($EXIT == 0) {
+ print("Error: expected $EXIT code to be non-zero");
+ }
+}
+
+// no exception now!
+tryExec();
+
+// turn on error with non-zero exit code
+$EXEC.throwOnError = true;
+tryExec();
+
+// no exception after this
+$EXEC.throwOnError = false;
+tryExec();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/trusted/JDK-8087292.js.EXPECTED Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,1 @@
+RangeError: $EXEC returned non-zero exit code: 1
--- a/nashorn/test/script/trusted/classfilter.js.EXPECTED Tue Sep 08 16:01:29 2015 +0400
+++ b/nashorn/test/script/trusted/classfilter.js.EXPECTED Tue Sep 08 14:40:44 2015 -0700
@@ -4,7 +4,18 @@
typeof java.util.Map evalutes to function
typeof java.util.HashMap evalutes to function
var m = new java.util.HashMap(); m.put('foo', 42); m evalutes to {foo=42}
-java.lang.System.out.println evalutes to [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println]
+java.lang.System.out.println evalutes to [jdk.internal.dynalink.beans.OverloadedDynamicMethod
+ void java.io.PrintStream.println()
+ void java.io.PrintStream.println(boolean)
+ void java.io.PrintStream.println(char)
+ void java.io.PrintStream.println(char[])
+ void java.io.PrintStream.println(double)
+ void java.io.PrintStream.println(float)
+ void java.io.PrintStream.println(int)
+ void java.io.PrintStream.println(long)
+ void java.io.PrintStream.println(Object)
+ void java.io.PrintStream.println(String)
+]
java.lang.System.exit evalutes to [jdk.internal.dynalink.beans.SimpleDynamicMethod void java.lang.System.exit(int)]
new javax.script.SimpleBindings throws java.lang.RuntimeException: java.lang.ClassNotFoundException: javax.script.SimpleBindings
Java.type('javax.script.ScriptContext') throws java.lang.RuntimeException: java.lang.ClassNotFoundException: javax.script.ScriptContext
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/test/models/VarArgConsumer.java Tue Sep 08 14:40:44 2015 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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.test.models;
+
+/**
+ * Simple function interface with a varargs SAM method.
+ */
+@FunctionalInterface
+public interface VarArgConsumer {
+ public void apply(Object... o);
+}
+